MATLAB GUI图形界面 独立回调函数.docx
《MATLAB GUI图形界面 独立回调函数.docx》由会员分享,可在线阅读,更多相关《MATLAB GUI图形界面 独立回调函数.docx(24页珍藏版)》请在冰点文库上搜索。
MATLABGUI图形界面独立回调函数
独立的回调函数
建立GUI函数的一个有效方法是编写独立的回调函数,专门执行一个或多个回调。
函数使用的对象句柄和其它变量可以作为参量传递,必要时回调函数可返回值。
考虑先前的一个例子,建立一个方位角的滑标,以脚本文件来实现。
%setview.mscriptfile
vw=get(gca,'View');
Hc_az=uicontrol(gcf,'Style','slider',...
'Position',[10514020],...
'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',[10254020],...
'String',num2str(get(Hc_az,'Min')));
Hc_max=uicontrol(gcf,'Style','text',...
'Position',[110254020],...
'String',num2str(get(Hc_az,'Max')));
Hc_cur=uicontrol(gcf,'Style','text',...
'Position',[60254020],...
'String',num2str(get(Hc_az,'Value')));
下面是同样的例子。
作为一个函数,采用'Tag'属性来辨别控制框,并使用独立的M文件来执行回调。
funtionsetview()
vw=get(gca,'View');
Hc_az=uicontrol(gcf,'Style','Slider',...
'Position',[10514020],...
'Min',-90,'Max',90,'Value',vw
(1),...
'Tag','Azslider',...
'Callback','svcback');
Hc_min=uicontrol(gcf,'style','text,...
'Position',[10254020],...
'String',num2str(get(Hc_az,'Min')));
Hc_max=uicontrol(gcf,'Style','text',...
'Position',[110254020],...
'String',num2str(get(Hc_az,'Max')));
Hc_cur=uicontrol(gcf,'Style','text',...
'Position',[60254020],...
'Tag','Azcur',...
'String',num2str(get(Hc_az,'Value')));
回调函数本身如下:
functionsvcback()
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或ifelseif语句,可将回调函数装入调用函数内。
通常这样一种函数调用的结构为
functionguifunc(switch)。
其中switch确定执行哪一个函数开关的参量,它可以是字符串'startup','close','sectolor'等等,也可以是代码或数字。
如switch是字符串,则可如下面所示的M文件片段那样将开关编程。
ifnargin<1,switch='startup';end;
if~isstr(switch),error('Invalidargument'),end;
ifstrcmp(switch,'startup'),
elseifstrcmp(switch,'setcolor'),
elseifstrcmp(switch,'close'),
end
如果是代码或字符串,开关也可以相同方式编程。
ifnargin<1,switch=0;end;
ifisstr(switch),error('Invalidargument'),end;
ifswitch==0,
elseifswitch==1,
elseifswitch==2,
end
下面的例子说明了方位角滑标如何可作为单独的函数M文件来实现:
functionsetview(switch)
ifnargin<1,switch='startup';end;
if~isstr(switch),error('Invalidargument.');end;
vw=get(gca,'view');%Thisinformationisneededinbothsections
ifstrcmp(switch,'startup')%Definethecontrolsandtagthem
Hc_az=uicontrol(gcf,'Style','slider',...
'Position',[10514020],...
'Min',-90,'Max',90,'Value'vw
(1),...
'Tag','AZslider',...
'Callback','setview('set')');
Hc_min=uicontrol(gcf,'Style','text',...
'Position',[10254020],...
'String',num2str(get(Hc_az,'Min')));
Hc_max=uicontrol(gcf,'Style','text',...
'Position',[110254020],...
'String',num2str(get(Hc_az,'Max')));
Hc_cur=uicontrol(gcf,'Style','text',...
'Position',[60254020],...
'Tag','AZcur',...
'string',num2str(get(Hc_az,'Value')));
elseifstrcmp(switch,'set')%ExecutetheCallback
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函数的所有部分都可用,全局变量是在函数的公共区说明,因此整个函数以及所有对函数的递归调用都可以利用全局变量,下面的例子说明如何利用全局变量将方位角滑标编程。
functionsetview(switch)
globalHC_AZHC_CUR%Createglobalvariables
ifnargin<1,switch='startup';end;
if~isstr(switch,error('Invalidargument.');end;
vw=get(gca,'View');%Thisinformationisneededinbothsections
ifstrcmp(switch,'startup')%Definethecontrols
Hc_AZ=uicontrol(gcf,'style','slider',...
'Position',[10514020],...
'Min',-90,'Max',90,'Value',vw
(1),...
'Callback','setview('set')');
Hc_min=uicontrol(gcf,'Style','text',...
'Position',[10254020],...
'String',num2str(get(Hc-AZ,'Min',)));
HcMax=uicontrol(gcf,'Style','text',...
'Position',[110254020],...
'String',num2str(get(Hc_AZ,'Max')));
Hc_cur=uicontrol(gcf,'style','text',...
'Position',[60254020],...
'String',num2str(get(HC_AZ,'Value')));
elseifstrcmp(switch,'set')%ExecutetheCallback
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去获取,故回调代码比较简单,全局变量通常使一个函数更有效。
不过有一点要注意,尽管一个变量在函数内说明为全局的,变量并不能自动地在命令窗口工作空间中利用,也不能在回调字符串内使用。
但是,如果用户发命令:
>>clearglobal,则所有全局变量则都被破坏,包括在函数内定义的那些变量。
当单独的一个图形或有限个变量要被所有的回调(函数)利用时,全局变量使用和递归性函数调用都是有效的技术。
对于包含多个图形的更复杂的函数,或用独立对象回调函数实现的情况,'UserData'属性更合适。
另外,只要可获得对象句柄,对象'UserData'的属性值在命令窗口工作空间中是存在的。
用户数据属性
同属性'Tag'一样,'UserData'属性可在函数之间或递归函数的不同部分之间传递信息。
如果需要多个变量,这些变量可以在一个容易辨识的对象的属性'UsetData'中传递。
如前面所述,对与句柄图形对象在一起的单个数据矩阵'UserData'提供了存储。
下面的程序利用了当前图形的'UserData'属性来实现方位角滑标。
functionsetview(switch)
ifnargin<1,switch='startup';end;
vw=get(gca,'View');%Thisinformationisneededinbothsections
ifstrcmp(switch,'startup')%Definethecontrols
Hc_az=uicontrol(gcf,'Style','slider',...
'Position',[10514020],...
'Min',-90,'Max',90,'Value',vw
(1),...
'Callback','setview("set")');
Hc_min=uicontrol(gcf,'Style','text',...
'Position',[10254020],...
'String',num2str(get(Hc_az,'Min')));
Hc_max=uicontrol(gcf,'Style','text',...
'Position',[110254020],...
'String',num2str(get(Hc_az,'Max')));
Hc_cur=uicontrol(gcf,'Style','text',...
'Position',[60254020],...
'String',num2str(get(Hc_az,'Value')));
set(gcf,'UserData',[Hc_azHc_cur]);%Storetheobjecthandles
elseifstrcmp(switch,'set')%ExecutetheCallback
Hc_all=get(gcf,'UserData');%retrievetheobjecthandles
Hc_az=Hc_all
(1);
Hc_cur=Hc_all
(2);
str=num2str(get(Hc_az,'Value'));
newview=[get(Hc_az,'Value')vw
(2)];
set(Hc_cur,'String',str)
set(gca,'View',newview)
end
句柄存储于'startup'末端,图形属性'UserData'中,在回调被执行前对此进行检索。
如果有许多回调,如下面的程序片断所示,'UserData'只需检索一次。
ifstrcmp(switch,'startup')%Definethecontrolsandtagthem
%
set(gcf,'UserData',[Hc_azHc_cur]);%Storetheobjecthandles
else%ThismustbeaCallback
Hc_all=get(gcf,'UserData');%Retrievetheobjecthandles
Hc_az=Hc_all
(1);
Hc_cur=Hc_all
(2);
ifstrcmp(switch,'set')
%
elseifstrcmp(switch,'close')
%
%
end
end
调试GUIM文件
回调字符串在命令窗口工作空间中计算并执行的,这个情况对编写和调试GUI函数和脚本文件有某种隐含意义。
回调字符串可以很复杂,尤其是在脚本文件中,这为句法错提供了许多机会,记录单引号、逗号、括号是令人头痛的事。
如果出现了句法错误,MATLAB给出提示;只要对象的'Callback'属性值是一个真正的文本串,MATLAB就认可了。
只有当对象被激活并将回调字符串传给eval时,才检查回调字符串内部的句法错误。
这样让用户定义回调字符串,它涉及还未曾定义过的对象句柄和变量,这使编写相互参照的程序变得更容易,但是每个回调函数必须分别测试,保证回调字符串是合法的MATLAB命令,并且回调字符中涉及的所有变量可在命令窗口工作空间中是可利用的。
将回调象函数M文件一样编程或象GUI函数本身内的开关一样编程,就可以不运行整个GUI函数而对各个回调进行改变或测试。
因为回调字符串是在命令窗工作空间中而不在函数本身内计算,在函数与各回调之间传递数据就变得十分复杂。
例如,函数test包含如下程序:
functiontest()
tpos1=[20205020];
tpos2=[20805020];
Hc_text=uicontrol('Style','text','String','Hello','Position',tposl);
Hc-push=uicontrol('Style','push','String','MoveText',...
'Position',[155010025],...
'Callback','set(Hc-text,"Position",tpos2)');
所有语句都是有效的MATLAB命令,且回调字符串也对有效的MATLAB语句估值。
文本对象和按钮出现在图形上,但当激活按钮键时,MATLAB就出示错误。
>>test
>>
?
?
?
UndefinedfunctiionorvariableHc_text.
?
?
?
ErrorwhileevaluatingCallbackstring.
如果test是个脚本文件,就不会出现这样问题,因为所有变量可在命令窗口工作空间中使用,因为test是个函数,Hc_text和tpos2在命令窗口工作空间中均未定义,回调字符串执行失败。
一种解决方法是使用各个字符串元素来建立回调,该字符串元素由数值而非变量建立,例如,改变回调字符串如下:
'Callback',['set9',...
sprintf('&.15g',Hc_text),...
',''Position'',',...
sprintf('[%.15g%.15g%.15g%.15g]',tpos2),...
')']);
建立了包括Hc_text对象句柄值的一个字符串,该值变换成具有15位精度的字符串,而tpos2变量转换成矩阵表示的字符串。
在函数内计算sprinf语句,然后将所得的字符串用在回调中。
在命令窗工作空间执行的实际命令如下所示
eval('set(87.000244140625,''Position'',[208050100])')
将一个对象句柄转换为字符串,必须保持全精度。
上例中的变换,使用了小数点后15位的数字的精度。
在MATLAB中句柄对象转换应使用这样的精度。
要记住,变量随后的变换不会改变回调字符串。
在前面的例子中,在控制框定义之后改变tpos2的值,就无效果。
例如,在函数结尾处加命令
tpos2=[202005020]
就无效果,因为在tpos2重新定义之前,通过计算tpos2,回调字符串已经建立。
21.6指针和鼠标按钮事件
GUI函数利用鼠标箭头的位置和鼠标按钮的状态来控制MATLAB行动。
本节讨论指针、对象位置和鼠标按钮动作之间的交互,以及MATLAB如何响应变化或事件,诸如:
揿下按钮、松开按钮或箭头移动等。
回调属性,选择区域和堆积顺序
所有句柄图形对象具有一个至今还未阐述过的'ButtonDownFcn'属性,本节就进行讨论。
uimenu和uicontrol均有'CallBack'属性,这个属性是菜单和控制框的应用核心。
另外,图形有'KeyPressFcn'和'ResizeFcn'属性以及'WindowButtonUpFc