7-4 嚙踝蕭嚙?M 嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙踝蕭嚙?

到現在為止,您應該看過很多以 GUI 為主的 MATLAB 應用程式了吧?(如果還沒有,請趕快試試 xpsound、travel、truss、lorenz 等指令。)本節將簡單介紹如何在指令視窗建立類似的 GUI 設計。(另一個 GUI 的設計方法,則是使用 GUIDE 發展環境,詳見下一章介紹。)

MATLAB 的 uicontrol 是產生 UI (User Interface) 控制物件的主要指令,這些 UI 控制物件包含:

以下是一個產生按鈕(Push Button)的最簡單範例:

Example 1: 07-握把式圖形與GUI設計/uicontrol01.mh = uicontrol; % 產生按鈕 set(h, 'String', '請按我!'); % 在按鈕表面加入文字「請按我!」 cmd = 'fprintf(''有人按我一下喔!\n'');'; % 定義按鈕被按後的反應指令 set(h, 'Callback', cmd); % 設定按鈕的反應指令

在執行上述範例後,MATLAB 會產生一個空白視窗,上面有一個按鈕(如下圖),每次在點選此按鈕後,MATLAB 的指令視窗即會出現「有人按我一下喔!」的文字,請親自試試看!

在上例中,由於 UI 控制物件是圖形物件的孩子,因此若沒有現成的圖形視窗,MATLAB 會新增一圖形視窗來容納 UI 控制物件。此外,所有 UI 控制物件的「反應指令」(Callbacks,亦即按下 UI 控制物件後,MATLAB 執行的指令)都必須以字串來定義,因此若在反應動作中又出現字串(如上例的「有人按我一下喔!」),則必須以兩個「''」(Double Quote)來框住字串。(有關字串的處理,可詳見本書第十章「字元與字串」。) MATLAB 支援的 UI 控制物件可呈現如下:

Example 2: 07-握把式圖形與GUI設計/uicontrol02.mclose all % 關閉所有圖形視窗 uicontrol('style', 'push', 'position', [200 20 80 30]); uicontrol('style', 'slide', 'position', [200 70 80 30]); uicontrol('style', 'radio', 'position', [200 120 80 30]); uicontrol('style', 'frame', 'position', [200 170 80 30]); uicontrol('style', 'check', 'position', [200 220 80 30]); uicontrol('style', 'edit', 'position', [200 270 80 30]); uicontrol('style', 'list', 'position', [200 320 80 30], 'string', '1|2|3|4'); uicontrol('style', 'popup', 'position', [200 370 80 30], 'string', 'one|two|three');

在上述例子中,style 後面所接的字串即代表 UI 控制物件的類別,而 position 後面所接的向量即代表 UI 控制物件在圖形視窗的位置,以 [x, y, width, length] 為例,即代表 UI 控制物件的左下角之座標為 [x, y],長度為 width,高度為 length (均以 Pixel 為單位)。

以下介紹另外一個較複雜的例子,其檔案名稱為 ui01.m,您可在 MATLAB 指令視窗下輸入「ui01」,即可得到一個圖形視窗及相關的 UI 控制物件,如下圖:

Example 3: 07-握把式圖形與GUI設計/ui01.m% 產生新圖形視窗,其左下角之座標為[30, 30], % 長度為300,高度為200(均以Pixel為單位) figure('position', [30 30 300 200]); % 在圖形視窗內產生一個圖軸,其左下角之座標為[0.1, 0.2], % 長度為0.8,高度為0.8(使用標準化的單位,即圖形的左下角為[0, 0], % 長度及高度都是1。) axes('position', [0.1 0.2 0.8 0.8]); % 視窗上的第一個圖形,為三度空間的peaks函數。 pointNum = 20; [xx, yy, zz] = peaks(pointNum); surf(xx, yy, zz); colormap hsv axis tight % 第一個UI控制物件,用以控制背景格線的顯示。 h1 = uicontrol('style', 'checkbox', 'string', 'Grid on', ... 'position', [10, 10, 60, 20], 'value', 1); % 第二個UI控制物件,用以指定X軸及Y軸的格子點數目。 h2 = uicontrol('style', 'edit', 'string', int2str(pointNum), ... 'position', [90, 10, 60, 20]); % 第三個UI控制物件,用以指定顯示曲面所用到的色盤矩陣。 h3 = uicontrol('style', 'popupmenu', ... 'string', 'hsv|hot|cool', ... 'position', [170, 10, 60, 20]); % 第一個UI控制物件的反應指令為「grid」。 set(h1, 'callback', 'grid'); % 第二個UI控制物件的反應指令為「cb2」。 set(h2, 'callback', 'cb2'); % 第三個UI控制物件的反應指令為「cb3」。 set(h3, 'callback', 'cb3');

上述範例可以產生一個圖形視窗,包含三個 UI 控制物件:

您可以隨意點選或改變這些 UI 控制物件,並觀察圖形和背景的變化。

為使讀者瞭解這個例子,我們在原始程式碼中加了很多註解,讓此範例更加簡單易懂。需注意的是,本範例還呼叫了另外兩個腳本檔 cb2.m 和 cb3.m,其中 cb2.m 負責處理格子點的個數,內容如下:

