Академический Документы
Профессиональный Документы
Культура Документы
Each function in MATLAB contains a set of variables specific to that function. Even in the same .m file, you dont have (direct) access to variables created in other functions within the file. Global variables give you the ability to create/change a variable in one function and have that updated variable accessible elsewhere. This post will discuss two methods for handling (no pun intended) global variables, one of which is perfectly integrated into Graphical User Interfaces (GUIs).
The global function needs to be called in each separate function (usually in the beginning) where the variables will be called. Stylistically, the variable names are usually longer names and all in CAPS to indicate global variables within the functions. The documented example in the MATLAB helps shows this pretty well:
function tic global TICTOC %define/incorporate global variable at start of function TICTOC = clock; function t = toc global TICTOC %accesses variable TICTOC (or creates it if TICTOC is undefined) if nargout < 1 elapsed_time = etime(clock, TICTOC) else t = etime(clock, TICTOC); end
Many hard-core coders prefer to avoid using global except for constants. The reason behind this is because its generally considered poor form to lock up a variable name (See Steve Ls comment below for another reason!). While this wont matter for smaller programs and functions, when the files get to be many hundreds (or thousands or millions) of lines long, it can be very difficult to keep track of all of the global variables and to remember to call all the necessary variables at the start of each function. The great thing about GUIs is that they already have a built-in global structure to deal with all of your global variables: the handles. The handles structure is an input (and therefore accessible) to every function in the GUI, making it perfectly capable doing everything the global command can. In fact, you shouldnt ever have to use global command when designing a GUI because the handles structure does the job so well. GUIs and global dont mix kids!
METHOD 2: handles.variable
As you may have seen from many of the blinkdagger GUI tutorials, the handles structure is an extremely useful method to manipulate GUI boxes/buttons/tools. But the tool data are all just stored variables that can be accessed anywhere within the GUI (aka global variables!). Since we dont need to edit any property of the handles structure (e.g. handles.static_text, String), we dont need to use the get/set commands. Creating the global variable is as easy as saying:
handles.x = 42; %And of course, don't forget to update your handles structure: guidata(hObject, handles);
handles.x is now an independent variable and note that it has no relation to the local variable x.
x = 43;
is a completely valid command in the same function that would not overwrite your global variable handles.x. Remember, these variables can range from constants (e.g. 12) to strings (e.g. Hello World) to structures, cells, and arrays of constants/strings. Hopefully you can see the usefullness of global variables and will use them (properly!) in your coding adventures.
poor form to lock up a variable name. Thats one reason to avoid using global variables, but a much stronger reason to avoid using global variables is that it can lead to bugs that are very difficult and time consuming to locate, particularly in the context of a GUI. Suppose I write a function that uses a global variable x.
function y = myglobalsquare global x if isempty(x) x = 5; end y = x^2;
In isolation, this function works perfectly fine. I set the value of the global variable x and then call myglobalsquare, and I get back the value x^2. Now I incorporate this function into a GUI. I set it as the callback for one of my GUIs uicontrols and have another uicontrols callback set the value of the global variable x. I test it and it works, and I go on finishing up the GUI. But suddenly, when I introduce a new object into the GUI and set up its callback, my Square button no longer works! Whats going on? I havent made any changes to the Square button in hours! The problem, I find out after spending a LOT of time looking at myglobalsquare and the callback that sets the global variable x, is that the callback for the new object I introduced in the GUI _also_ uses the global variable x. Because of that callback functions manipulation of the global variable, the myglobalsquare function no longer works the way I expect it to. If you think of a function workspace as a house, with the input arguments coming in the front door and the output arguments leaving by the back door, a global variable is an open window that anyone can crawl through and move your furniture around, potentially without you realizing it until you invite a very important guest (the data for the real problem youre trying to solve, not the data youve used to test the function) for a visit. On a side note, I suppose that would make a nested function an apartment in an apartment complex, where the landlord has the right to come in and move stuff around in certain circumstances [mainly maintenance or emergency situations] and the resident doesnt have the right to do certain things [like paint the walls.] 3. on 30 Jun 2009 at 10:22 am 3Zane Montgomery I love the analogy. Thanks for the tip Steve!
4. on 01 Jul 2009 at 6:43 am 4MATLABDoug ARGHH! Globals make me crazy The handles structure is not global. It is passed around to all the callbacks in a GUI by default, but it is not global. I know this is partially a religious issue, but I see way too many people abusing true global variables because they do not understand scoping of variables and then they end up in a real mess later. Please do not use global variables unless you can explain to your teddy bear (http://sjbdeveloper.blogspot.com/2006/03/teddy-bear-code-reviews.html) why you really need them. My bet is you would be better off without them. See below for alternatives. On to my next religious issue: the handles structure is for handles. It just feels untidy to put data in a structure specifically labeled for handles. I see people putting just tons of data into the handles structure and it becomes a real mess. Is it going to cause as many problems as globals? Not likely. However, I highly recommend the use of GETAPPDATA and SETAPPDATA as shown in this video: http://blogs.mathworks.com/videos/2005/10/03/guide-video-part-two/ To me, this is cleaner. Loren is a fan of nested functions http://blogs.mathworks.com/loren/2008/01/16/nested-functions-and-variable-scope/ Please consider the alternative before using unneeded globals. Globals are often the cause of really tricky errors. Globals are just quicker, easier, more seductive. Use nested functions or appdata, not as clumsy or random as a global. An elegant weapon, for a more civilized age. -Doug Anonymous Is it ok to use the userdata from the root? like
ud=get(0,userdata); ud.x=42; set(0,userdata,ud); on 02 Jul 2009 at 2:38 pm 6Anonymous Im writing GUIs that contain some pretty large data arrays, and dont want these to be unnecessary duplicated, using up RAM. Im currently using global variables. Whilst I appreciate the elegance of Method 2, would switching to this effectively double my memory usage (with one copy of the data in the GUIs handles structure, and the other in the local handles copy)? on 01 Aug 2009 at 10:43 am 7Dey Hi all I apologize in advance because I dont have a clue how start a new post I need a script which does the following.: I have the following directory structures C:/Big/ecm/sDDP/new/level1/level1_1/level1_1_1/*.ext C:/Big/ecm/sDDP/new/level1/level1_1/level1_1_2/*.ext C:/Big/ecm/sDDP/new/level1/level1_1/level1_1_3/*.ext . . . C:/Big/ecm/sDDP/new/level2/level2_1/level2_1_1/*.ext C:/Big/ecm/sDDP/new/level2/level2_1/level2_1_2/*.ext C:/Big/ecm/sDDP/new/level2/level2_1/level2_1_3/*.ext . . . etc. I want to go through the folders levelx_y_z(where x, y, z stands for 1_1_1, 1_1_2 etc.) to get the files *.ext. I dont want to select these files manually with uigetfile, because its very time consuming. Could anyone help me please. I tried something with fullfile(path, *.ext) but then I still have to specify each path. P.s. The folders levelx/levelx_y/level/x_y_z are named otherwise actually. I just wanted to illustrate the structure
who can everyone help me! im unstill about the gui ,i want to show the transfer function iin the Guide ,but how dont know begin my following topic: for G(S)=(7s^2+16s+10)/(s^4+5s^3+11s^2+16s+10) and have to show : + time set + bulk acceleration +error set in the Guide i hope you can make it help me thank you on 23 Jan 2011 at 11:45 am 9Ameya Having a Problem trying to plot an imported array, the gui does not except a code from another .m file even though its shown in the workspaceKindly help
Dey You can solve your problem in one line with a regular expression: regexp(text, expression) You can get the text input from dir and the expression below should match your files: C:/Big/ecm/sDDP/new/level\d+/level\d+_\d+/level\d+_\d+_\d+/.*\.ext It may be a good idea to experiment a bit with regexp to get familiar with it since it can be a bit tricky to get the expressions right.
Contents
Accessing Table Data within GUI Callbacks Accessing only the Selected Data Next Time Links and Downloads
For simplicity sake, lets assume that you would like to create a button that will add 3 to each of the entries of the table when the button is pressed. How would you go about doing this? Its actually quite straightforward. Lets take a look at the callback for the add button:
function add_pushbutton_Callback(hObject, eventdata, handles) % hObject handle to add_pushbutton (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) %get the table data tableData = get(handles.uitable1,'data'); %add 3 to the table tableData = tableData + 3; %update the table set(handles.uitable1,'data',tableData);
So now, when I press the Add 3 button, it adds 3 to the table! This is just a simple example to show how to extract the data from the UITABLE, and to perform an operation on it.
How would you go about doing this? Read on and all will be revealed.
Enabling CellSelectionCallback
The first thing we need to do is to enable the Cell Selection Callback. But first, why are we doing this? Enabling this callback will allow us to keep track of what cells are being
selected on the table. You can do this by bringing up the Property Inspector for the UITABLE, and then clicking the following icon as shown in the image below.
If you did it correctly, your m-file should have been updated to include the following:
% --- Executes when selected cell(s) is changed in uitable1. function uitable1_CellSelectionCallback(hObject, eventdata, handles) % hObject handle to uitable1 (see GCBO) % eventdata structure with the following fields (see UITABLE) % Indices: row and column indices of the cell(s) currently selecteds % handles structure with handles and user data (see GUIDATA)
In addition, the CellSelectionCallback field should now be populated as shown in the image below:
% Indices: row and column indices of the cell(s) currently selecteds % handles structure with handles and user data (see GUIDATA) %every time the cell selection changes, we update this data %eventdata stores the indices of the selected cells handles.selectedCells = eventdata.Indices; %update the gui data guidata(hObject, handles);
Now, we need to write the callback for the button we just added:
% --- Executes on button press in sumNumbers_pushbutton. function sumNumbers_pushbutton_Callback(hObject, eventdata, handles) % hObject handle to sumNumbers_pushbutton (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA)
%get the number of rows and columns [rows,columns] = size(handles.selectedCells); %get the data from the UITABLE tableData = get(handles.uitable1,'data'); %initialize the sum sum = 0; %loop through each selected cell and keep a running sum %can anyone thing of a better way to do this? for x=1:rows sum = sum +tableData(tableIndices(x,1),tableIndices(x,2)); end %display the sum on the GUI set(handles.sum_text,'String',num2str(sum))
And there you have it, now you can select any number of cells, and then sum up the value of the contents!
Next Time
Next time, were going to talk about some of the cool features of the UITABLE that we have not yet discussed, including different data types within the UITABLE.
Download Source Files The MathWorks Documentation for UITABLE Cool Things You can do with UITABLE Dougs Video on UITABLE
Contents
Adding a Table to Your GUI using GUIDE Displaying Data on the Table Adding Column and Row Labels Modifying your Table through the m-file Next Time Links and Downloads
Within the GUIDE framework, you can add a table to your GUI using the following icon from the toolbar: .
A neat feature is that the table is smart enough to fill out the table according to the size of the data matrix that you feed it. So if I had done the following instead:
myData = rand(100,100);
The table would incorporate the use of scroll bars, as shown below.
modify the labels by first bringing up the Property Inspector for the UITABLE. This can be done by double clicking the UITABLE component.
Now, if you click on any of the fields in the above picture, it will bring up the Table Property Editor. This is where you can add Row and Column labels. For example:
Make sure you click on the Rows, and that you select the Show names entered below as the row headers option. Finally, you just need to modify the names. Similarly, you can do the same for the columns.
Once youre done with that. you should see the following:
And once you run your GUI, you can see the final result. A well labeled table that displays your data beautifully!
Sometimes its easier to work from within the m-file framework, rather than the GUIDE framework. We could have done exactly what we did above programmatically through the m-file. In the opening function we could have done the following:
%store the row headers into a cell array rowHeaders = {'Blink','Dagger','Loves','MATLAB','!!!!!!'}; %set the row labels set(handles.uitable1,'RowName',rowHeaders); %do the same for the column headers columnHeaders = {'Quan','Daniel','Rob','Zane'}; set(handles.uitable1,'ColumnName',columnHeaders);
In this example, we assumed that we knew the dimensions of our table. If you dont know the size of your table beforehand, then it can be difficult to apply data labels that are meaningful. By working through the m-file, you obtain more flexibility since you wont have to go back and modify the .fig file every time you want to make a change. And if you are going to apply dynamic labeling, then working from the m-file is going to be much easier.
Next Time
Next time, were going to talk about how to work with manipulating the data within the table.
MATLAB GUI - Tool Tips are your Friends! What is a Tool Tip?
A tool tip is supplementary information about a GUI component that appears when the user hovers the mouse cursor over the GUI component. As you can imagine, this can be quite useful for the user. See below for examples.
If you have a large list of tooltips, you may want to do it in separate m-file and call that mfile in the opening function.
Contents
How to use this GUI: Quick User Guide About this GUI Putting it all Together Addpath Next Time
A simple but effective way to implement a help screen is to create another standalone GUI. For example, I created a standalone GUI that consists of only a static text component. I populated the text field with some helpful information regarding the GUI and detailed a succinct users guide.
When the GUI is called by the user, the user will see the following:
Of course, you can add more tidbits and information depending on the actual GUI. You might also want to add a FAQ section here if you feel your GUI needs some extra explanation. If you cant fit all the information into one screen, you can also utilize pushbuttons that will change the static text when the button is pressed.
When the GUI is called by the user, the user will see the following:
the callback for the How to use this GUI menu item is:
function helpGUI_Callback(hObject, eventdata, handles) %this is the name of the help GUI that contains the help information helpGUI_description
Addpath
I have found that the addpath command within MATLAB can really help you keep your files organized. If your GUI utilizes other m-files or images, it can be advantageous to store them in appropriate subdirectories. you can store them in a separate directory and simply add the path of that directory. It can get a little crowded in the main directory of your GUI, so its usually a good idea to put all your sub functions and sub GUIs in a lower level folder. For example, the following image shows how I originally had my m-files organized. The main GUI files are Tutor_Commuter_QQ_05.fig and Tutor_Commuter_QQ_05.m. The rest of the files are used in creating the help.
In the following image, you can see how I reorganized the files. All the files except the main files are placed in the subfunctions folder.
Now, all that has to done is to add the path of the subfunctions within the Opening Function of the main GUI.
%the addpath adds the subfunctions folder onto the MATLAB path. m-files %within this directory will be run as if it were in the same directory as the %main GUI itself %the fullfile command combines directory names and parts %pwd is the "present working directory", which in this case will be where %the main GUI is located addpath(fullfile(pwd,'subfunctions');
Next Time
It looks like weve revamped Zanes GUI so that its obtained a shade of respectability. If you guys have any more ideas on what can be done, wed love to hear about it. In the near future, well open up the floor and ask for GUIs from our readers! Until next time . . .