轉(zhuǎn)自 http://blog.csdn.net/smf0504/article/details/51814375
其實(shí)Matlab提供了很多種直接或間接方法實(shí)現(xiàn)多fig中的數(shù)據(jù)共享,只是大家沒有注意罷了:
1鄙信、全局變量
2喷市、作為函數(shù)的參數(shù)傳遞
3描沟、利用控件的userdata數(shù)據(jù)
4囱嫩、為handles結(jié)構(gòu)體添加新字段
5、setappdata函數(shù)為句柄添加數(shù)據(jù)
6胚吁、跨空間計(jì)算evalin和賦值assignin
7、將數(shù)據(jù)保存到文件恋脚,需要時(shí)讀取
8、帶參數(shù)調(diào)用GUI的M文件
9焰手、嵌套函數(shù)(不適用于GUIDE中糟描,只適用純命令是的GUI)
一、全局變量
運(yùn)用global定義全局變量傳遞參數(shù)书妻,適用于gui內(nèi)控件間以及不同gui間船响。這種方式恐怕是最簡單的方式,是很省心躲履!但是见间,簡單的問題就在于有時(shí)你會很頭疼!因?yàn)樵诿恳粋€(gè)要到該全局變量的地方工猜,你都要添一句gloalx米诉,還有就是如果你在一個(gè)地方修改了 x的值,那么所有x的值就都變了篷帅!有的時(shí)候恐怕會出現(xiàn)紊亂史侣。另一個(gè)更重要的問題在于,套用C++的一句話魏身,全局變量破壞了程序的封裝性惊橱!所以,全局變量是能少用盡量少用箭昵。
以下創(chuàng)造一個(gè)簡單的GUI給大家說明一下税朴,建一個(gè)GUI, 包含兩個(gè)按鈕家制,一個(gè)坐標(biāo)系正林,一個(gè)用來畫y=sin(x),一個(gè)用來畫y=cos(x);
eg:在GUI的OpeningFcn函數(shù)中寫:
globalx y1 y2
x=0:.1:2*pi;y1=sin(x);y2=cos(x);
在pushbutton1_Callback函數(shù)中寫
Globalx y1
Plot(x,y1)
在pushbutton1_Callback函數(shù)中寫
Globalx y2
Plot(x,y2)
全局變量是比較方便的,但全局變量會破壞封閉性颤殴,如果不是有大量數(shù)據(jù)要傳遞卓囚,建議不要使用。
二诅病、運(yùn)用gui本身的varain{}哪亿、varaout{}傳遞參數(shù)
這種方式僅適用于gui間傳遞數(shù)據(jù),且只適合與主子結(jié)構(gòu)贤笆,及從主gui調(diào)用子gui蝇棉,然后關(guān)掉子gui,而不適合遞進(jìn)結(jié)構(gòu)芥永,即一步一步實(shí)現(xiàn)的方式篡殷。
輸入?yún)?shù)傳遞(主要在子gui中設(shè)置):
比如子GUI的名稱為subGUI,設(shè)想的參數(shù)輸入輸出為:[out1,out2] = subGUI(in1, in2)
在subGUI的m文件中(由GUIDE自動產(chǎn)生):
1.第一行的形式為:function varargout = subGUI(varargin)
該行不用做任何修改;varargin 和varargout 分別是一個(gè)可變長度的cell型數(shù)組埋涧。輸入?yún)?shù)in1和in2保存在varargin中板辽,輸出參數(shù)out1奇瘦,out2包含在varargout中;
2.在subGUI的OpeningFcn中劲弦,讀入?yún)?shù)耳标,并用guidata保存,即:
handles.in1= varargin{1};
handles.in2= varargin{2};
guidata(hObject,handles);
返回參數(shù)的設(shè)置:
1.在主GUI的OpeningFcn函數(shù)中加上[out1, out2] = subGUI(in1, in2)邑跪,用于調(diào)用子gui次坡,并在結(jié)尾加上uiwait(handles.figure1);figure1是subGUI的Tag,主要是等待調(diào)用子gui的過程画畅,從而獲得子gui的輸出參數(shù)out1砸琅、out2;
2.subGUI中控制程序結(jié)束(如"OK”和"Cancel"按鈕)的callback末尾加上uiresume(handles.figure1)轴踱,注意是主gui的窗口handles.figure1,不要將delete命令放在這些callback中症脂;
3.在子GUI的OutputFcn中設(shè)置要傳遞出去的參數(shù),如varargout{1} = handles.out1淫僻;varargout{2}= handles.out2;末尾添加delete(handles.figure1); 結(jié)束程序诱篷。
在GUI的OpenFcn中,如果不加uiwait嘁傀, 程序會直接運(yùn)行到下面,執(zhí)行OutputFcn视粮。也就是說程序一運(yùn)行细办,返回值就確定了,再在其它部分對handles.output作更改也沒有效果了蕾殴。
加上uiwait后笑撞,只有執(zhí)行了uiresume后,才會繼續(xù)執(zhí)行到OutputFcn钓觉,在此之前用戶有充分的時(shí)間設(shè)置返回值茴肥。
通過以上設(shè)置以后,就可以通過 [out1, out2] = subGUI(in1, in2) 的形式調(diào)用該子程序荡灾。
在一個(gè)GUI中調(diào)用另一個(gè)GUI時(shí)瓤狐,主GUI不需要特別的設(shè)置,同調(diào)用普通的函數(shù)一樣批幌。在打開子GUI界面的同時(shí)础锐,主程序還可以響應(yīng)其它的控件。不需要擔(dān)心子GUI的返回值被傳錯(cuò)了地方荧缘。
三皆警、userdata數(shù)據(jù)
直接通過對象的userdata屬性進(jìn)行各個(gè)callback之間的數(shù)據(jù)存取操作,主要適用于gui內(nèi)截粗。首先必須將數(shù)據(jù)存儲到一個(gè)特定的對象中信姓,假設(shè)對象的句柄值為ui_handle,需要存儲的值為value,則輸入以下程序即可:
set('ui_handle','UserData',Value);
此時(shí)鸵隧,value數(shù)據(jù)就存在句柄值為ui_handle的對象內(nèi),在執(zhí)行的過程中若要取回變量可以通過以下方式在任意callback中獲取該數(shù)據(jù)值 :
value=get(''ui_handle,'UserData');
雖然使用這種方法簡單 意推,但是每個(gè)對象僅能存取一個(gè)變量值豆瘫,因此當(dāng)同一對象存儲兩次變量時(shí) ,先前的變量值就會被覆蓋掉左痢,因此都用UserData存儲簡單與單一的數(shù)據(jù)靡羡。如下面有兩個(gè)gui函數(shù), myloadfn加載mydata.mat文件俊性,該文件內(nèi)存儲XYData變量略步,其值為m*2的繪圖矩陣,加載后將該變量值存儲到 當(dāng)前的窗口的UserData屬性中定页。另一個(gè)myplotfcn函數(shù)則是用以獲取該UserData屬性中存取的繪圖數(shù)據(jù)趟薄,然后繪圖。代碼如下:
function myloadfcn
load mydata;
set(gcbf,'UserData',XYdata)
function myplotfcn
XYdata=get(gcbf,'UserData');
x=XYData(:,1);
y=XYData(:,2);
plot(x,y);
userdata的缺點(diǎn)就是一個(gè)句柄只能放一個(gè)Userdata典徊。
四杭煎、GUI數(shù)據(jù)(handles)
結(jié)合handles和guidata函數(shù),適用于gui內(nèi)卒落,如果你在pushbutton1中得到一個(gè)變量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對象中费坊。這樣不必?fù)?dān)心在一個(gè)pushbutton的callback中存儲的變量在其他對象中無法提取倒槐。
data = guidata(object_handle);獲取當(dāng)前object_handle的handles數(shù)據(jù),最后一次guidata(object_handle,data)保存的數(shù)據(jù)附井。
一個(gè)簡單的GUI給大家說明一下讨越,建一個(gè)GUI, 包含兩個(gè)按鈕永毅,一個(gè)坐標(biāo)系谎痢,一個(gè)用來畫y=sin(x),一個(gè)用來畫y=cos(x);
eg:在GUI的OpeningFcn函數(shù)中寫:
x=0:.1:2*pi;
y1=sin(x);
y2=cos(x);
handles.x=x;
handles.y1=y1;
handles.y2=y2;
guidata(hObject,handles);%注意,在OpeningFcn函數(shù)中這句是本身存在的卷雕,若在其它函數(shù)中节猿,務(wù)必加上這句
在pushbutton1_Callback函數(shù)中寫
x=handles.x;
y1=handles.y1;
plot(x,y1)
在pushbutton2_Callback函數(shù)中寫
x=handles.x;
y2=handles.y2;
plot(x,y2)
五、Application數(shù)據(jù)
應(yīng)用setappdata\getappdata與rmappdata函數(shù),適用于gui間和gui內(nèi)滨嘱。使用上面三個(gè)函數(shù)最有彈性處理數(shù)據(jù)的傳送問題峰鄙,與UserData的方式相類似,但是克服UserData的缺點(diǎn)太雨,使一個(gè)對象能存取多個(gè)變量值吟榴。
(1)getappdata函數(shù)
value=getappdata(h,name)
(2)setappdata函數(shù)
setappdata(h,name,value)
(3)rmappdata函數(shù)
rmappdata(h,name)
首先在matlab命令窗口輸入magic(3)數(shù)據(jù),因此當(dāng)前的工作空間就存儲了magic(3)這組數(shù)據(jù)了囊扳,然后建立一個(gè)按鈕來獲取并顯示magic(3)數(shù)據(jù)吩翻。
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
當(dāng)在主、子gui內(nèi)調(diào)用時(shí)锥咸,可以如下設(shè)置
fig1調(diào)用fig2時(shí)狭瞎,使用fig2指令來打開fig2,
在fig2的m文件中,在回調(diào)函數(shù)中用setappdata(fig1,'A',A);實(shí)現(xiàn)返回fig1搏予,并將參數(shù)A傳遞給fig1
然后在fig1的使用A的地方添加A=getappdata(fig1熊锭,‘A’)。
但這種方式的一個(gè)問題就是每調(diào)用一次雪侥,fig1的數(shù)據(jù)就得初始化一次碗殷,這是因?yàn)閟etappdata(fig1,'A',A)中出現(xiàn)了fig1,調(diào)用一次setappdata就得運(yùn)行一次fig1的緣故速缨,解決方案就是把setappdata(fig1,'A',A)改為setappdata(0,'A',A)锌妻,這樣把A讀入matlabworkspace,相當(dāng)于一個(gè)全局變量了旬牲,但當(dāng)然比直接用global定義全局變量好仿粹!
同樣的例子:
eg:在GUI的OpeningFcn函數(shù)中寫:
x=0:.1:2*pi;
y1=sin(x);
y2=cos(x);
setappdata(handles.figure1,'x',x)%在figure1下創(chuàng)建’x’,包含數(shù)據(jù)x,也可以放在其它句柄下,如setappdata(handles.pushbutton1,'x',x)引谜,不過一般放在figure1下牍陌,記起來方便……
setappdata(handles.figure1,'y1',y1)
setappdata(handles.figure1,'y2',y2)
在pushbutton1_Callback函數(shù)中寫
x=getappdata(handles.figure1,'x');%提取擎浴,當(dāng)然用get了……
y1=getappdata(handles.figure1,'y1');
plot(x,y1)
在pushbutton1_Callback函數(shù)中寫
x=getappdata(handles.figure1,'x');
y2=getappdata(handles.figure1,'y2');
plot(x,y2)
六员咽、跨空間計(jì)算evalin和賦值assignin
適用于gui間和gui內(nèi)
Assignin函數(shù)基本語法
assignin(ws, 'var',val)
其中'base' or 'caller',分別表示基本工作空間和調(diào)用函數(shù)(callerfunction)工作空間贮预,
Assinin函數(shù)將值val指定給工作空間ws中的變量var贝室,若變量var不存在,則創(chuàng)建一個(gè)變量var仿吞。
從一個(gè)函數(shù)function向MATLAB工作空間中輸入數(shù)據(jù)滑频;
在一個(gè)函數(shù)function內(nèi)部,需要改變一個(gè)在callerfunction函數(shù)工作空間中定義的變量唤冈,例如函數(shù)形參列表中的變量峡迷。
例子:
%向基本工作空間中傳輸數(shù)據(jù)變量
Functionassignin_test1
prompt = {'Enterimage name:','Enter colormap name:'};
title = 'Imagedisplay - 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函數(shù)基本語法
evalin(ws,expression)
[a1, a2, a3, ...] = evalin(ws, expression)
在特定的工作空間執(zhí)行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函數(shù)中的變量為expression的語句夯辖,而不能是subfunction
該函數(shù)不可嵌套使用琉预,evalin('caller','evalin(''caller'', ''x'')')是錯(cuò)誤的
例子:
如果在figure1中有個(gè)變量a1
則傳入時(shí)assignin('base','a1',data) %data是workplace中的變量
在figure2傳出時(shí)a2=evalin('base','data'); %a2是figure2中的變量
七、將數(shù)據(jù)保存到文件蒿褂,需要時(shí)讀取
運(yùn)用save和load(importdata)傳遞參數(shù)圆米,適用于gui間和gui內(nèi)。將某變量x的值先存到磁盤啄栓,用的時(shí)候在調(diào)用娄帖。格式如下:save('.mat','x');用的時(shí)候就用load('.mat'),但這樣只是把x讀到了matlabworkspace谴供,不會用顯示块茁,你還要再去查看這個(gè)變量名,然后才能用,建議使用p=importdata('*.mat'),p是一個(gè)結(jié)構(gòu)體桂肌,可以隨意使用了数焊。當(dāng)然,這種方式涉及到磁盤讀寫崎场,速度當(dāng)然會有影響的佩耳,一般情況不用,通常用在保存以及導(dǎo)入某個(gè)變量時(shí)谭跨!
八干厚、帶參數(shù)調(diào)用GUI的M文件
這個(gè)相信大家都很熟悉了,適用于gui間和gui內(nèi)螃宙。
總結(jié)幾點(diǎn):
① 如果變量數(shù)據(jù)量很大蛮瞄,需要占用大量內(nèi)存,不要將變量存儲為handles的變量谆扎,因?yàn)槊總€(gè)控件每次調(diào)用callback function都會使用handles挂捅,增加不必要的內(nèi)存開銷。若改變量存取不頻繁堂湖,可以考慮UserData數(shù)據(jù)或者Application數(shù)據(jù)闲先;若存取比較頻繁,建議使用Global變量和Application結(jié)構(gòu)體无蜂,這里的Application要定義為setappdata(0,'var',val)以及getappdata(0,'var',val)伺糠。
② 對于GUI界面之間的數(shù)據(jù)傳遞,可以考慮以下幾種方法:
方法1:采用global函數(shù)斥季。
可以采用這種方法共享數(shù)據(jù)训桶;
方法2:采用findobj和findall函數(shù)查找對象句柄
findall(0, 'Type','figure', 'Tag', 'figure1')
查找標(biāo)簽為figure1的窗口,無論該窗口是否隱藏。
方法3:采用handles結(jié)構(gòu)舵揭。
假設(shè)我們在窗口1的Opening函數(shù)中慰照,采用函數(shù)創(chuàng)建了一個(gè)子窗口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的任何回調(diào)函數(shù)中,直接訪問子窗口2的任意控件琉朽,可以在上述語句后緊跟著寫下如下語句:
handles.btn1 =h_btn1;
handles.btn2 =h_btn2;
handles.btn3 =h_btn3;
最后毒租,需要一個(gè)guidata語句。當(dāng)然箱叁,Opening函數(shù)最后有g(shù)uidata語句墅垮,所以不用自己添加。
方法4:將要共享的數(shù)據(jù)使用save函數(shù)存入mat文件耕漱;或者使用文件I/O函數(shù)算色,存入文本文件中。