07-握把式圖形與GUI設計/cb2.m% 取得第二個UI控制物件的數值。 pointNum = round(str2num(get(h2, 'string'))); % 若數字太大或太小,則設定為10。 if pointNum <= 1 | pointNum > 100, pointNum = 10; set(h2, 'string', int2str(pointNum)); end % 根據所得的數字,重畫peaks曲面。 [xx, yy, zz] = peaks(pointNum); surf(xx, yy, zz); axis tight; % 根據第一個UI控制物件,決定是否要畫格線。 if get(h1, 'value')==1, grid on; else grid off; end

而 cb3.m 則負責改變色盤矩陣,內容如下:

07-握把式圖形與GUI設計/cb3.m% 根據第三個UI控制物件來決定使用的色盤矩陣。 switch get(h3, 'value') case 1 colormap(hsv); case 2 colormap(hot); case 3 colormap(cool); otherwise disp('Unknown option'); end

在上述的的簡易 UI 程式設計範例中,我們可以發覺有兩個缺點:

  1. 需要使用四個檔案,管理不方便。
  2. 使用的變數都在 MATLAB 基本工作空間中,容易造成變數的相衝及覆蓋。

解決上述問題的一個簡單的方法,是將所有的程式碼集中於一個函式中,並以不同的輸入字串來指示函數所需執行的功能,此種 GUI 程式設計的方法在 MATLAB 的各種 Demo 程式常被用到,特稱為「Switchyard Programming」。以上例來說,以「Switchyard Programming」來產生的等效 M 檔案可顯示如下:

Example 4: 07-握把式圖形與GUI設計/ui02.mfunction ui02(action) % ui02: Example of UI programming using "switchyard programming" % Roger Jang, 20040405 if nargin<1, action='initialize'; end switch(action) case 'initialize' % 圖形視窗及UI控制物件的初始化。 % 產生新圖形視窗,其左下角之座標為[30, 30], % 長度為300,高度為200(均以Pixel為單位) figH = figure('position', [30 30 300 200]); % 在圖形視窗內產生一個圖軸,其左下角之座標為[0.1, 0.2], % 長度為0.8,高度為0.8(使用標準化的單位,即圖形的左下角為[0, 0], % 長度及高度都是1。) axes('position', [0.1 0.2 0.8 0.8]); % 視窗上的第一個圖形,為三度空間的peaks函數。 pointNum = 20; [xx, yy, zz] = peaks(pointNum); surf(xx, yy, zz); colormap hsv axis tight % 第一個UI控制物件,用以控制背景格線的顯示。 h1 = uicontrol('style', 'checkbox', ... 'tag', 'ui4grid', ... 'string', 'Grid on', ... 'position', [10, 10, 60, 20], 'value', 1); % 第二個UI控制物件,用以指定X軸及Y軸的格子點數目。 h2 = uicontrol('style', 'edit', ... 'tag', 'ui4pointNum', ... 'string', int2str(pointNum), ... 'position', [90, 10, 60, 20]); % 第三個UI控制物件,用以指定顯示曲面所用到的調色盤。 h3 = uicontrol('style', 'popupmenu', ... 'tag', 'ui4colorMap', ... 'string', 'hsv|hot|cool', ... 'position', [170, 10, 60, 20]); % 第一個UI控制物件的反應指令為「grid」。 set(h1, 'callback', 'grid'); % 第二個UI控制物件的反應指令為「ui02('setPointNum')」。 set(h2, 'callback', 'ui02(''setPointNum'')'); % 第三個UI控制物件的反應指令為「ui02('setColorMap')」。 set(h3, 'callback', 'ui02(''setColorMap'')'); case 'setPointNum' % 第二個UI控制物件的callback。 % 找出第一及第二個UI控制物件的握把。 h1 = findobj(0, 'tag', 'ui4grid'); h2 = findobj(0, 'tag', 'ui4pointNum'); % 取得第二個UI控制物件的數值。 pointNum = round(str2num(get(h2, 'string'))); % 若數字太大或太小,則設定為10。 if pointNum <= 1 | pointNum > 100, pointNum = 10; set(h2, 'string', int2str(pointNum)); end % 根據所得的數字,重畫peaks曲面。 [xx, yy, zz] = peaks(pointNum); surf(xx, yy, zz); axis tight; % 根據第一個UI控制物件,決定是否要畫格線。 if get(h1, 'value')==1, grid on; else grid off; end case 'setColorMap' % 第三個UI控制物件的callback。 % 找出第三個UI控制物件的握把。 h3 = findobj(0, 'tag', 'ui4colorMap'); % 根據第三個UI控制物件來決定使用的色盤矩陣。 switch get(h3, 'value') case 1 colormap(hsv); case 2 colormap(hot); case 3 colormap(cool); otherwise disp('Unknown option'); end otherwise error('Unknown action string!'); end

上例所產生的 UI 介面和功能,和 ui01.m 完全一樣,但只有用到一個單一檔案,乾淨很多,而且不會發生變數相衝的問題。

另,在上例中,我們為了要能夠找出三個 UI 控制物件的握把,因此特別設定他們個別的「Tag」值,因此若要用到這些 UI 控制物件,可用 findobj 指令來直接來找出他們的握把,非常方便。


MATLAB程式設計:入門篇