Sunday, April 8, 2012

Sharing data among MATLAB GUIs: Part 1

When there are multiple GUIs in your MATLAB application, the need to let the GUIs communicate with each other is inevitable. While sharing data between the different callbacks within the same GUI may already turn some people off, the sharing of data among different GUIs is not as difficult as one may think.

In short, you need to write functions in the different GUIs to deal with establishing communication links and data exchange, and when the time comes to pull/push data to/from a GUI, simply call the appropriate functions via the GUI's functions to have the data updated.

When two GUIs are sharing data, one of them must be providing the data while the other must be receiving the data. For simplicity'sake, I am going to call the one that sends the data as the source gui and the one that receives the data as the target gui.

In the source gui, you need to have a function that returns the desired data when it is called, say, get_data(). Similarly, in the target gui, you need to have a function that read in (or use) the data, say, set_data().

Depending on where you initiate the data exchange between the two guis, the sequence of actions is different. If the communication is initiated at the source gui, you are pushing data to the target gui; on the other hand, if it is initiated at the target gui, you are pulling data from the source gui. The former case will call the set_data function in the target gui to have the data pushed over, while the latter case will call the get_data function in the source gui to have the data pulled from the source gui.

Getting down to the actual implementation, there are basically two steps. In the first step, you need to make the guis aware of each other's existence and know what their responsibility is; in the second step, you need to specify the detail/protocol of the communication. You can think of the first step as the laying down the necessary hardware and the second step as implementing software that utilize the hardware in place.

Step 1: Setting up the communication links between the guis

To share data between guis, they have to be aware of each other. In the simplest cases where you have a source gui and a target gui, you will need to have the handle of the target gui in the source gui, and the handle of the source gui in the target gui. To accomplish that, you can have a set_target function in the source gui and a set_source function in the target gui. When the functions are called, they will take the handle of the other gui and store it as an item in the handles structure for later use. Below is a sample set_target function in the source gui.


function set_target(source_handle, target_handle)
% retrieve handles structure in the source gui
handles = guidata(source_handle);  
% assign target handle as an item in the handles structure 
handles.target = target_handle;
% save the handles s
guidata(source_handle, handles);


With the set_target and set_source functions properly written in the source gui and target gui, running the following code will have the communication link established.

% This will be your main script 
% start up the two guis 
source_handle = source_gui;
target_handle = target_gui; 
% establish the link between the two 
source_gui('set_target', source_handle, target_handle); 
target_gui('set_source', target_handle, source_handle);

Step 2: Setting up the communication protocol (well, in a way)

Once the links are established, you will need to implement rules as to what and how the data is shared. During the design, you need to make sure the guis make no assumption about what is going on in the other gui or what variables are being used. Knowing exactly what your intention is with each gui should be able to help you set up your rules properly.

As an example, I have two guis with text boxes and push buttons in them. The push button in the source gui is labelled 'Send', while the one in the target gui is labelled 'Retrieve'. The interaction is fairly straightforward, write whatever you can think of in the text boxes, once a push button is clicked, you will see the text in the source gui copied over to the text box in the target gui. That said, clicking the Send button will push the data, while clicking the Retrieve button will pull the data. Same results, different approach though. The set_data and get_data functions are posted below. Nothing fancy, they either set the string property or get the string from the text box.

function set_data(handles, s) %  in the target gui 
set(handles.txt_tgt,'string', s);


function s = get_data(handles) % in the source gui 
s = get(handles.txt_src,'string');

