Matlab 版 (精华区)

发信人: bage (最近比较烦), 信区: Matlab
标  题: 精通Matlab(十六
发信站: 哈工大紫丁香 (Sun Feb  4 14:04:28 2001), 转信

发信人: Security (淼水), 信区: MathTools       
发信站: BBS 水木清华站 (Tue Jun  1 22:42:08 1999)


独立的回调函数

建立GUI函数的一个有效方法是编写独立的回调函数,专门执行一个或多个回调。函数使用的对象句柄和其它变量可以作为参量传递,必要时回调函数可返回值。
考虑先前的一个例子,建立一个方位角的滑标,以脚本文件来实现。

% setview.m script file

vw=get(gca, ' View ' );

Hc_az=uicontrol(gcf, ' Style ' , ' slider ' ,...
             ' Position ' ,[10  5  140  20],...
             ' Min ' ,-90, ' Max ' ,90, ' Value ' ,vw(1),...
             ' Callback ' ,[...
                   ' set(Hc_cur, ' String ' ,num2str(get(Hc_az, ' Value ' ))), ' ...
                   ' set(gca, ' View ' ,[get(Hc_az, ' Value ' ) vw(2)]) ' ]);
Hc_min=uicontrol(gcf, ' style ' , ' text ' ,...
               ' Position ' ,[10  25  40  20],...
               ' String ' ,num2str(get(Hc_az, ' Min ' )));

Hc_max=uicontrol(gcf, ' Style ' , ' text ' ,...
               ' Position ' ,[110  25  40  20],...
               ' String ' ,num2str(get(Hc_az, ' Max ' )));

Hc_cur=uicontrol(gcf, ' Style ' , ' text ' ,...
               ' Position ' ,[60  25  40  20],...
               ' String ' ,num2str(get(Hc_az, ' Value ' )));

下面是同样的例子。作为一个函数,采用 ' Tag ' 属性来辨别控制框,并使用独立的M文件来执行回调。

                  funtion setview( )

                  vw=get(gca, ' View ' );

                  Hc_az=uicontrol(gcf, ' Style ' , ' Slider ' ,...
                                ' Position ' ,[10  5  140  20],...
                                ' Min ' ,-90, ' Max ' ,90, ' Value ' ,vw(1),...
                                ' Tag ' , ' Azslider ' ,...
                                ' Callback ' , ' svcback ' );

                  Hc_min=uicontrol(gcf, ' style ' , ' text,...
                                ' Position ' ,[10  25  40  20],...
                                ' String ' ,num2str(get(Hc_az, ' Min ' )));

                   Hc_max=uicontrol(gcf, ' Style ' , ' text ' ,...
                               ' Position ' ,[110  25  40  20],...
                               ' String ' ,num2str(get(Hc_az, ' Max ' )));

                   Hc_cur=uicontrol(gcf, ' Style ' , ' text ' ,...
                              ' Position ' ,[60  25  40  20],...
                              ' Tag ' , ' Azcur ' ,...
                              ' String ' ,num2str(get(Hc_az, ' Value ' )));

回调函数本身如下:

function svcback( )

vw = get(gca, ' View ' );

Hc_az = findobj(gcf, ' Tag ' , ' AZslider ' );
Hc_cur = findobj(gcf, ' Tag ' , ' AZcur ' );

str = num2str(get(Hc_az, ' Value ' ));
newview =[get(Hc_az, ' Value ' ) vw(2)];
set(Hc_cur, ' String ' ,str)
set(gca, ' View ' ,newview)

上面的例子并不节省很多代码,但却得到了用函数而不用脚本文件的优点:回调函数可以利用临时变量,而不使命令窗口工作空间拥挤;不需要eval所需的引号和字符串;在回调函数中命令的句法变得十分简单。使用独立回调函数技术,越复杂的回调(函数)越简单。
独立回调函数的缺点是:需要很大数目的M文件以实现一个含有若干控制框和菜单项的GUI函数,所有这些M文件必须在MATLAB路径中可得,且每一个文件又必须要有一个不同的文件名。在对文件名大小有限制且对大小写不敏感的平台上,如MS-windows,文件冲突的机会就增加了。而且回调
函数只能被GUI函数调用而不能被用户调用。

递归函数调用

利用单独的M文件并递归地调用该文件,既可以避免多个M文件的复杂性,又可以利用函数的优点。使用开关 switches或if  elseif语句,可将回调函数装入调用函数内。通常这样一种函数调用的结构为

                function guifunc(switch)。

其中switch确定执行哪一个函数开关的参量,它可以是字符串 ' startup ' , ' close ' , ' sectolor ' 等等,也可以是代码或数字。如switch是字符串,则可如下面所示的M文件片段那样将开关编程。

if nargin < 1, switch =  ' startup ' ; end;
if ~isstr(switch), error( ' Invalid argument ' ), end;
if strcmp(switch, ' startup ' ),
    <statement to create controls or menus>
    <statements to implement the GUI function>
elseif strcmp(switch, ' setcolor ' ),
    <statements to perform the Callback associated with setcolor>
elseif strcmp(switch, ' close ' ),
    <statements to perform the Callback associated with close>
end

如果是代码或字符串,开关也可以相同方式编程。

if nargin < 1, switch = 0; end;
if isstr(switch), error( ' Invalid argument ' ), end;
if switch = = 0,
     <statements to create controls or menus>
     <statements to implement the GUI function>
elseif switch = =1,
     <statements to perform the Callback associated with setcolor>
elseif switch ==2,
     <statements to perform the Callback associated with close>
end

下面的例子说明了方位角滑标如何可作为单独的函数M文件来实现:

function setview(switch)

if nargin < 1, switch =  ' startup ' ; end;
if ~isstr(switch), error( ' Invalid argument. ' ); end;

vw = get(gca, ' view ' ); % This information is needed in both sections

if strcmp(switch, ' startup ' ) % Define the controls and tag them

    Hc_az = uicontrol(gcf, ' Style ' , ' slider ' ,...
             ' Position ' ,[10 5 140 20],...
             ' Min ' ,-90, ' Max ' ,90, ' Value ' vw(1),...
             ' Tag ' , ' AZslider ' ,...
             ' Callback ' , ' setview( ' set ' ) ' );

    Hc_min=uicontrol(gcf, ' Style ' , ' text ' ,...
              ' Position ' ,[10 25 40 20],...
              ' String ' ,num2str(get(Hc_az, ' Min ' )));
    Hc_max = uicontrol(gcf, ' Style ' , ' text ' ,...
              ' Position ' ,[110 25 40 20],...
              ' String ' ,num2str(get(Hc_az, ' Max ' )));

    Hc_cur =uicontrol(gcf, ' Style ' , ' text ' ,...
             ' Position ' ,[60 25 40 20],...
             ' Tag ' , ' AZcur ' ,...
             ' string ' ,num2str(get(Hc_az, ' Value ' )));

elseif strcmp(switch, ' set ' ) % Execute the Callback 

      Hc_az=findobj(gcf, ' Tag ' , ' AZslider ' );
      Hc_cur-findobj(gcf, ' Tag ' , ' AZcur ' );

      str = num2str(get(Hc_az, ' Value ' ));
      newview - [get(Hc_az, ' Value ' ) vw(2)];

      set(Hc_cur, ' String ' , str)
      set(gca, ' View ' ,newview)
end

上述的两个例子均设置了 ' tag ' 属性,利用该属性和函数findobj寻找回调函数所需对象的句柄。另外两种方法将在下章描述。

全局变量

全局变量可用在函数中,使某些变量对GUI函数的所有部分都可用,全局变量是在函数的公共区说明,因此整个函数以及所有对函数的递归调用都可以利用全局变量,下面的例子说明如何利用全局变量将方位角滑标编程。

function setview(switch)

global HC_AZ HC_CUR % Create global variables

if nargin < 1, switch = ' startup ' ; end;
if ~isstr(switch, error( ' Invalid argument. ' ); end;

vw = get (gca, ' View ' ); % This information is needed in both sections
if strcmp(switch, ' startup ' ) % Define the controls

    Hc_AZ=uicontrol(gcf, ' style ' , ' slider ' ,...
              ' Position ' ,[10 5 140 20],...
              ' Min ' ,-90, ' Max ' ,90, ' Value ' ,vw(1),...
              ' Callback ' , ' setview( ' set ' ) ' );

    Hc_min=uicontrol(gcf, ' Style ' , ' text ' ,...
              ' Position ' ,[10 25 40 20],...
              ' String ' ,num2str(get(Hc-AZ, ' Min ' ,)));

    HcMax=uicontrol(gcf, ' Style ' , ' text ' ,...
              ' Position ' ,[110 25 40 20],...
              ' String ' ,num2str(get(Hc_AZ, ' Max ' )));

    Hc_cur=uicontrol(gcf, ' style ' , ' text ' ,...
              ' Position ' ,[60 25 40 20],...
              ' String ' ,num2str(get(HC_AZ, ' Value ' )));

elseif strcmp(switch, ' set ' ) % Execute the Callback

      str=num2str(get(HC_AZ, ' Value ' ));
      newview= [get(HC_AZ, ' Value ' ) vw(2)];

      set(HC_CUR, ' String ' ,str)
      set(gca, ' View ' ,newview)

end

全局变量遵循MATLAB的规定,变量名要大写。不需要 ' tag ' 属性,且不使用它,另外因为对象句柄存在的,不需要用函数findobj去获取,故回调代码比较简单,全局变量通常使一个函数更有效。
不过有一点要注意,尽管一个变量在函数内说明为全局的,变量并不能自动地在命令窗口工作空间中利用,也不能在回调字符串内使用。但是,如果用户发命令:>>  clear global,则所有全局变量则都被破坏,包括在函数内定义的那些变量。
当单独的一个图形或有限个变量要被所有的回调(函数)利用时,全局变量使用和递归性函数调用都是有效的技术。对于包含多个图形的更复杂的函数,或用独立对象回调函数实现的情况, ' UserData ' 属性更合适。另外,只要可获得对象句柄,对象 ' UserData ' 
的属性值在命令窗口工作空间中是存在的。

用户数据属性

同属性 ' Tag ' 一样, ' UserData ' 属性可在函数之间或递归函数的不同部分之间传递信息。如果需要多个变量,这些变量可以在一个容易辨识的对象的属性 ' UsetData ' 中传递。如前面所述, 对与句柄图形对象在一起的单个数据矩阵' UserData ' 
提供了存储。下面的程序利用了当前图形的 ' UserData ' 属性来实现方位角滑标。

function setview(switch)

if nargin < 1, switch =  ' startup ' ; end;

vw = get(gca, ' View ' ); % This information is needed in both sections

if strcmp(switch, ' startup ' ) % Define the controls

     Hc_az = uicontrol(gcf, ' Style ' , ' slider ' ,...
              ' Position ' ,[10 5 140 20],...
              ' Min ' ,-90, ' Max ' ,90, ' Value ' ,vw(1),...
              ' Callb的特殊形式的drawnow。

Drawnow

Drawnow命令迫使MATLAB更新屏幕,只要MATLAB回到命令提示,或执行drawnow,figure,getframe或pause命令,屏幕就更新。drawnow的特殊形式draunow( ' discard ' )使事件队列中所有事件的放弃。在回调中将drawnow( ' discard ' 
)包含在一个特殊命令之前,就含有清除事件队列的效果,防止刷新事件,以及回调事件中断回调。

21.8  M文件举例

精通MATLAB工具箱中一些函数阐明了上面所讨论的若干技术。第一个例子mmview3d应用全局变量和递归函数调用,把方位角和仰角滑标加到图形中。函数中有大量的对象,但函数很直观。因为mmview3d文件相当得长,故分段表示。第一段定义了函数标号,帮助文本和全局变量。

function mmview3d(cmd)
%  MMVIE3D GUI controllled Azimuth and Elevation adustment.
%  for adjusting azimuth and elevation using the mouse.
%
%  The  ' Revert '  pushbutton reverts to the original view.

%  The  ' cmd '  argument executes the callbacks.

%  Copyright (c) 1996 by Prentice-Hall, Inc.

global Hc_acur Hc_esli Hc_ecur CVIEW

第二段处理初始用户的调用,建立必要的uicontrol对象并把回调定义为递归函数调用。

if  nargin==0

%------------------------------------------------------------------
%  Assign a handle to the current figure window.
%  Get the current view for slider initial values.
%  Use normalized uicontrol units rather than the default  ' pixels ' .
%------------------------------------------------------------------

Hf_fig=gcf;
CVIEW=get(gca, ' View ' );
if abs(CVIEW(1))>180, CVIEW(1)=CVIEW(1)-(360*sign(CVIEW(1)));end
set(Hf_fig, ' DefaultUicontrolUnits ' , ' normalized ' );

%-------------------------------------------------------------------
%  Define azimuth and elevation sliders.
%  The position is in normalized units  (0-1).
%  Maximum, minimum, and initial values are set.
%--------------------------------------------------------------------

Hc_asli=uicontrol(Hf_fig, ' style ' , ' slider ' ,...
 ' position ' ,[.09  .02  .3  .05],...
 ' min ' ,-180, ' max ' ,180, ' value ' , CVIEW(1),...
 ' callback ' , ' mmview3d(991) ' );

Hc_esli=uicontrol(Hf_fig, ' style ' , ' slider ' ,...
 ' position;,[.92  .5  .04  .42],...
 ' min ' ,-90, ' max ' ,90, ' val ' ,CVIEW(2),...
 ' callback ' , ' mmview3d(992) ' );

%--------------------------------------------------------------------
%  Place the text boxes showing the minimum and maximum values at the 
%  ends of each slider, These are text displays, and cannot be edited.
%---------------------------------------------------------------------

uicontrol(Hf_fig, ' style ' , ' text ' ,...
 ' pos ' ,[.02  .02  .07  .05],...
 ' string ' ,num2str(get(Hc_asli, ' min ' )));

uicontrol(Hf_fig, ' style ' , ' text ' ,...
 ' pos ' ,[.39  .02  .07  .05],...
 ' string ' ,num2str(get(Hc_esli, ' min ' )));

uicontrol(Hf_fig, ' style ' , ' text ' ,...
 ' pos ' ,[.915  .92  .05  .05],...
 ' string ' ,num2str(get(Hc_esli, ' max ' )));

%--------------------------------------------------------------------
% Place labels for each slider
%--------------------------------------------------------------------

uicontrol(Hf_fig, ' style ' , ' text ' ,...
 ' pos ' ,[9.095  .08  .15  .05],...
 ' string ' , ' Azimuth ' );

uicontrol(Hf_fig, ' style ' , ' text ' ,...
 ' pos ' ,[.885  .39  .11  .05],...
 ' string ' , ' Elevation ' );

%-------------------------------------------------sition
     MMCXY_OUT=cp(1,1:2);
     xystr=sprintf( ' [%.3g] ' ,MMCXY_OUT);
     Hu=get(gcf, ' Userdata ' );
     set(Hu, ' String ' xystr)  %  put x-y coordinaates in text box

elseif strcmp(arg,  ' end ' )  %  mouse click occurred, clean things up
     Hu=get(gcf,  ' Userdata ' );
     set(Hu, ' visible ' , ' off ' )  %  make sure text box disappears
     delete(Hu)
     set(gcf, ' Pointer ' , ' arrow ' ,...
              ' WindowButtonMotionFcn ' , '  ' ,...
              ' WindowButtonDownFcn ' , '  ' ,...
              ' Userdata ' ,[])
end

第一次被调用时,mmcxy建立文本uicontrol,改变指针形状,设定 ' WindowButtonDownFcn ' 和 ' WindowButtonMotionFcn ' 的回调,然后等待按键或先揿按钮。若有键揿下,就调用清除(cleanup)程序,清除文本框,恢复鼠标指针,清除图形回调及 ' UserData ' 
属性。若点击鼠标按钮, ' WindowButtonDownFcn ' 回调就处理清除任务。在等待时,图形中鼠标指针的移动会触发 ' WindowButtonMotionFcn ' 回调,更新uicontrol中文本串。
精通MATLAB工具箱中的另一个函数是mmtext,它利用 ' WindowButtonDownFcn '   , ' WindowButtonUpFcn ' 和 ' WindowButtonMotionFcn ' 回调的另一个短小函数以安置和拖曳文本。

function mmtext(arg)
%  MMTEXT place and drag text with mouse
%  MMTEXT waits for a mouse click on a text object
%  in the current figure then allows it to be dragged
%  while the mouse button remains down.
%  MMTEXT( ' whatever ' ) places the string  ' whatever '  on 
%  the current axes and allows it to be dragged.
%
%  MMTEXT becomes inactive after the move is complete or
%  no text object is selected.

%  Copyright (c) 1996 by Prentice-Hall, Inc.

if -nargin, arg=0;end

if isstr(arg) % user entered text to be placed
    Ht=text( ' units ' , ' normalized ' ,...
         ' Position ' ,[.05  .05],...
         ' String ' ,arg,...
         ' HorizontalAlignment ' , ' left ' ,...
         ' VerticalAlignment ' , ' baseline ' );
    mmtext(0)  %  call mmtext again to drag it

elseif arg==0 %  initial call, select text for dragging
    Hf=mmgcf;
    if isempty(Hf),  error( ' No Figure Available. ' ), end
    set(Hf, ' BackingStore ' , ' off ' ,...
         ' WindowButtonDownFcn ' , ' mmtext(1) ' )
    figure(Hf)  %  bring figure forward

elseif arg==1  &  strcmp(get(gco, ' Type ' ), ' text ' )  % text object selected
 

--

--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: bage.bbs@smth.org]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:209.118毫秒