Making Multiple GUIs Work Together

Data-Sharing Techniques

Although most GUIs created in GUIDE use single figures, you can make several GUIDE-generated GUIs work together if your application requires more than a single figure. For example, your GUI may need to use several dialog boxes to display and obtain some of the parameters used by the GUI, or your GUI may include several individual tools that work together, either at the same time or in succession.

This section describes the techniques you can use to share data among multiple GUIDE GUIs. It also provides examples that show you how to make a set of GUIs cooperate with one another.

GUIs can share data in many ways. In a given application you can use more than one technique. To avoid communication via files or workspace variables, you can use any of the methods described in the following table:

Data-Sharing MethodHow it WorksUse for...
Property/value pairsSend data into a newly invoked or existing GUI by passing it along as input arguments.Communicating data to new GUIs.
OutputReturn data from the invoked GUI.Communicating data back to the invoking GUI, such as passing back the handles structure of the invoked GUI.
Function handles Pass function handles as data through one of the three following methods.Exposing functionality within a GUI or between GUIs.
userdata: Store data in a figure or component; communicate to other GUIs via handle references.Communicating data within a GUI or between GUIs.
getappdata/setappdata: Store data as a property in a figure or component; communicate to other GUIs via handle references.Communicating data within a GUI or across GUIs.
guidata: Store data in the handles structure of a GUI; communicate to other GUIs via handle references.Communicating data within a GUI or across GUIs; a convenient way to manage application data.

The techniques described in Sharing Data Among a GUI's Callbacks for sharing data within a GUI—GUI data , application data, and user data property—can also share data among several GUIs as long as the handles to objects in the first GUI are made available to other GUIs.

This section provides two examples that illustrate these techniques. The first example describes how a simple GUI can open and receive data from a modal dialog box. The second, more extensive, example illustrates how the three components of an icon editor are made to interact.

Example—Manipulating a Modal Dialog Box for User Input

This example illustrates how to do the common tasks involved in making multiple GUIs work together. It explains how to position a second GUI relative to the main GUI and demonstrates how data is passed to a modal dialog box invoked from a GUIDE GUI. The dialog box displays text data in an edit field. Changes that you make to the edit field are passed back to the main GUI. The main GUI uses this data in various ways. You can update the appearance of one of the components of the main GUI by changing the data in the modal dialog box.

The main GUI contains one button and a static text field giving instructions. When you click the button, a modal dialog box opens and the button's current string appears in an editable text field that you can then change it. If you click OK, the value of the text field is returned to the main GUI, which sets the string property of the button to value you entered. The main GUI and its modal dialog box are shown in the following figure.

How the Text Change Dialog Box Works

