| MATLAB® | ![]() |
This example shows how to implement a GUI that displays names and phone numbers, which it reads from a MAT-file.

This example demonstrates the following GUI programming techniques:
Uses open and save dialogs to provide a means for users to locate and open the address book MAT-files and to save revised or new address book MAT-files.
Defines callbacks written for GUI menus.
Uses the GUI's handles structure to save and recall shared data.
Uses a GUI figure resize function.
One of the key techniques illustrated in this example is how to keep track of information and make it available to the various subfunctions. This information includes
The name of the current MAT-file
The names and phone numbers stored in the MAT-file
An index pointer that indicates the current name and phone number, which must be updated as the user pages through the address book
The figure position and size
The handles of all GUI components
The descriptions of the subfunctions that follow illustrate how to save and retrieve information from the handles structure. See handles Structure for background information on this structure.
If you are reading this in the MATLAB® Help browser, you can click the following links to display the GUIDE Layout Editor and the MATLAB Editor with a completed version of this example. This enables you to see the values of all component properties and to understand how the components are assembled to create the GUI. You can also see a complete listing of the code that is discussed in the following sections.
Note The following links execute MATLAB commands and are designed to work within the MATLAB Help browser. If you are reading this online or in PDF, you should go to the corresponding section in the MATLAB Help Browser to use the links. |
The GUI is nonblocking and nonmodal since it is designed to be displayed while you perform other MATLAB tasks.
This GUI uses the following GUI option settings:
Resize behavior: User-specified
Command-line accessibility: Off
GUI M-file options selected:
Generate callback function prototypes
Application allows only one instance to run
You can call the GUI M-file with no arguments, in which case the GUI uses the default address book MAT-file, or you can specify an alternate MAT-file from which the GUI reads information. In this example, the user calls the GUI with a pair of arguments, address_book('book', 'my_list.mat'). The first argument, 'book', is a key word that the M-file looks for in the opening function. If the M-file finds the key word, it knows to use the second argument as the MAT-file for the address book. Calling the GUI with this syntax is analogous to calling it with a valid property-value pair, such as ('color', 'red'). However, since 'book' is not a valid figure property, in this example the opening function in the M-file includes code to recognize the pair ('book', 'my_list.mat').
Note that it is not necessary to use the key word 'book'. You could program the M-file to accept just the MAT-file as an argument, using the syntax address_book('my_list.mat'). The advantage of calling the GUI with the pair ('book', 'my_list.mat') is that you can program the GUI to accept other user arguments, as well as valid figure properties, using the property-value pair syntax. The GUI can then identify which property the user wants to specify from the property name.
The following code shows how to program the opening function to look for the key word 'book', and if it finds the key word, to use the MAT-file specified by the second argument as the list of contacts.
function address_book_OpeningFcn(hObject, eventdata,...
handles, varargin)
% Choose default command line output for address_book
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% User added code follows
if nargin < 4
% Load the default address book
Check_And_Load([],handles);
% If the first element in varargin is 'book' and
& the second element is a MATLAB file, then load that file
elseif (length(varargin) == 2 && ...
strcmpi(varargin{1},'book') && ...
(2 == exist(varargin{2},'file')))
Check_And_Load(varargin{2},handles);
else
errordlg('File Not Found','File Load Error')
set(handles.Contact_Name,'String','')
set(handles.Contact_Phone,'String','')
endThere are two ways in which an address book (i.e., a MAT-file) is loaded into the GUI:
When running the GUI, you can specify a MAT-file as an argument. If you do not specify an argument, the GUI loads the default address book (addrbook.mat).
The user can select Open under the File menu to browse for other MAT-files.
To be a valid address book, the MAT-file must contain a structure called Addresses that has two fields called Name and Phone. The Check_And_Load subfunction validates and loads the data with the following steps:
Loads (load) the specified file or the default if none is specified.
Determines if the MAT-file is a valid address book.
Displays the data if it is valid. If it is not valid, displays an error dialog (errordlg).
Returns 1 for valid MAT-files and 0 if invalid (used by the Open menu callback)
Saves the following items in the handles structure:
The name of the MAT-file
The Addresses structure
An index pointer indicating which name and phone number are currently displayed
This is the Check_And_Load function.
function pass = Check_And_Load(file,handles)
% Initialize the variable "pass" to determine if this is
% a valid file.
pass = 0;
% If called without any file then set file to the default
% filename.
% Otherwise, if the file exists then load it.
if isempty(file)
file = 'addrbook.mat';
handles.LastFile = file;
guidata(handles.Address_Book,handles)
end
if exist(file) == 2
data = load(file);
end
% Validate the MAT-file
% The file is valid if the variable is called "Addresses"
% and it has fields called "Name" and "Phone"
flds = fieldnames(data);
if (length(flds) == 1) && (strcmp(flds{1},'Addresses'))
fields = fieldnames(data.Addresses);
if (length(fields) == 2) && ...
(strcmp(fields{1},'Name')) && ...
(strcmp(fields{2},'Phone'))
pass = 1;
end
end
% If the file is valid, display it
if pass
% Add Addresses to the handles structure
handles.Addresses = data.Addresses;
guidata(handles.Address_Book,handles)
% Display the first entry
set(handles.Contact_Name,'String',data.Addresses(1).Name)
set(handles.Contact_Phone,'String',data.Addresses(1).Phone)
% Set the index pointer to 1 and save handles
handles.Index = 1;
guidata(handles.Address_Book,handles)
else
errordlg('Not a valid Address Book','Address Book Error')
endThe address book GUI contains a File menu that has an Open submenu for loading address book MAT-files. When selected, Open displays a dialog (uigetfile) that enables the user to browse for files. The dialog displays only MAT-files, but users can change the filter to display all files.
The dialog returns both the filename and the path to the file, which is then passed to fullfile to ensure the path is properly constructed for any platform. Check_And_Load validates and load the new address book.
function Open_Callback(hObject, eventdata, handles)
[filename, pathname] = uigetfile( ...
{'*.mat', 'All MAT-Files (*.mat)'; ...
'*.*','All Files (*.*)'}, ...
'Select Address Book');
% If "Cancel" is selected then return
if isequal([filename,pathname],[0,0])
return
% Otherwise construct the fullfilename and Check and load
% the file
else
File = fullfile(pathname,filename);
% if the MAT-file is not valid, do not save the name
if Check_And_Load(File,handles)
handles.LastFIle = File;
guidata(hObject, handles)
end
endSee the Creating Menus section for information on creating the menu.
The Contact Name text box displays the name of the address book entry. If you type in a new name and press enter, the callback performs these steps:
If the name exists in the current address book, the corresponding phone number is displayed.
If the name does not exist, a question dialog (questdlg) asks you if you want to create a new entry or cancel and return to the name previously displayed.
If you create a new entry, you must save the MAT-file with the File > Save menu.
This callback makes use of the handles structure to access the contents of the address book and to maintain an index pointer (handles.Index) that enables the callback to determine what name was displayed before it was changed by the user. The index pointer indicates what name is currently displayed. The address book and index pointer fields are added by the Check_And_Load function when the GUI is run.
If the user adds a new entry, the callback adds the new name to the address book and updates the index pointer to reflect the new value displayed. The updated address book and index pointer are again saved (guidata) in the handles structure.
function Contact_Name_Callback(hObject, eventdata, handles)
% Get the strings in the Contact Name and Phone text box
Current_Name = get(handles.Contact_Name,'string');
Current_Phone = get(handles.Contact_Phone,'string');
% If empty then return
if isempty(Current_Name)
return
end
% Get the current list of addresses from the handles structure
Addresses = handles.Addresses;
% Go through the list of contacts
% Determine if the current name matches an existing name
for i = 1:length(Addresses)
if strcmp(Addresses(i).Name,Current_Name)
set(handles.Contact_Name,'string',Addresses(i).Name)
set(handles.Contact_Phone,'string',Addresses(i).Phone)
handles.Index = i;
guidata(hObject, handles)
return
end
end
% If it's a new name, ask to create a new entry
Answer=questdlg('Do you want to create a new entry?', ...
'Create New Entry', ...
'Yes','Cancel','Yes');
switch Answer
case 'Yes'
Addresses(end+1).Name = Current_Name; % Grow array by 1
Addresses(end).Phone = Current_Phone;
index = length(Addresses);
handles.Addresses = Addresses;
handles.Index = index;
guidata(hObject, handles)
return
case 'Cancel'
% Revert back to the original number
set(handles.Contact_Name,'String',Addresses(handles.Index).Name
)
set(handles.Contact_Phone,'String',Addresses(handles.Index).Pho
ne)
return
endThe Contact Phone # text box displays the phone number of the entry listed in the Contact Name text box. If you type in a new number click one of the push buttons, the callback opens a question dialog that asks you if you want to change the existing number or cancel your change.
Like the Contact Name text box, this callback uses the index pointer (handles.Index) to update the new number in the address book and to revert to the previously displayed number if the user selects Cancel from the question dialog. Both the current address book and the index pointer are saved in the handles structure so that this data is available to other callbacks.
If you create a new entry, you must save the MAT-file with the File > Save menu.
function Contact_Phone_Callback(hObject, eventdata, handles)
Current_Phone = get(handles.Contact_Phone,'string');
% If either one is empty then return
if isempty(Current_Phone)
return
end
% Get the current list of addresses from the handles structure
Addresses = handles.Addresses;
Answer=questdlg('Do you want to change the phone number?', ...
'Change Phone Number', ...
'Yes','Cancel','Yes');
switch Answer
case 'Yes'
% If no name match was found create a new contact
Addresses(handles.Index).Phone = Current_Phone;
handles.Addresses = Addresses;
guidata(hObject, handles)
return
case 'Cancel'
% Revert back to the original number
set(handles.Contact_Phone,...
'String',Addresses(handles.Index).Phone)
return
endThe Prev and Next buttons page back and forth through the entries in the address book. Both push buttons use the same callback, Prev_Next_Callback. You must set the Callback property of both push buttons to call this subfunction, as the following illustration of the Prev push button Callback property setting shows.

The callback defines an additional argument, str, that indicates which button, Prev or Next, was clicked. For the Prev button Callback property (illustrated above), the Callback string includes 'Prev' as the last argument. The Next button Callback string includes 'Next' as the last argument. The value of str is used in case statements to implement each button's functionality (see the code listing below).
Prev_Next_Callback gets the current index pointer and the addresses from the handles structure and, depending on which button the user presses, the index pointer is decremented or incremented and the corresponding address and phone number are displayed. The final step stores the new value for the index pointer in the handles structure and saves the updated structure using guidata.
function Prev_Next_Callback(hObject, eventdata,handles,str) % Get the index pointer and the addresses index = handles.Index; Addresses = handles.Addresses; % Depending on whether Prev or Next was clicked, % change the display switch str case 'Prev' % Decrease the index by one i = index - 1; % If the index is less than one then set it equal to the index % of the last element in the Addresses array if i < 1 i = length(Addresses); end case 'Next' % Increase the index by one i = index + 1; % If the index is greater than the size of the array then % point to the first item in the Addresses array if i > length(Addresses) i = 1; end end % Get the appropriate data for the index in selected Current_Name = Addresses(i).Name; Current_Phone = Addresses(i).Phone; set(handles.Contact_Name,'string',Current_Name) set(handles.Contact_Phone,'string',Current_Phone) % Update the index pointer to reflect the new index handles.Index = i; guidata(hObject, handles)
When you make changes to an address book, you need to save the current MAT-file, or save it as a new MAT-file. The File submenus Save and Save As enable you to do this. These menus, created with the Menu Editor, use the same callback, Save_Callback.
The callback uses the menu Tag property to identify whether Save or Save As is the callback object (i.e., the object whose handle is passed in as the first argument to the callback function). You specify the menu's Tag property with the Menu Editor.
The handles structure contains the Addresses structure, which you must save (handles.Addresses) as well as the name of the currently loaded MAT-file (handles.LastFile). When the user makes changes to the name or number, the Contact_Name_Callback or the Contact_Phone_Callback updates handles.Addresses.
If the user selects Save, the save command is called to save the current MAT-file with the new names and phone numbers.
If the user selects Save As, a dialog is displayed (uiputfile) that enables the user to select the name of an existing MAT-file or specify a new file. The dialog returns the selected filename and path. The final steps include
Using fullfile to create a platform-independent pathname.
Calling save to save the new data in the MAT-file.
Updating the handles structure to contain the new MAT-file name.
Calling guidata to save the handles structure.
function Save_Callback(hObject, eventdata, handles)
% Get the Tag of the menu selected
Tag = get(hObject, 'Tag');
% Get the address array
Addresses = handles.Addresses;
% Based on the item selected, take the appropriate action
switch Tag
case 'Save'
% Save to the default addrbook file
File = handles.LastFile;
save(File,'Addresses')
case 'Save_As'
% Allow the user to select the file name to save to
[filename, pathname] = uiputfile( ...
{'*.mat';'*.*'}, ...
'Save as');
% If 'Cancel' was selected then return
if isequal([filename,pathname],[0,0])
return
else
% Construct the full path and save
File = fullfile(pathname,filename);
save(File,'Addresses')
handles.LastFile = File;
guidata(hObject, handles)
end
endThe Create New menu simply clears the Contact Name and Contact Phone # text fields to facilitate adding a new name and number. After making the new entries, the user must then save the address book with the Save or Save As menus. This callback sets the text String properties to empty strings:
function New_Callback(hObject, eventdata, handles) set(handles.Contact_Name,'String','') set(handles.Contact_Phone,'String','')
The address book defines its own resize function. To use this resize function, you must set the Application Options dialog Resize behavior to User-specified, which in turn sets the figure's ResizeFcn property to:
address_book('ResizeFcn',gcbo,[],guidata(gcbo))Whenever the user resizes the figure, MATLAB software calls the ResizeFcn subfunction in the address book M-file (address_book.m)
The resize function allows users to make the figure wider, to accommodate long names and numbers, but does not allow the figure to be made narrower than its original width. Also, users cannot change the height. These restrictions do not limit the usefulness of the GUI and simplify the resize function, which must maintain the proper proportions between the figure size and the components in the GUI.
When the user resizes the figure and releases the mouse, the resize function executes. At that point, the resized figure's dimensions are saved. The following sections describe how the resize function handles the various possibilities.
If the new width is greater than the original width, set the figure to the new width.
The size of the Contact Name text box changes in proportion to the new figure width. This is accomplished by:
Changing the Units of the text box to normalized.
Resetting the width of the text box to be 78.9% of the figure's width.
Returning the Units to characters.
If the new width is less than the original width, use the original width.
If the user attempts to change the height, use the original height. However, because the resize function is triggered when the user releases the mouse button after changing the size, the resize function cannot always determine the original position of the GUI on screen. Therefore, the resize function applies a compensation to the vertical position (second element in the figure Position vector) by adding the vertical position when the mouse is released to the height when mouse is released and subtracting the original height.
When the figure is resized from the bottom, it stays in the same position. When resized from the top, the figure moves to the location where the mouse button is released.
The resize function calls movegui to ensure that the resized figure is on screen regardless of where the user releases the mouse.
When the GUI is first run, it is displayed at the size and location specified by the figure Position property. You can set this property with the Property Inspector when you create the GUI.
function ResizeFcn(hObject, eventdata, handles)
% Get the figure size and position
Figure_Size = get(hObject, 'Position');
% Set the figure's original size in character units
Original_Size = [ 0 0 94 19.230769230769234];
% If the resized figure is smaller than the
% original figure size then compensate.
if (Figure_Size(3)<Original_Size(3)) | ...
(Figure_Size(4) ~= Original_Size(4))
if Figure_Size(3) < Original_Size(3)
% If the width is too small then reset to origianl width.
set(hObject, 'Position',...
[Figure_Size(1), Figure_Size(2), ...
Original_Size(3), Original_Size(4)])
Figure_Size = get(hObject, 'Position');
end
if Figure_Size(4) ~= Original_Size(4)
% Do not allow the height to change.
set(hObject, 'Position',...
[Figure_Size(1),...
Figure_Size(2)+Figure_Size(4)-Original_Size(4),...
Figure_Size(3), Original_Size(4)])
end
end
% Adjust the size of the Contact Name text box.
% Set the units of the Contact Name field to 'Normalized'.
set(handles.Contact_Name,'units','normalized')
% Get its Position.
C_N_pos = get(handles.Contact_Name,'Position');
% Reset it so that it's width remains normalized.
% relative to figure.
set(handles.Contact_Name,'Position',...
[C_N_pos(1) C_N_pos(2) 0.789 C_N_pos(4)])
% Return the units to 'Characters'.
set(handles.Contact_Name,'units','characters')
% Reposition GUI on screen.
movegui(hObject, 'onscreen')
![]() | A GUI to Set Simulink® Model Parameters | Using a Modal Dialog to Confirm an Operation | ![]() |
| © 1984-2008- The MathWorks, Inc. - Site Help - Patents - Trademarks - Privacy Policy - Preventing Piracy - RSS |