Note that to be able to call these functions from a different guis, you need to first `publish' the functions by adding the handle to the function as an item in the handles structure. To do that, in the opening function of the gui (before the handles structure is saved), add

handles.set_data = @set_data;

to the target gui, and add

handles.get_data = @get_data; 

to the source gui. Doing so will allow you to access these functions from a different gui.

As the final step, we just need to set up the callbacks of the push buttons, so that the data exchange will occur when the button is clicked. And it is in these functions, we will call the set_data and get_data function we prepared earlier.

% in the target gui 
% --- Executes on button press in pb_retrieve.
function pb_retrieve_Callback(hObject, eventdata, handles)
% get the handle to the source gui 
source_handle = handles.source; 
% get the handles structure of the target gui 
s_handles = guidata(source_handle); 
% update string to the one returned by the get_data function 
set(handles.txt_tgt, 'string', s_handles.get_data(s_handles));

% in the source gui 
% --- Executes on button press in pb_send.
function pb_send_Callback(hObject, eventdata, handles)
% get the handle to the target gui 
target_handle = handles.target; 
% get the handles structure of the target gui 
t_handles = guidata(target_handle); 
% call the set_data function 
t_handles.set_data(t_handles, get(handles.txt_src, 'string'));


Now, if you run the 'main' script to have the two guis running at the same time and have their link established, you will be able to observe the string passing from the source to the target. The example can be downloaded here. Run the test_script.m file.

While the example used is a very simple two-gui with one-way data flow, the same concept can be expanded and applied to cases where you want one-to-many or many-to-many guis with two-way communications. As long as you can have a clear design before diving into the coding, things should be relatively straightforward.

16 comments:

  1. Instead of following this long procedure why don't we use a Global Variable?

    I mean following the procedure in this link:

    https://www.facebook.com/note.php?note_id=155090817877779

    What are the drawbacks using a Global variable?

    ReplyDelete
  2. I have actually discuss the use of global variable in Part II, which can be found below.

    http://we15hang.blogspot.ca/2012/04/sharing-data-among-matlab-guis-part-2.html

    In short, with global variable, you will need to manually 'apply' the update, which isn't very user-friendly.

    Using the example on their page, after you update the value for the global variable x in one gui, you will have to click on the button on other GUIs in order to have the updated string shown.

    If you follow the long and tedious procedures shown in this post, however, the updated data will be pushed/pulled so that once you update the data in one GUI, the impact of such update can be immediately seen in other GUIs.

    Hope I explained it clearly. Feel free to ask if you have more questions.

    Good luck.

    ReplyDelete
  3. Yes, I got you now.
    I appreciate your work. Both of these articles about Data Sharing among GUI's is really helpful.

    I'm currently working on matlab GUI's. I will write you if I find any doubts.

    many thanks for your time :)

    ReplyDelete
  4. Wei, I find your article very interesting. I am working on 3 GUIs (using GUIDE). GUI-1 will call GUI-2 (used to collect user inputs, process the input data) and then output the results to GUI-3. Therefore, logically, there's no need to call the GUIs at the same time. Question1: Is your method applicable to transfering data between GUIs using GUIDE? Question2: In the case of 3 GUIs, how do you set the communication links as well as the communication protocol?
    Thanks.

    ReplyDelete
  5. Hi Anonymous, thanks for the comment.

    To answer your questions.

    1. Yes, what I have shown in the post would work with GUIs created with GUIDE. In fact, what I am doing is writing more functions for the GUIs, and it doesn't really have anything to do with GUIDE. Let me know if I misunderstood your question.

    2. I have just written a post regarding the design of the GUIs based on the example you gave me.

    http://we15hang.blogspot.ca/2012/06/matlab-guis-part-3.html

    I will be working on another post which will detail the implementation of the design in a more systematic way. If you can give me more detail as to what you are trying to do, I may be able to use it as an example, which should help you with your own work.

    ReplyDelete
  6. Thank you very much.

    ReplyDelete
  7. Hi nk15, it follows the same approach described in this post. You can download the sample code and try to make it work with an array (or whatever variable type you are working with) instead of a string, and then plot it on an axes (or just have it echo out in the command line) after you 'read' the array from the other gui.

    Let me know if you run into any problems.

    Wei

    ReplyDelete
  8. How could I transfer the data from GUI to m script?

    ReplyDelete
    Replies
    1. Not exactly sure what you want to do. If your GUI is a one-time deal (much like a dialog box), then you may want to look into using the GUI's output function. See the link to a tutorial below (not mine).

      http://blogs.mathworks.com/videos/2010/02/12/advanced-getting-an-output-from-a-guide-gui/

      If on the other hand you just want to grab some data from the GUI throughout the its lifetime, maybe you can try setappdata and getappdata. As long as you have the handle to the figure, you can easily store the variables using setappdata and you can retrieve the data in the script using the getappdata function. (not tested, but I think it should work).

      Finally, if you want to go fancy, write a function in the GUI which you can then call to get whatever. It will take more effort, but it is probably a must if you are developing some complicated GUIs.

      Good luck.

      Delete
  9. Hello Wei Shang

    I am using Computer Vision System Toolbox in Matlab to grabb images from two cameras simultaneously, I want to create an Graphical User Interface which include the picture grabbing from two cameras into two axis. The problem is I don't know how to create GUI with axis while using Computer Vision System Toolbox. Can you help me or provide me an matlab code for creating GUI using Computer Vision System toolbox to grabb images from camera in real time. Can you help me how to write matlab code with using image acquisition toolbox and computer vision system toolbox for grabbing images from two cameras simultaneously, these camera working on firewire bus.

    kind regards

    ReplyDelete
    Replies
    1. Hi Mgmdo,

      I think you will need to create the GUI and the axis for the image first, once that is done, you can have a push button on the gui, say, 'Get Image'. And when pushed, it will get the image from the Computer Vision System Toolbox and show it on the axis.

      Unfortunately I don't have have the toolbox (nor time) to code it up, maybe some of your colleague and help you with that? I don't expect this to be overly complicated (unless I am missing something).

      Good luck.





      Delete
    2. Also, instead of a push button, you could set up a timer object so that he image is updated at a fixed interval.

      Delete
  10. Hi Wei Shang,

    Thanks for your post. Can I ask how should we set up the Gui with guide using a OK-pushbutton (from/on a sub Gui) when clicked, will pass a set of values & display in the editboxes in the main Gui?

    Thanks for your help.

    ReplyDelete
    Replies
    1. What values are to be passed in?

      If it is a simple confirmation dialog box, MATLAB has a selection of predefined dialogs that may suit your need.

      http://www.mathworks.com/help/matlab/predefined-dialog-boxes.html

      If none of those suits you, you can easily create your own.

      http://www.mathworks.com/help/matlab/creating_guis/modal-dialog-box-in-a-guide-gui.html

      Hope it helps.

      Delete
    2. Hi Wei Shang,

      Thanks for your reply and suggestions.

      I have made a main-GUI and a sub-GUI using guide. On the main-GUI, I have, for example, three editboxes and a A-pushbutton. On the sub-GUI, I have a set of data and a OK-pushbutton.

      I have coded the "sub-GUI name" under the A-pushbutton callback so when I click the A-pushbutton, it will pop-up the sub-GUI.

      On the sub-GUI, I have a pre-defined data, for example, x=1;y=2;z=3 which I would like to pass to the main-GUI and display on the editboxes (created on the main-GUI) when the OK-pushbutton is clicked.

      I tried set it up with setappdata & getappdata, but can you please guide me the correct way to code the syntax please?

      Thanks for your time.

      Delete
    3. It is possible.

      In fact, if you pass in the handle to your main GUI (which I believe is just a figure handle) to your sub-gui when you create it, you then have complete control over the your main GUI. That means (based on logic) you can get or update the application data in the main gui (with setappdata and getappdata) , update the handles in your main gui, etc.

      I would put an example out if I have time, unfortunately, little free time.

      Good luck and let me know how it goes.

      Delete