When the user clicks the Change Me button, the Text Change dialog box appears. To invoke this dialog box, include a property/value pair with name 'changeme_main' (the main GUI's name) and value set to the handle to the main figure in the argument. This data enables the dialog box to access the main GUI's data. If the main GUI's data is missing, the dialog box displays an error that describes proper usage and exits.

function buttonChangeMe_Callback(hObject, ...
         eventdata, handles)
changeme_dialog('changeme_main', handles.figure);

Perform the following tasks in MATLAB in the order they occur.

Managing the Text Change Dialog

  1. In the Property Inspector for the Text Change dialog boxes figure, set the 'WindowStyle' property to 'Modal'. This ensures that the Text Change dialog box is modal and that the user cannot interact with other figures while this dialog box is active.

  2. Invoke uiwait in the OpeningFcn of the dialog box to put off calling the output function until uiresume is called. This keeps the invocation call of the GUI from returning until that time:

    function changeme_dialog_OpeningFcn(hObject, ...
             eventdata, handles, varargin)
    .
    .
    .
    uiwait(hObject);
    .
    .
    .
    
  3. Invoke uiresume within CloseRequestFcn for the figure, the Cancel button, and the OK button. Every callback in which the GUI needs to close should call uiresume:

    function buttonCancel_Callback(hObject, ...
             eventdata, handles)
    uiresume(handles.figure);
    
    function figure_CloseRequestFcn(hObject, ...
             eventdata, handles)
    uiresume(hObject);
    
    function buttonOK_Callback(hObject, e...
             ventdata, handles)
    .
    .
    .
    uiresume(handles.figure);
  4. In the OutputFcn, make sure to delete the figure, so that it closes:

    function varargout = changeme_dialog_Dialog_OutputFcn(hObject, ...
             eventdata, handles)
    varargout{1} = [];
    delete(hObject);

Protecting and Position the Text Change Dialog

  1. Make sure you invoke the Text Change dialog box from the main GUI. The OpeningFcn for the dialog box scans the input arguments for the changeme_main property. If it does not find the property or finds an invalid value, the modal dialog box displays an error and exits.

  2. Validate the input and call uiwait. This ensures that the main GUI can exit without waiting for OutputFcn to close the figure:

    function changeme_dialog_OpeningFcn(hObject, ...
             eventdata, handles, varargin)
    
    % Check to see the changeme_main gui is passed in
    dontOpen = false;
    mainGuiInput = find(strcmp(varargin, 'changeme_main'));
    if (isempty(mainGuiInput)) 
      || (length(varargin) <= mainGuiInput) 
      || (~ishandle(varargin{mainGuiInput+1}))
        dontOpen = true;
    else
    .
    .
    .
    end
    .
    .
    .
    if dontOpen
       disp('-----------------------------------------------------');
       disp('Improper input arguments. Pass a property value pair') 
       disp('whose name is "changeme_main" and value is the handle')
       disp('to the changeme_main figure.');
       disp('eg:');
       disp('   x = changeme_main()');
       disp('   changeme_dialog('changeme_main', x)');
       disp('-----------------------------------------------------');
    else
       uiwait(hObject);
    end
  3. Position the Text Change dialog box to the lower-right side of the main figure using the passed-in handle to the main figure. This ensures that if the main figure is moved and the dialog box is invoked, it opens in the position you specified instead of in a different location.

    function changeme_dialog_OpeningFcn(hObject, ...
             eventdata, handles, varargin)
    .
    .
    .  
    mainGuiInput = find(strcmp(varargin, 'changeme_main'));
    .
    .
    .
    handles.changeMeMain = varargin{mainGuiInput+1};
    .
    .
    .
        % Position to be relative to parent:
        parentPosition = getpixelposition(handles.changeMeMain);
        currentPosition = get(hObject, 'Position');  
        % Sets the position to be directly centered on the main figure
        newX = parentPosition(1) + (parentPosition(3)/2 ...
             - currentPosition(3)/2);
        newY = parentPosition(2) + (parentPosition(4)/2 ...
             - currentPosition(4)/2);
        newW = currentPosition(3);
        newH = currentPosition(4);
        
        set(hObject, 'Position', [newX, newY, newW, newH]);
    .
    .
    .

Initializing Text in the Text Change Dialog Box

  1. To initialize the Text Change dialog box text to the Change Me button's current text, get the main GUI's handles structure from the handle that was passed to the modal dialog box:

    function changeme_dialog_OpeningFcn(hObject, ...
             eventdata, handles, varargin)
    
    mainGuiInput = find(strcmp(varargin, 'changeme_main'));
    .
    .
    .
    % Remember the handle, and adjust our position
    handles.changeMeMain = varargin{mainGuiInput+1};
  2. Get the Change Me button's String property and set the String property to the edit box's value in the dialog box OpeningFcn.

    % Set the initial text
    mainHandles = guidata(handles.changeMeMain);
    set(handles.editChangeMe, 'String', …
        get(mainHandles.buttonChangeMe, 'String'));
    .
    .
    .

Canceling the Text Change Dialog Box

Call uiresume to close the modal dialog box if the user clicks Cancel or closes the window. Do not modify the main GUI to close the modal dialog box.

function buttonCancel_Callback(hObject, ...
         eventdata, handles)
uiresume(handles.figure);
 
function figure_CloseRequestFcn(hObject, ...
         eventdata, handles)
uiresume(hObject);

Applying the Text Change

Use the reference to the main GUI in the handles structure saved by OpeningFcn in the modal dialog box to apply the text change. The user clicks OK to apply the text change . This sets the Change Me button label in the main GUI to the value entered in the text field of the modal dialog box.

function buttonOK_Callback(hObject, ...
         eventdata, handles)
text = get(handles.editChangeMe, 'String');
main = handles.changeMeMain;
mainHandles = guidata(main);
changeMeButton = mainHandles.buttonChangeMe;
set(changeMeButton, 'String', text);
uiresume(handles.figure);

Example—Individual GUIDE GUIs Working Together as an Application

This example demonstrates how three GUIs in GUIDE work together within the main GUI. These GUIs share data and expose functionality to one another using several different techniques:

Background Information

The following sections describe how each GUI works, both independently and in conjunction with the other GUIs, and how its M-file is implemented.

GUI Behavior Icon Editor.   The behavior of the Icon Editor application is described in this sequence:

M-file Implementations.   The Icon Editor application uses three M-files and FIG-files that were fully implemented in GUIDE. You can modify and enhance them in the GUIDE environment should you choose to do so. The FIG-files are:

The associated M-files contain the following functions and signatures:

Launching the Icon Editor and the Tool and Color Palettes

When you launch the Icon Editor, the Tool Palette and Color Palette automatically starts up. The Tool and the Color Palettes are children of the Icon Editor and communicate as described here:

The Icon Editor is passed into the Tool Palette, and Color Palette as a property/value (p/v) pair that allows the Tool and Color Palette to make calls back into Icon Editor. The output value from calling both of the palettes is the handle to their GUI figures. These figure handles are saved into the handles structure of Icon Editor:

% in Icon Editor
function guide_Icon Editor_OpeningFcn(hObject, ...
         eventdata, handles, varargin)
.
.
.
handles.colorPalette = guide_colorpalette('iconEditor', hObject);
handles.toolPalette = guide_toolpalette('iconEditor', hObject);
.
.
.
% Update handles structure
guidata(hObject, handles);

The Color Palette needs to remember the Icon Editor for later:

% in colorPalette
function guide_colorpalette_OpeningFcn(hObject, ...
         eventdata, handles, varargin)
handles.output = hObject;
.
.
.
handles.iconEditor = [];

iconEditorInput = find(strcmp(varargin, 'iconEditor'));
if ~isempty(iconEditorInput)
   handles.iconEditor = varargin{iconEditorInput+1};
end
.
.
.
% Update handles structure
guidata(hObject, handles);

The Tool Palette also needs to remember the Icon Editor:

% in toolPalette
function guide_toolpalette_OpeningFcn(hObject, ...
         eventdata, handles, varargin)
handles.output = hObject;
.
.
.
handles.iconEditor = [];

iconEditorInput = find(strcmp(varargin, 'iconEditor'));
if ~isempty(iconEditorInput)
   handles.iconEditor = varargin{iconEditorInput+1};
end
.
.
.
% Update handles structure
guidata(hObject, handles);

Setting the Initial Color on the Color Palette

After you create all three GUIs, you need to set the initial color. When you invoke the Color Palette from the Icon Editor, the Color Palette passes a function handle that tells the Icon Editor how to set the initial color. This function handle is stored in its handles structure. You can retrieve the handles structure from the figure to which the Color Palette outputs the handle:

% in colorPalette
function guide_colorpalette_OpeningFcn(hObject, ...
         eventdata, handles, varargin)
handles.output = hObject;
.
.
.
% Set the initial palette color to black
handles.mSelectedColor = [0 0 0];

% Publish the function setSelectedColor
handles.setColor = @setSelectedColor;
.
.
.
% Update handles structure
guidata(hObject, handles);


% in colorPalette
function setSelectedColor(hObject, color)
handles = guidata(hObject);
.
.
.
handles.mSelectedColor =color;
.
.
.
guidata(hObject, handles);

Call the publicized function from the Icon Editor, setting the initial color to 'red':

% in Icon Editor
function guide_iconeditor_OpeningFcn(hObject, ...
         eventdata, handles, varargin)
.
.
.
handles.colorPalette = guide_colorpalette('iconEditor', hObject);
.
.
.
colorPalette = handles.colorPalette;
colorPaletteHandles = guidata(colorPalette);
colorPaletteHandles.setColor(colorPalette, [1 0 0]);
.
.
.
% Update handles structure
guidata(hObject, handles);

Accessing the Color Palette's Current Color from the Icon Editor

The Color Palette initializes the current color data:

%in colorPalette
function guide_colorpalette_OpeningFcn(hObject, ...
         eventdata, handles, varargin)
handles.output = hObject;
.
.
.
handles.mSelectedColor = [0 0 0];
.
.
.
% Update handles structure
guidata(hObject, handles);

The Icon Editor retrieves the initial color from the Color Palette's GUI data via its handles structure:

% in Icon Editor
function color = getColor(hObject)
handles = guidata(hObject);
colorPalette = handles.colorPalette;
colorPaletteHandles = guidata(colorPalette);
color = colorPaletteHandles.mSelectedColor;

Using UserData Property to Share Data

You can use the UserData property of components in your GUIDE GUI to share data. When you click the mouse in the icon editing area, you select a tool. You can use every tool in the Tool Palette to modify the icon you are editing by altering the tools CData. The GUI uses the UserData property of each tool to record the function that you call when a tool is selected and applied to the icon-editing area. Each tool alters different aspects of the icon data. Here is an example of how the pencil tool works.

In the CreateFcn for the pencil tool, add the user data that points to the function for the pencil tool:

% in toolPalette
function toolPencil_CreateFcn(hObject, eventdata, handles)
set(hObject,'UserData', struct('Callback', @pencilToolCallback));

The Tool Palette tracks the currently selected tool in its handles structure's mCurrentTool field. You can get this structure from other GUIs once you create the handles structure of the Tool Palette. Set the currently selected tool by calling guidata after you click a button in the Tool Palette:

% in toolPalette
function toolPalette_SelectionChangeFcn(hObject, ...
        eventdata, handles)
handles.mCurrentTool = hObject;
guidata(hObject, handles);

When you select the pencil tool and click in the icon-editing area, the Icon Editor calls the pencil tool function:

% in iconEditor
function iconEditor_WindowButtonDownFcn(hObject,...
         eventdata, handles)
toolPalette = handles.toolPalette;
toolPaletteHandles = guidata(toolPalette);
	.
	.
	.
userData = get(toolPaletteHandles.mCurrentTool, 'UserData');
handles.mIconCData = userData.Callback(toolPaletteHandles, ...
        toolPaletteHandles.mCurrentTool, handles.mIconCData, ...);

The following code shows how the pixel value in the icon-editing area under the mouse click (the Tool icon's CData) changes to the color currently selected in the Color Palette:

% in toolPalette
function cdata = pencilToolCallback(handles, toolstruct, cdata,...)
iconEditor = handles.iconEditor;
iconEditorHandles = guidata(iconEditor);
x = ...
y = ...
% update color of the selected block
color = iconEditorHandles.getColor(iconEditor);
cdata(y, x,:) = color;

Displaying the Current Tool's Cursor

You can have the cursor display the current tools pointer icon when the mouse is in the editing area and the default arrow is displayed outside the editing area. To do this you must identify the selected tool through the Tool Palette's handles structure:

% in Icon Editor
function iconEditor_WindowButtonMotionFcn(hObject, ...
        eventdata, handles)
.
.
.
rows = size(handles.mIconCData,1);
cols = size(handles.mIconCData,2);
pt = get(handles.icon,'currentpoint');
overicon = (pt(1,1)>=0 && pt(1,1)<=rows) && ...
           (pt(1,2)>=0 && pt(1,2)<=cols);
.
.
.
if ~overicon
    set(hObject,'pointer','arrow');        
else
    toolPalette = handles.toolPalette;
    toolPaletteHandles = guidata(toolPalette);
    tool = toolPaletteHandles.mCurrentTool;
    cdata = round(mean(get(tool, 'cdata'),3))+1;
    if ~isempty(cdata)
        set(hObject,'pointer','custom','PointerShapeCData', ...
        cdata(1:16, 1:16),'PointerShapeHotSpot',[16 1]);        
    end
end
.
.
.

Closing All Windows When Complete

When the Icon Editor was launched, the handles structure was invoked, which in turn opened the Color Palette and Tool Palette. However, Icon Editor also invoked uiwait to defer output until the GUI is complete. When you need to close the windows, neither the Color Palette nor Tool Palette close independently of Icon Editor because there is a complicated close sequence involved. You can close all windows using one of these methods:

You cannot close the Color Palette and Tool Palette windows (by clicking their X box) directly.

In the next example, you set the output of Icon Editor to be the Cdata of the icon. The opening function for Icon Editor, with uiwait, contains this code:

% in Icon Editor
function guide_iconeditor_OpeningFcn(hObject, eventdata, ...
        handles, varargin)

.
.
.
handles.colorPalette = guide_colorpalette();
handles.toolPalette = guide_toolpalette('iconEditor', hObject);
.
.
. 
% Update handles structure
guidata(hObject, handles);
uiwait(hObject);

As a result, you must call uiresume on each exit path:

% in Icon Editor
function buttonOK_Callback(hObject, eventdata, handles)
uiresume(handles.figure);

function buttonCancel_Callback(hObject, eventdata, handles)
% Make sure the return data will be empty if we cancelled
handles.mIconCData =[];
guidata(handles.figure, handles);
uiresume(handles.figure);

function Icon Editor_CloseRequestFcn(hObject, eventdata, handles)
uiresume(hObject);

To ensure that the Color Palette is not closed any other way, override its closerequestfcn to take no action:

% in colorPalette
function figure_CloseRequestFcn(hObject, eventdata, handles)
% Don't close this figure. It must be deleted from Icon Editor

Do the same for the Tool Palette:

% in toolPalette
function figure_CloseRequestFcn(hObject, eventdata, handles)
% Don't close this figure. It must be deleted from Icon Editor

Finally, in the output function, delete all three GUIs:

% in Icon Editor
function varargout = guide_iconeditor_OutputFcn(hObject, ...
        eventdata, handles)
% Return the cdata of the icon. If cancelled, this will be empty
varargout{1} = handles.mIconCData;
delete(handles.toolPalette);
delete(handles.colorPalette);
delete(hObject);
  


 © 1984-2008- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS