標籤:
轉載自 落落輕塵
[Fig檔案方式,即使用菜單File->New->GUI來設計介面]
首先值得注意的是,在低版本matlab上製作的含GUI的m檔案一般不能在高版本的matlab上面運行,但是從7.0版開始改進了一點,我試過6.5版的含GUI的m檔案可以在7.0版上運行,但如果在7.0版上面修改過.fig檔案,那麼就不能回到6.5版上運行了(顯示一堆錯誤,我沒看懂,不知道能否通過修改使之重新可在6.5版上運行,呵呵),而在7.0版上製作的含GUI的m檔案就完全不能放到6.5版上運行了(也是同樣的錯誤)。這可能是因為matlab各版本在GUI上改動較大,所以都不支援向下相容。也許相容性差是使用GUI編寫程式的最大麻煩。
其次,說說使用GUI的好處。不知道是否承襲了VC orBCB的習慣,我比較喜歡編寫完程式後按快速鍵運行(此時會自動儲存m檔案),但是,對於程式有輸入參數的時候,如果不採用GUI方式,這顯然是行不通的――當然了,可以在commandwindow按“向上”鍵然後重新改寫你想要的參數。對於一些較大型的程式,正因為我比較偏向於按F5運行程式,所以我會選擇使用GUI方式。不過GUI方式的好處就遠不止於此了,它可以把幾個功能相關的模組集中起來,使得不需要重新關閉、運行就能得到不同的結果,便於比較;可以減少figure滿天飛的現象,這在matlab中尤為明顯;便於互動式地觀看不同的資料,例如在我處理的fMRI問題中,希望觀看每個三維點對應的時間序列,這時候需要提供互動選擇……不過,儘管GUI有很多好處,但是其缺點也是有的,除了上面提到的相容性(移植性)以外,要管理、維護一個GUI介面也是比較麻煩的,相信有其他語言的介面設計經驗的朋友也知道這點。
再者,對GUI問題,說說我的一點經驗吧。其實,matlab已經在這方面改進了不少,從控制項的增加和教程的學習都可以看出來。例如6.5版本是沒有Panel和ButtonGroup這兩個控制項的,在2006a版本中就新增了這兩個控制項(這個好像7.0版就有了,不確定);教程方面,也使用了最為直觀的視頻教學方式,建議新手看看Creatinga GUI with GUIDE 和Creating Graphical UserInterfaces兩節。所以,操作上的細節我就不多講了,自己摸索一下就ok了。至於編程時最為關鍵的參數傳遞問題,可以參考本論壇或者模擬論壇上面的“函數結構與參數傳遞”一文,作者整理得較完整,不過有點難懂。這裡我簡單說一下吧:
[轉cwit]關於參數傳遞的方法:
1. 在記憶體中提取:①採用function的varargin和varargout傳送,②存在handle的ApplicationData中,③儲存在handles裡面。當然還有其他方法;
2. 存在硬碟上,採用save和load;
3. 用全域變數,最次的辦法,有時卻是最好的辦法;
我想,對於這裡處理的GUI問題,一般不會用到save和load命令(要從mat檔案讀取資料初始化或者把資料存放區到mat檔案中例外),“function的varargin和varargout傳送”的方法也不較少使用(因為對於控制項的回呼函數,matlab規定了輸入參數為“hObject,eventdata, handles,varargin”,且一般沒有傳回值,所以不同於自訂的函數),所以剩下的方法就只有三種了:
1.存在handle的ApplicationData中――利用setappdata函數將資料儲存在對象的“ApplicationData”屬性中,利用getappdata函數從對象的“ApplicationData”屬性中提取資料,如果沒有定義,就為空白。例如,假設figure的tag屬性是figure1,則setappdata(handles.figure1,’A’,A)就可以把變數A存放到figure1的“ApplicationData”屬性中,名字為A,而B=getappdata(handles.figure1,’A’)就可以把figure1的“ApplicationData”屬性中名字為A的變數賦給B。setappdata和getappdata操作的對象,最好為figure_handle,便於管理和擴充。Matlab的進階編程和對象控制,將大量使用這兩個函數[轉自cwit];
2.儲存在handles裡面――首先,這是訪問控制項的常用方法,注意到Tag是唯一標識控制項的屬性,也就說,如果一個控制項的Tag屬性是a,那麼,在fig對應的m檔案中,只要含有“handles”作為其輸入參數的函數中,就可以使用handles.a對該控制項進行訪問。既然控制代碼(相當於其他語言中的指標)已經拿到手了,就任由“宰割”了(例如設定屬性、存取資料等就比較容易了);其次,可以利用這種方法把自訂的變數儲存在handles裡面進行存取,這在matlab協助的Creatinga GUI with GUIDE一節中有具體介紹,不多說;
3.用全域變數的方法――這是我進行參數傳遞的常用方法,使用方法是:在兩個函數體(當然可以是多個了,這裡是主函數和子函數的意思)中使用前加入語句“globalA”,其中A是多個函數需要傳遞的變數名,多個變數用空格格開,句末不需要加分號。這種方法由於存放在硬碟上,存取速度會減慢,但是如果變數個數不多、或者對該變數引用的函數不多,可以考慮用此辦法(我尚未能領會cwit兄所說“最次的辦法,有時卻是最好的辦法”之含義)。
至於其他有關GUI命令、控制項屬性和圖形屬性可以參考matlab的協助,或者參考“GUI命令大全”、《精通GUI圖形介面編程》(這兩個本論壇有)、“Matlab圖形映像屬性”、“GUI.rtf”(這兩個參見附件,後者下載後手動修改一下尾碼名)。實際上,用得比較多的控制項屬性不外乎以下幾種(高手例外):
Visible屬性,例如axes、edit、button等,格式:set(handles.***,‘Visible’, ‘on’); 或者set(handles.***, ‘Visible’,‘off’);
String屬性,例如edit、text等,格式:str=get(handles.***,‘String’)或set(handles.***,’String’,str);
Enable屬性,例如edit、button、text等,格式:set(handles.***,‘Enable’, ‘on’);或者set(handles.***, ‘Enable’, ‘off’);
Value屬性,例如radio button、checkbox等,格式:a=get(handles.***, ‘Value’)或set(handles.***,’Value’,1);或set(handles.***,’Value’,0);
留意一下響應函數的注釋部分,有時候會得到提示的。例如,我的matlab 2007a 中,在設計介面上增加了 listbox 控制項後,m 檔案的對應回呼函數處顯示如下:
% --- Executes on selectionchange in listbox1.
functionlistbox1_Callback(hObject, eventdata, handles)
% hObject handle to listbox1(see GCBO)
% eventdata reserved - to bedefined in a future version of MATLAB
% handles structure withhandles and user data (see GUIDATA)
% Hints: contents =get(hObject,‘String‘) returns listbox1 contents as cell array ——這是該控制項基本用法的一點提示
%contents{get(hObject,‘Value‘)} returns selected item from listbox1—— 這是該控制項基本用法的一點提示
最後,介紹一下我在使用的過程中發現的一些問題或者技巧(真的只有一點點而已,希望以後可以不斷補充拉,這些技巧對m檔案方式的GUI也適用):
1.當控制項位置有重疊時,直接放置方式與程式描繪方式不相容。直接放置方式是指在GUI設計視窗中放置axes控制項,程式描繪方式是指在程式中利用plot、subplot函數作圖。經本人測試,在同一個fig檔案中,先使用程式描繪方式把圖形plot出來(此時直接放置的axes控制項為不可見狀態),後欲再把直接放置的axes控制項重新設定為可見狀態時,如果通過這兩種方式控制的axes位置有重疊,那麼放置的axes控制項控制代碼會莫名其妙消失,變成無效控制代碼,即出現Invalidhandle的錯誤(儘管其handle是有值的)。所以,在交替採用這兩種方式的時候,其位置不能發生重疊。――其根本原因應該是第5點所說的
2.有多個axes控制項時,可以用axes(handles.haxis)來選擇切換,這個方法比plot(x,y,’parent’,haxis)更加靈活,應該不算原創(因為在精通GUI一書上有介紹),但是在我讀此書之前就一直使用到現在。具體來說,在fig檔案方式的GUI中,假設你的axes控制項的tag屬性值為hA,則在畫圖前使用axes(handles.hA);就可以指定在這個axes上面作圖;在m檔案方式的GUI中,假設你是通過hA=axes(...);建立這個控制項的,那麼使用plot(x,y,‘parent‘,hA);語句就可以指定在這個axes上面作圖。其他控制項也類似,以Edit 控制項為例,首先給 edit1 增加一個Tag屬性,即:H_edit1=……‘Tag‘,‘edit1‘……; ,然後使用set(findobj(‘Tag‘,‘edit1‘),‘string‘,‘1234‘); 便可。
3.設定對象透明屬性的alpha(.5)語句會影響其他對象的可見度設定,也就是說,當fig視窗中某個對象(我的例子是axes對象)使用了alpha語句設定其透明度之後,就不能對fig視窗中其他對象設定Visible屬性為off了,此時off值是失效的,解決辦法是對其他對象設定Enable屬性來近似達到需要的效果。
【以下轉自newseee】
4.設計GUI,mailab版本越高越好,bug少,功能全面。比如uigeifile(還是uigetdir?記不清了。)在R12中就不支援。初始化時,加上版本判斷。
5.axes物件不能放到其它物件之上!
6.axes沒有Callback,但是可以在上面放一張圖(image),可以有Callback。
7. windows和linux下GUI會看起來不一樣,為了相容,字型改成default,Unit的單位要用characters。
8.動態圖形是迴圈畫出來的。開啟figure的DoubleBuffer到on,可以避免圖形的閃爍。記得要用axes(h)。因為每plot一次,座標系就重新整理了。人不能踩進同一條河裡。
9. matlab r13有bug,linux下submenu不能動態更新,能刪除,不能添加。我的解決辦法是在callback中把GUI都關閉,然後更新submenu(在主函數中 function varargout = untitled_OutputFcn(hObject, eventdata,handles) 這一行下面添加,此時視窗還沒有建立。),然後重新開啟gui。
[m檔案方式設計介面]
這種方式的入門最好根據自己的需要,下載一些具體例子作為參考(例如震動或模擬等論壇上一些牛人發的文章),結合手頭上的任務(或者興趣)來學。與上面的fig檔案方式相比,這種方式可以誇不同的matlab平台使用,不必考慮相容性問題(當然了,要滿足一個前提:要該平台的文法或命令支援才行,例如&&在6.5版本無效,也就是說,如果你的程式是用7.0以上版本的matlab編寫,但是希望程式可以在6.5版本中運行,那麼在編寫條件判斷語句時只能使用&),但是換來的代價是所有控制項的建立和布局、事件的響應函數入口等等都需要自己用代碼來實現,因此比fig檔案方式要困難一點。當然,你可以下載別人寫好的介面來做修改。一般來說,如果是用來內部調試、測試的話,用fig方式比較好,但是如果用來向外發布的話,還是m檔案方式比較通用一點(雖然可以打包來換取多一點的通用性,但你總不能帶著100多m的MCRInstaller檔案到處走吧?2006b是100多m,2006a好像是60多m,記不清了)。
1.建立控制項時,直接採用“‘屬性名稱‘,‘屬性值‘”的方式(如‘CallBack‘,‘delete(gcbf);clearall;abc()‘)將導致程式不能調試到達其響應函數(貌似調用自己時不能,調用其他函數可以,沒有完全測試,呵呵),解決方案是使用訊息傳遞,即‘CallBack’, @Action,然後寫:
FunctionAction(hObject,eventdata,handles)
delete(gcbf);
clear all;
abc();
2.實現進度條有兩種方式(可能不止):waitbar方式和uicontrol方式,後者可以使用兩個edit控制項,或者使用axes控制項加上line函數產生,但是無論哪種方式,如果每次迴圈都重新整理一下,那麼當迴圈總次數很大時(如幾十萬次),運行速度會減慢,建議每隔一段距離(step)重新整理一次,這樣可以加快運行速度。例如:
if (i - 100*k/N) <=1e-003
waitbar(k/N);
i = i + step;
end
其中i是控制進度條在何處重新整理,k是程式的迴圈變數,N是程式迴圈的總次數。
使用 uicontrol方式實現進度條的樣本:
複製內容到剪貼簿
代碼:figure;
e1 =uicontrol(gcf,‘style‘,‘edit‘,‘BackgroundColor‘,‘w‘,...
‘unit‘,‘normalized‘,‘position‘,[0.35,0.6,0.02,0.25]);
e2 =uicontrol(gcf,‘style‘,‘edit‘,‘BackgroundColor‘,‘r‘,...
‘unit‘,‘normalized‘,‘position‘,[0.3525,0.6,0.015,0.01]);
drawnow;
n = 1000;
ii = 1;
for i = 1:0.01:n
if (ii - 100*i/n) <=1e-003
set(e2,‘position‘,[0.3525,0.6,0.015,0.01+0.24*i/n]);
drawnow;
ii = ii + 1;
end
end【附錄】轉自cwit兄:
m檔案與fig檔案建立figure的十大差異——用代碼寫figure,並不是麻煩。如果你習慣了,或者熟悉了,會發現用代碼實現guide編程,比GUI方便很多,功能也很強大。用m檔案實現guide編程,相比GUI編程有幾大差異:
1.代碼可複用,節省成本;
2.GUI不能靈活建立uimenu,並且不能編輯其所有屬性;
3.GUI還沒有實現建立uitoolbox;
4.GUI不能建立所有axes的子物件;
5.寫介面也有一些演算法,在GUI中無法實現。而用m檔案就可以實現在不同視窗尺寸下給對象以合適的位置;
6.m檔案可以產生非常複雜的介面;
7.採用GUI編程,代碼編譯後依賴於*.fig檔案;
8.m檔案可以實現組件;
9.m檔案建立的對象,可以方便的在handle中存取資料;
10.m檔案可以將建立對象代碼與動作執行代碼很好的結合起來。
【注】關於兩種方式的運行:
對於fig檔案方式:fig檔案記錄的是控制項的布局和屬性等資源資訊,m檔案記錄的是控制項的響應訊息(這是個人理解,更準確的介紹請參閱有關GUI的書籍,我懶得去查了,呵呵),兩者缺一不可。所以,不能通過開啟fig檔案(如菜單中的Open命令)來運行該GUI,這種方式的運行方法有兩種:開啟該GUI對應的m檔案,然後像普通m檔案那樣運行;開啟該GUI的設計介面(菜單操作:FileàNewàGUIàOpenExisting GUI,開啟 fig 檔案。
[轉載] 關於matlab GUI的一點心得