MATLAB GUI傳遞方式
1、全局變量;
2、作為函數的參數傳遞;
3、利用控件的userdata數據;
4、為handles結構體添加新字段;
5、setappdata函數為句柄添加數據;
6、跨空間計算evalin和賦值assignin;
7、將數據保存到文件,需要時讀取;
8、帶參數調用GUI的M文件;
9、嵌套函數(不適用於GUIDE中,只適用純命令是的GUI)。
一. 全局變量
運用global定義全局變量傳遞參數,適用於gui內控件間以及不同gui間。這種方式恐怕是最簡單的方式,是很省心!但是,簡單的問題就在於有時你會很頭疼!因為在每一個要到該全局變量的地方,你都要添一句gloal x,還有就是如果你在一個地方修改了 x的值,那么所有x的值就都變了!有的時候恐怕會出現紊亂。另一個更重要的問題在於,套用C++的一句話,全局變量破壞了程序的封裝性!所以,全局變量是能少用盡量少用。
以下創造一個簡單的GUI給大家說明一下,建一個GUI, 包含兩個按鈕,一個坐標系,一個用來畫y=sin(x),一個用來畫y=cos(x);
eg:在GUI的OpeningFcn函數中寫:
global x y1 y2
x=0:.1:2*pi;y1=sin(x);y2=cos(x);
在pushbutton1_Callback函數中寫
Global x y1
Plot(x,y1)
在pushbutton1_Callback函數中寫
Global x y2
Plot(x,y2)
全局變量是比較方便的,但全局變量會破壞封閉性,如果不是有大量數據要傳遞,建議不要使用。
二. 運用gui本身的varain{}、varaout{}傳遞參數
這種方式僅適用於gui間傳遞數據,且只適合與主子結構,及從主gui調用子gui,然后關掉子gui,而不適合遞進結構,即一步一步實現的方式。
輸入參數傳遞(主要在子gui中設置):
比如子GUI的名稱為subGUI, 設想的參數輸入輸出為:[out1, out2] = subGUI(in1, in2)
在subGUI的m文件中(由GUIDE自動產生):
1.第一行的形式為:function varargout = subGUI(varargin)
該行不用做任何修改;varargin 和 varargout 分別是一個可變長度的cell型數組。輸入參數in1和in2保存在varargin中,輸出參數out1,out2包含在varargout中;
2.在subGUI的OpeningFcn中,讀入參數,並用guidata保存,即:
handles.in1 = varargin{1};
handles.in2 = varargin{2};
guidata(hObject, handles);
返回參數的設置:
1. 在主GUI的OpeningFcn函數中加上[out1, out2] = subGUI(in1, in2),用於調用子gui,並在結尾加上uiwait(handles.figure1); figure1是subGUI的Tag,主要是等待調用子gui的過程,從而獲得子gui的輸出參數out1、out2;
2. subGUI中控制程序結束(如"OK”和"Cancel"按鈕)的callback末尾加上uiresume(handles.figure1),注意是主gui的窗口handles.figure1,不要將delete命令放在這些callback中;
3. 在子GUI的OutputFcn中設置要傳遞出去的參數,如 varargout{1} = handles.out1;varargout{2} = handles.out2;末尾添加 delete(handles.figure1); 結束程序。
在GUI的OpenFcn中,如果不加uiwait, 程序會直接運行到下面,執行OutputFcn。也就是說程序一運行,返回值就確定了,再在其它部分對handles.output作更改也沒有效果了。
加上uiwait后,只有執行了uiresume后,才會繼續執行到OutputFcn,在此之前用戶有充分的時間設置返回值。
通過以上設置以后,就可以通過 [out1, out2] = subGUI(in1, in2) 的形式調用該子程序。
在一個GUI中調用另一個GUI時,主GUI不需要特別的設置,同調用普通的函數一樣。在打開子GUI界面的同時,主程序還可以響應其它的控件。不需要擔心子GUI的返回值被傳錯了地方。
三. userdata數據
直接通過對象的userdata屬性進行各個callback之間的數據存取操作,主要適用於gui內。首先必須將數據存儲到一個特定的對象中,假設對象的句柄值為ui_handle,需要存儲的值為value,則輸入以下程序即可:
set('ui_handle','UserData',Value);
此時,value數據就存在句柄值為ui_handle的對象內,在執行的過程中若要取回變量可以通過以下方式在任意callback中獲取該數據值 :
value=get('ui_handle','UserData');
雖然使用這種方法簡單 ,但是每個對象僅能存取一個變量值,因此當同一對象存儲兩次變量時 ,先前的變量值就會被覆蓋掉,因此都用UserData存儲簡單與單一的數據。如下面有兩個gui函數, myloadfn加載mydata.mat文件,該文件內存儲XYData變量,其值為m*2的繪圖矩陣,加載后將該變量值存儲到 當前的窗口的UserData屬性中。另一個myplotfcn函數則是用以獲取該UserData屬性中存取的繪圖數據,然后繪圖。代碼如下:
function myloadfcn
load mydata;
set(gcbf,'UserData',XYdata)
function myplotfcn
XYdata=get(gcbf,'UserData');
x=XYData(:,1);
y=XYData(:,2);
plot(x,y);
userdata的缺點就是一個句柄只能放一個Userdata。
四. GUI數據(handles)
結合handles和guidata函數,適用於gui內,如果你在pushbutton1中得到一個變量X,相傳出去,那么在pushbutton1的callback中,在得到X后添加如下代碼:
handles.X=X;
guidata(hObject,handles)(注意,一定是兩行連寫)
在pushbutton2中要用到X是,在其callback先添加 X=handles.X; 即可得到X的值。
注:
- guidata(object_handle,data);如果object_handle不是figure型句柄,那么會將data保存在object_handle的父figure對象中。這樣不必擔心在一個pushbutton的callback中存儲的變量在其他對象中無法提取。
- data = guidata(object_handle);獲取當前object_handle的handles數據,最后一次guidata(object_handle,data)保存的數據。
一個簡單的GUI給大家說明一下,建一個GUI, 包含兩個按鈕,一個坐標系,一個用來畫y=sin(x),一個用來畫y=cos(x);
eg:在GUI的OpeningFcn函數中寫:
x=0:.1:2*pi;
y1=sin(x);
y2=cos(x);
handles.x=x;
handles.y1=y1;
handles.y2=y2;
guidata(hObject, handles);%注意,在OpeningFcn函數中這句是本身存在的,若在其它函數中,務必加上這句
在pushbutton1_Callback函數中寫
x=handles.x;
y1=handles.y1;
plot(x,y1)
在pushbutton2_Callback函數中寫
x=handles.x;
y2=handles.y2;
plot(x,y2)
五. Application數據
應用setappdata\getappdata與rmappdata函數,適用於gui間和gui內。使用上面三個函數最有彈性處理數據的傳送問題,與UserData的方式相類似,但是克服UserData的缺點,使一個對象能存取多個變量值。
(1)getappdata函數
value=getappdata(h,name)
(2)setappdata函數
setappdata(h,name,value)
(3)rmappdata函數
rmappdata(h,name)
首先在matlab命令窗口輸入magic(3)數據,因此當前的工作空間就存儲了magic(3)這組數據了,然后建立一個按鈕來獲取並顯示magic(3)數據。
A=magic(3);
setappdata(gcf,'A',A);%save
uicontrol('String','顯示矩陣A','callback','A=getappdata(gcf,''A'')');
A =
8 1 6
3 5 7
4 9 2
當在主、子gui內調用時,可以如下設置
fig1調用fig2時,使用fig2指令來打開fig2,
在fig2的m文件中,在回調函數中用setappdata(fig1,'A',A);實現返回fig1,並將參數A傳遞給fig1
然后在fig1的使用A的地方添加A=getappdata(fig1,‘A’)。
但這種方式的一個問題就是每調用一次,fig1的數據就得初始化一次,這是因為setappdata(fig1,'A',A)中出現了fig1,調用一次setappdata就得運行一次fig1的緣故,解決方案就是把setappdata(fig1,'A',A)改為setappdata(0,'A',A),這樣把A讀入matlab workspace,相當於一個全局變量了,但當然比直接用global定義全局變量好!
同樣的例子:
eg:在GUI的OpeningFcn函數中寫:
x=0:.1:2*pi;
y1=sin(x);
y2=cos(x);
setappdata(handles.figure1,'x',x) %在figure1下創建’x’,包含數據x,也可以放在其它句柄下,如setappdata(handles. pushbutton1,'x',x),不過一般放在figure1下,記起來方便……
setappdata(handles.figure1,'y1',y1)
setappdata(handles.figure1,'y2',y2)
在pushbutton1_Callback函數中寫
x=getappdata(handles.figure1,'x');%提取,當然用get了……
y1=getappdata(handles.figure1,'y1');
plot(x,y1)
在pushbutton1_Callback函數中寫
x=getappdata(handles.figure1,'x');
y2=getappdata(handles.figure1,'y2');
plot(x,y2)
六. 跨空間計算evalin和賦值assignin
適用於gui間和gui內
Assignin函數基本語法
assignin(ws, 'var', val)
其中'base' or 'caller',分別表示基本工作空間和調用函數(caller function)工作空間,
Assinin函數將值val指定給工作空間ws中的變量var,若變量var不存在,則創建一個變量var。
從一個函數function向MATLAB工作空間中輸入數據;
在一個函數function內部,需要改變一個在caller function函數工作空間中定義的變量,例如函數形參列表中的變量。
例子:
%向基本工作空間中傳輸數據變量
Function assignin_test1
prompt = {'Enter image name:','Enter colormap name:'};
title = 'Image display - assignin example';
lines = 1;
def = {'my_image','hsv'};
answer = inputdlg(prompt,title,lines,def);
assignin('base','imfile',answer{1});
assignin('base','cmap',answer{2});
evalin函數基本語法
evalin(ws, expression)
[a1, a2, a3, ...] = evalin(ws, expression)
在特定的工作空間執行MATLAB語句,expression的形式如
expression = [string1, int2str(var), string2,...]
[a1, a2, a3, ...] = evalin(ws, expression),將返回值賦予變量a1,a2,a3,... evalin(ws,'[a1, a2, a3, ...] = function(var)')
注:
evalin('caller', expression),只能指定callerfunction函數中的變量為expression的語句,而不能是subfunction
該函數不可嵌套使用,evalin('caller', 'evalin(''caller'', ''x'')')是錯誤的
例子:
如果在figure1中有個變量a1
則傳入時assignin('base','data',a1) %data是workplace中的變量
在figure2傳出時a2=evalin('base','data'); %a2是figure2中的變量
七. 將數據保存到文件,需要時讀取
運用save和load(importdata)傳遞參數,適用於gui間和gui內。將某變量x的值先存到磁盤,用的時候在調用。格式如下:save('*.mat','x');用的時候就用load('*.mat'),但這樣只是把x讀到了matlab workspace,不會用顯示,你還要再去查看這個變量名, 然后才能用,建議使用p=importdata('*.mat'),p是一個結構體,可以隨意使用了。當然,這種方式涉及到磁盤讀寫,速度當然會有影響的,一般情況不用,通常用在保存以及導入某個變量時!
八. 帶參數調用GUI的M文件
這個相信大家都很熟悉了,適用於gui間和gui內。
總結幾點:
① 如果變量數據量很大,需要占用大量內存,不要將變量存儲為handles的變量,因為每個控件每次調用callback function都會使用handles,增加不必要的內存開銷。若改變量存取不頻繁,可以考慮UserData數據或者Application數據;若存取比較頻繁,建議使用Global變量和Application結構體,這里的Application要定義為setappdata(0,'var',val)以及getappdata(0,'var',val)。
② 對於GUI界面之間的數據傳遞,可以考慮以下幾種方法:
方法1:采用global函數。
可以采用這種方法共享數據;
方法2:采用findobj和findall函數查找對象句柄
findall(0, 'Type', 'figure', 'Tag', 'figure1')
查找標簽為figure1的窗口,無論該窗口是否隱藏。
方法3:采用handles結構。
假設我們在窗口1的Opening函數中,采用函數創建了一個子窗口2:
h_fig = figure('Visible', 'off', ...);
h_btn1 = uicontrol('Parent', h_fig, ‘Tag', 'btn1', ...);
h_btn2 = uicontrol('Parent', h_fig, ‘Tag', 'btn2', ...);
h_btn3 = uicontrol('Parent', h_fig, ‘Tag', 'btn3', ...);
如果我們要在窗口1的任何回調函數中,直接訪問子窗口2的任意控件,可以在上述語句后緊跟着寫下如下語句:
handles.btn1 = h_btn1;
handles.btn2 = h_btn2;
handles.btn3 = h_btn3;
最后,需要一個guidata語句。當然,Opening函數最后有guidata語句,所以不用自己添加。
方法4:將要共享的數據使用save函數存入mat文件;或者使用文件I/O函數,存入文本文件中。
引用:http://wenku.baidu.com/view/e3b07f624431b90d6d85c71b.html?re=view