Correct way to fetch data from a GUI with nested menus.

2 visualizaciones (últimos 30 días)
Samuel
Samuel el 5 de Mayo de 2022
Comentada: Jan el 6 de Mayo de 2022
Goodmorning everyone.
I'm developing a GUI for a program that simulates the interactions between different components. Since every component has a long list of fields, the gui is structured as a main menu with pop up buttons that open different sub menus, one for each component (example: push button A opens a menu for Component A, push button B opens a menu for Component B). To create the menus I'm using GUIDE.
What I want to do is to have a separate struct for every component into the main gui, so I can better manage all the functions with push buttons from the main menu, and fetch data from the sub-menus into these structs.
Problem is that I'm having a really hard time understanding how to pass and save data from the sub-menus to the main menu.
For example, the initialization of values goes as follows:
% --- code that generates main gui before this line --- %
global ComponentA;
global ComponentB;
% struct initialization
initializeGUI(ComponentA, ComponentB);
%initializeGUI does a bunch of: ComponentA.value = 1;
% debug
disp(ComponentA);
% --- code that generates all the callback functions for the gui buttons below this line --%
The disp(ComponentA) returns an empty struct, while if I do the same thing inside initializeGUI.m it returns all the data correctly.
So, what is the correct way to pass structs to and fetch data from the sub menu?

Respuesta aceptada

Jan
Jan el 5 de Mayo de 2022
These lines define ComponentA and ComponentB as globals:
global ComponentA;
global ComponentB;
The you do not use them as global variables, but provide their contents as input argument:
initializeGUI(ComponentA, ComponentB);
But you do not catch the changes here. This would be:
[ComponentA, ComponentB] = initializeGUI(ComponentA, ComponentB);
  • If you do catch the changes by using outputs, there is no need to declare the variables as globals.
  • If you declare them as globales, there is no need to provide them as inputs or to catch the outputs.
The general best programming practice is to avoid gloable variables, because they impede the debugging and the cause collisions with other software using the same names for global variables by accident.
Store the data as UserData of the GUI. See also the command guidata to store data in the ApplicationData of the figure. Both is much safer than using globals.
  2 comentarios
Samuel
Samuel el 5 de Mayo de 2022
Thanks! This partially solved my issue. I'm still using global definitions because I'm unfamiliar with UserData and the use of guidata command.
So, now my global variables get initialized correctly, passed to my sub menus, modified from such sub menus, but I can't fetch the data back into the main gui.
For example:
% --- code that generates main gui before this line --- %
global Component;
initializeComponent(); % does something like Component.value = 1;
display(Component); % displays Component: value = 1;
function push_Callback(hObject, eventdata, handles)
run('submenu.m'); % opens a sub menu with a textbox
% in submenu.m:
% global Component;
% Component.value = 2;
% display(Component);
% displays Component: value = 2;
end
display(Component); % displays Component: value = 1;
So, it looks like my variables are getting updated, but the struct in the main gui isn't. If I remove the global definition in the sub-menus files, I get errors about variables not being found, not having dot indexing, etc...
What can I do (besides banging my head against the wall)?
Jan
Jan el 6 de Mayo de 2022
@Samuel: "I'm still using global definitions because I'm unfamiliar with UserData and the use of guidata command." - Then it is time to change thuis. Global varibales are a shot in your knee - not only in Matlab but in other programming langauages as well.
Instead of storing variables globally, create them as field of a struct:
Data.Component = 'WhatEverYouNeed';
Storing them in the UserData or ApplicationData is trivial:
% In the figure's UserData:
FigureHandle.UserData = Data;
% Or in the ApplicationData:
setappdata(FigureHandle, 'Data', Data);
% Or using guidata:
guidata(FigureHandle, Data);
If you now want to access this struct in a callback:
% In the figure's UserData:
Datat = FigureHandle.UserData;
% Or in the ApplicationData:
Data = getappdata(FigureHandle, 'Data');
% Or using guidata:
Data = guidata(FigureHandle);
% Now use, change or add some data:
Data.NewField = TheOtherCheckboxes; % Or whatever
% Afterwards update the data in the figure as shown in the former code
% block
You can use one or all three of these methods.
Another bad programming practice is using scripts. They suffer from the same problem as global variables: The pollute the global workspace with variables. If you type in the command window " max = 17 ", calling the max() function in any following scripts will fail, because the function is shadowed by a variable. Inside a larger GUI the user (e.g. you) will be very confused about such wide-range side-effects, which are the killer for an efficient and reliable debugging. If your GUI is working depends on what the user has done before in the workspace and therefore it is impossible to test your code sufficiently.
The solution is easy: Use functions instead of scripts. In your case:
function push_Callback(hObject, eventdata, handles)
UserData = handles.FigureHandle.UserData; % Or how the fig's handle is called
% The insert the code of "submenu.m" here directly
UserData.Component.value = 2;
% Update the userdata (or setappdata or guidata, see above)
handles.FigureHandle.UserData = UserData;
end
No magic tricks, but immediately your GUI is indendent from any other activities in Matlab. You can run e.g. several instances of the GUI at the same time without using the same data.
Using globals and scripts makes it extremely hard to find out, which part of the code was respeonsible for the last change of a variable. You see already, that these methods cause an unexpeected behavior. Yo your case is a perfect example already to demonstrate the serios problems of globals and scripts. Therefore it is time to modify the programming strategy and following good programming patterns:
  • No globals
  • No scripts
Good luck!

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Creating, Deleting, and Querying Graphics Objects en Help Center y File Exchange.

Productos


Versión

R2019a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by