颜色控制
uimenu对象可设置两个颜色属性。 ' BackGroundColor ' 属性控制填充菜单背景的颜色。缺省值是浅灰。另一颜色属性为 ' ForeGroundColor ' ,它确定菜单项文本的颜色,缺省值是黑色。
颜色属性同样能很好地用于顶层菜单条和下拉菜单。颜色可以用来表示状态信息或简单加上菜单的特 色。例如,挑选线段颜色。在子菜单中,各菜单项的背景可以填充合适的色彩。
>> Hm_green=uimenu(Hm_color, ' Label ' , ' Green ' , ' BackgroundColor ' , ' g ' ,...
' Callback ' , ' set(Hl_line, ' Color ' , ' g ' ) ' );
菜单项去能
改变对象uimenu的 ' Enable ' 值或 ' Visible ' 属性可使菜单项暂时去能。 ' Enable ' 属性通常设为 ' on ' 。当 ' Enable ' 属性 ' 设为 ' off ' 时,标志字符串变灰,菜单项去能。在这种状态下,菜单项保持可见但不能被选择。此属性可用来将不恰当的菜单选择去能。
下面的例子(mmenu4.m)说明了用两个菜单项和 ' Enable ' 属性来设定坐标轴的 ' Box ' 属性的另一种方法。
>> Hm_top = uimenu( ' Label ' ,Example ' );
>> Hm_boxon = uimenu(Hm_top, ' Label ' , ' Set Box On ' ... ' CallBack ' ,[...
' set(gca, ' ' Box ' ' , ' ' on ' ' ), ' ,...
' set(Hm_boxon, ' ' Enable ' ' , ' ' off ' ' ), ' ,...
' set(Hm_boxoff, ' ' Enable ' ' , ' ' Enable ' ' , ' ' on ' ' ) ' ]);
>> Hm_boxoff = uimenu(Hm_top, ' Label ' ,Set Box Off ' ,... ' Enable ' , ' off ' ,... ' CallBack ' ,[...
' set(gca, ' ' Box ' ' , ' ' off ' ' ), ' ,...
' set(Hm_boxon, ' ' Enable ' ' , ' ' on ' ' ), ' ,...
' set(Hm_boxoff, ' ' Enable ' ' , ' ' off ' ' ) ' ]);
设定' Visible ' 属性为 ' off ', 可将菜单项完全隐藏。菜单项象是从屏幕中消失,而其它菜单项改变了在显示器上的位置以填补由当前不可见菜单造成的空隙。然而,不可见的菜单仍然存在,而且uimenu 对象的 ' Position ' 属性值也不改变。当属性 ' Visible ' 又重新设为 ' on ' 时,菜单项重新出现在正常的位置。
这个性质可以用来暂时地撤消一个菜单。下面的例子(mmenu5.m)建立了两个顶层菜单和两个菜单项。
>> Hm_control = uimenu( ' Label ' , ' Control ' );
>> Hm_extra = uimenu( ' Label ' , ' Extra ' );
>> Hm_limit = uimenu(Hm_control, ' Label ' , ' Limited Menus ' ,...
' CallBack ' , ' set(Hm_extra, ' ' Viseble ' ' , ' ' off ' ' ) ' );
>> Hm_full = uimenu(Hm_control, ' Label ' , ' Full Menus ' ,... ' CallBack ' , ' set(Hm_extra, ' ' Visible ' ' , ' ' on ' ' ) ' );
当选择了Limited Menus项时,Extra菜单就从菜单条中消失。当选择了Full Menus项时,Extra菜单又重新显示在原来的位置的菜单条上。
回调属性
' Callback ' 属性值是一个MATLAB字符串,MATLAB将它传给函数eval并在命令窗口工作空间执行。它对于函数M文件有重要的隐含意义,我们将在本章后面继续讨论这一属性。
因为 ' Callback ' 属性必须是字符串,所以在字符号内多重MATLAB命令、后续行以及字符串都会使必需的句法变得十分复杂。如果有不止一个命令要执行,命令间必须适当地分隔开来。例如,
>>uimenu( ' Label ' , ' Test ' , ' CallBack ' , ' grid on; set(gca, ' ' Box ' ' , ' ' on ' ' ) ' );
把一个字符串传给eval,使命令
>> grid on; set(gca, ' Box ' , ' on ' )
在命令窗口工作空间中执行。这是合法的句法,因为命令用逗号或分号隔开,多重命令可输入到同一命令行中。在定义回调函数时,也遵循MATLAB规定,即在已引用的字符串内,用两个单引号来表示单引号。
字符串可以串接起来生成一个合法MATLAB字符串,只要把它们括在方括号中。
>>uimenu( ' Label ' , ' Test ' , ' CallBack ' ,[ ' grid on, ' , ' set(gca, ' ' Box ' ' , ' ' on ' ' ) ' ]);
注意字符串 ' grid on ' 含有所需的逗号以分隔两个命令。
如果使用了续行号,上述命令可写为
>>uimenu( ' Label ' , ' Test ' ,...
' CallBack ' ,[...
' grid on, ' ,...
' set(gca, ' ' Box ' ' , ' ' on ' ' ) ' ...
]);
上例中命令行被分隔,每行的末尾加上了三个句号表示命令的继续。注意到上列单行的所有元素都被保留,包括字符串分隔命令的逗号。在 ' grid on, …' 行中最后引号后的逗号是可选的;下一行开始的空格起相同的作用。欲了解详情,请参阅前面关于建立行向量的章节。
如果引号、逗号和括号不正确输入,MATLAB将给出警告;但在复杂回调字符串中很难寻找错误的。为了使错误最少,对包含MATLAB语句的回调字符串请记住以下的一些规则:
把整个回调字符串括在方括号中,不要忘记最后的右括号' )' 。
把各语句括上单引号。
已引用的字符串内,要用双引号。如: ' quoted ' : ' a ' ' quoted ' ' string ' ; ' Quote ' ' a ' ' ' quoted ' ' ' string ' ' now '。在引号后要用逗号或空格结尾。
除了最后一句,各语句在引号内要以逗号或分号结尾;在引号后要用逗号或空格结尾。
有后续行的各行要以三个句号(...)结尾。
前面的例子之一mmenu4.m是所涉及的回调字符串句法的很好说明。
>> Hm_top = unimenu(Label ' , ' Example ' );
>> HM_boxon = uimenu(Hm_top,...
' Label ' , ' Set ' Box on ' ,...
' CallBack ' ,[...
' set(gca,''Box'',''on''), ' ,...
set(Hm_boxon,''Enable'',''off''), ' ,...
set(Hm_boxoff,''Enable'',''on'') ' ];
>> Hm_boxoff = uimenu(Hm_top,...
' Label ' , ' Set Box off ' ,...
' Enable ' , ' off ' ' , ' ,...
' CallBack ' ,[...
' set(gca,''Box'',''off'', ' ,...
' set(Hm_boxon,''Enable'',''on''), ' ,...
' set(Hm_boxoff''Enable'',''off'') ' ];
上例中还引出了关于回调函数另一个重点,在变量Hm_boxoff定义之前,在回调串中用Hm_boxoff替代Hm_boxon。因为回调串只是一个字符串,MATLAB 不会给出警告,而且仅在uimenu被激活并将字符串传给eval时才由MATLAB执行。它隐含有函数M文件的设计和测试,这将在本章后面讨论。
M文件的举例
下例将演示一组简单菜单的生成。该例子包含在精通MATLAB工具箱的函数M文件mmenus中。正如下面所示的那样,这个函数文件被分隔成了若干块,以便于讨论函数的各个方面。
首先,定义一个函数并在当前的图形中用顶层Line菜单建立菜单条,该菜单分别含有三个子菜单:Line Style,Line Width,Line Color。
function mmenus()
% MMENUS Simple menu example.
% MMENUS uses waitforbuttonpress and gco in callback strings
% to let the user make a menu selection and then select an object
% by clicking on it with the mouse. The callback strings then use
% the set function to apply the property value to the selected
% object.
% Copyright (c) 1996 by Prentice-Hall,Inc.
Hm_line = uimenu(gcf, ' label ' . ' Line ' );
Hm_lstyle = uimenu(Hm_line, ' label ' , ' Line Style ' );
Hm_lwidth = uimenu(Hm_line, ' label ' , ' Line width ' );
Hm_lcolor = uimenu(Hm_ ' label, ' Line Color ' );
其次,使用waitforbuttonpress和gco得到当前对象的句柄,确认它为一个线对象,并采用适当的 ' Linestyle ' 值。注意这些菜单项句柄以后不再使用,所以它们不必保存。
uimenu(Hm_lstyle, ' Label ' ,Solid ' ,...
' CallBack ' ,( ' waitforbuttonpress; ' ,...
' if get(gco,''type'')==''line'', ' ...
' set(gco,''LineStyle'',''-''), ' ...
' end ' ]);
uimenu(Hm_lstyle, ' Label ' ,Dotted ' ,...
' Callback ' ,[ ' waitforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''LineStyle'','','':''), ' ...
' end ' ]);
uimenu(Hm_lstyle, ' Label ' ,Dashed ' ,...
' Callback ' ,[ ' waitforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''LineStyle'',''-'':''), ' ...
' end ' ]);
uimenu(Hm_lstyle, ' Label ' ,DashDot ' ,...
' Callback ' ,[ ' waitforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''LineStyle'',''-'':''), ' ...
' end ' ]);
现在,对Line width子菜单项也做同样的操作:
uimenu(Hm_lwitdth, ' Label ' , ' Default ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''LineWidth'',0.5), ' ,...
' end ' ]);
uimenu(Hm_lwitdth, ' Label ' , ' Thick ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''LineWidth'',2.0), ' ,...
' end ' ]);
uimenu(Hm_lwitdth, ' Label ' , ' Thicker ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''LineWidth'',3.0), ' ,...
' end ' ]);
uimenu(Hm_lwitdth, ' Label ' , ' Thickest ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''LineWidth'',4.0), ' ,...
' end ' ]);
对Line Color子菜单项也做同样的操作。将菜单项背景加色并在合适时改变文本颜色。
uimenu(Hm_lcolor, ' Label ' , ' yellow ' ,...
' BackgroundColor ' , ' y ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''color'', ' ''y''), ' ,...
' end ' ]);
uimenu(Hm_lcolor, ' Label ' , ' Magenta ' ,...
' BackgroundColor ' , ' m ' , ' ForegroundColor ' , ' w ' ...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''color'', ' ''m''), ' ,...
' end ' ]);
uimenu(Hm_lcolor, ' Label ' , ' yan ' ,...
' BackgroundColor ' , ' c ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''color'', ' ''c''), ' ,...
' end ' ]);
uimenu(Hm_lcolor, ' Label ' , ' Red ' ,...
' BackgroundColor ' , ' r ' , ' ForegroundColor ' , ' w ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''color'', ' ''r''), ' ,...
' end ' ]);
uimenu(Hm_lcolor, ' Label ' , ' Green ' ,...
' BackgroundColor ' , ' g ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''color'', ' ''g''), ' ,...
' end ' ]);
uimenu(Hm_lcolor, ' Label ' , ' Blue ' ,...
' BackgroundColor ' , ' b ' , ' ForegroundColor ' , ' w ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''color'', ' ''b''), ' ,...
' end ' ]);
uimenu(Hm_lcolor, ' Label ' , ' White ' ,...
' BackgroundColor ' , ' w ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''color'', ' ''w''), ' ,...
' end ' ]);
uimenu(Hm_lcolor, ' Label ' , ' Black ' ,...
' BackgroundColor ' , ' k ' , ' ForegroundColor ' , ' w ' ,...
' CallBack ' ,[ ' witforbuttonpress; ' ,...
' if get(gco,''Type'')==''line'', ' ,...
' set(gco ,''color'', ' ''k''), ' ,...
' end ' ]);
为使这一函数更完全,可用同样方法增加另外的菜单以改变坐标轴、曲面、补片和图形的属性。例如,下面加上了一个Color映象以改变图形颜色的映象。
Hm_cmap=uimenu(gcf, ' Label ' , ' Color Map ' );
uimenu(Hm_cmap, ' Label ' , ' Lighter ' , ' CallBack ' , ' brighten(.3) ' );
uimenu(Hm_cmap, ' Label ' , ' Darker ' , ' CallBack ' , ' brighten(-.3) ' );
uimenu(Hm_cmap, ' Label ' , ' Default ' , ' CallBack ' , ' colormap(''default'') ' );
uimenu(Hm_cmap, ' Label ' , ' Gray ' , ' CallBack ' , ' colormap(gray) ' );
uimenu(Hm_cmap, ' Label ' , ' Hot ' , ' CallBack ' , ' colormap(hot) ' );
uimenu(Hm_cmap, ' Label ' , ' Cool ' , ' CallBack ' , ' colormap(cool) ' );
uimenu(Hm_cmap, ' Label ' , ' Bone ' , ' CallBack ' , ' colormap(bone) ' );
uimenu(Hm_cmap, ' Label ' , ' Copper ' , ' CallBack ' , ' colormap(copper) ' );
uimenu(Hm_cmap, ' Label ' , ' Pink ' , ' CallBack ' , ' colormap(pink) ' );
uimenu(Hm_cmap, ' Label ' , ' Prism ' , ' CallBack ' , ' colormap(prism) ' );
uimenu(Hm_cmap, ' Label ' , ' Jet ' , ' CallBack ' , ' colormap(jet) ' );
uimenu(Hm_cmap, ' Label ' , ' Flag ' , ' CallBack ' , ' colormap(flag) ' );
uimenu(Hm_cmap, ' Label ' , ' HSV ' , ' CallBack ' , ' colormap(hsvflag) ' );
最后,加上含有两个菜单项的Quit菜单。其中,Close Figure关闭图形;Remove Menus让图形打开但删除用户的顶层菜单及所有它的子菜单。drawnow命令立即删除菜单。
Hm_quit=uimenu(GCF, ' lABEL ' , ' quit ' );
uimenu(Hm_quit, ' Label ' , ' Close Figure ' , ' CallBack ' , ' close;return ' );
uimenu(Hm_quit, ' Label ' , ' Remove Menu ' ,...
' Callback ' ,[...
' delete(findobj(gcf,''Type,''uimenu'',''parent'',gcf)), ' ,...
' drawnow ' ]);
精通MATLAB工具箱中有许多采用这种技术的函数和其它建立有用的基于对象工具的函数。其中许多函数将在本章后面详细讨论。
21.4 控制框
在各计算机平台上,窗口系统都采用控制框和菜单,让用户进行某些操作,或设置选项或属性。控制框是图形对象,如图标、文本框和滚动条,它和菜单一起使用以建立用户图形界面,称之为窗口系统和计算机窗口管理器。
MATLAB控制框,又称uicontrol,与窗口管理器所用的函数十分相似。它们是图形对象,可以放置在MATLAB的图形窗中的任何位置并用鼠标激活。MATLAB的 uicontrol包括按钮、滑标、文本框及 弹出式菜单。
由MATLAB生成的uicontrol对象在Macintosh、MS-Windows 和X Window系统平台上,有稍微不同的外观,因为窗口系统表达图形对象的方法是不同的。但是,功能本质是相同的,所以相同的MATLAB编码将生成同样的对象,它在不同平台完成同样的功能。
Uicontrol由函数uicontrol生成。常用句法与前面所讨论的uimenu相同。
>>Hc_1=uicontrol(Hf_fig, ' PropertyName ' ,PropertyValue,...)
其中,Hc_1是由函数uicontrol生成uicontrol对象的句柄。通过设定uicontrol对象的属性值' PropertyName' , ' PropertyValue ' 定义了uicontrol的属性;Hf_fig是父对象的句柄,它必须是图形。如果图形对象句柄省略,就用当前的图形。
建立不同类型的控制框
MATLAB共有八种不同类型或型式的控制框。它们均用函数uicontrol建立。属性 ' Style ' 决定了所建控制框的类型。 ' Callback ' 属性值是当控制框激活时,传给eval在命令窗口空间执行的MATLAB字符串。
下面将分别对八种uicontrol对象进行讨论,并用示例说明。uicontrol对象的属性更为透彻的讨论和应用中更为完整的例子将在以后给出。
按钮键
按钮键,又称命令按钮或只叫按钮,是小的长方形屏幕对象,常常在对象本身标有文本。将鼠标指针移动至对象,来选择按钮键uicontrol,单击鼠标按钮,执行由回调字符串所定义的动作。按钮键的 ' Style ' 属性值是 ' pushbutton ' 。
按钮键典型地用于执行一个动作而不是改变状态或设定属性。下面的例子(mmctl1.m)建立标志为Close的按钮键uicontrol。当激活该按钮时,close关闭当前的图形。以象素为单位的' Position ' 属性定义按钮键的大小和位置,这是缺省的 ' Units ' 属性值。属性 ' String ' 定义了按钮的标志。
>>Hc_close=uicontrol(gcff, ' Style ' , ' push ' ,...
' Position ' ,[10 10 100 25],...
' String ' ,Close ' ,...
' CallBack ' , ' close);
无线按钮
无线按钮,又称选择按钮或切换按钮,它由一个标志并和标志文本的左端一个小圆圈或小菱形所形成。当选择时,圆圈或菱形被填充,且 ' Value ' 属性值设为1;若未被选择,指示符被清除, ' Value ' 属性值设为0。无线按钮键 ' style ' 的属性值是 ' radiobutton ' 。
无线按钮典型地用在一组互斥的选项中选择一项。为了确保互斥性,各无线按钮uicontrol的回调字符串必须不选组中其它项,将它们各项的 ' Value ' 设为0。然而,这只是一个约定,如果需要,无线按钮可与检查框交换使用。
下面的例子(mmctl2.m)建立了两个互斥选项的无线按钮,它将坐标轴 ' Box ' 属性开或关闭。
>> Hc_boxon = uicontrol(gcf, ' Style ' , ' radio ' ,...
' Position ' ,[20 45 100 20],...
' String ' , ' Set box on
' Value ' ,0,... ' ,...
' CallBack ' ,[...
' set(Hc_boxon ' ,''Value'',1 ' ...
' set(Hc_boxoff ' ,''Value'',0 ' ...
' set(gca,''Box'',''on'') ' ]);
>> Hc_boxoff = uicontrol(gcf, ' Style ' , ' radio ' ,...
' Position ' ,[20 20 100 20],...
' String ' , ' Set box off
' Value ' ,1,... ' ,...
' CallBack
' CallBack ' ,[...
' set(Hc_boxon ' ,''Value'',0 ' ...
' set(Hc_boxoff ' ,''Value'',1 ' ...
' set(gca,''Box'',''off'') ' ]);
检查框
检查框,又称切换按钮,它由具有标志并在标志的左边的一个小方框所组成。激活时,uicontrol在检查和清除状态之间切换。在检查状态时,根据平台的不同,方框被填充,或在框内含x, ' Value ' 属性值设为1。若为清除状态,则方框变空, ' Value ' 属性值设为0。
检查框典型地用于表明选项的状态或属性。通常检查框是独立的对象,如果需要,检查框可与无线按钮交换使用。
下面的例子(mmctl3.m)建立了一个检查框uicontrol, 设置坐标轴 ' Box ' 属性,当此检查框被激活时,测试 ' Value ' 属性以确定检查框是否以往被检查或清除过,并适当设置 ' Box ' 属性。
>> Hc_box = uicontrol(gcf, ' Style ' , ' check ' ,...
' Position ' ,[100 50 100 20],...
' String ' , ' Axis Box ' ,...
' CallBack ' ,[...
' if get(Hc_box,''Value'')==1, ' ...
' set(gca,''Box'',''on''), ' ...
' else, ' ...
' (gca,''Box'',''off'', ' ...
' end ' ]);
静态文本框
静态文本框是仅仅显示一个文本字符串的uicontrol,该字符串是由 ' string ' 属性所确定的。静态文本框的 ' Style ' 属性值是 ' text ' 。静态文本框典型地用于显示标志、用户信息及当前值。
静态文本框之所以称之为 ' 静态 ' ,是因为用户不能动态地修改所显示的文本。文本只能通过改变 ' String ' 属性来更改。
在X Window系统中,静态文本框可只含有一行文字;如文本框太短,不能容纳文本串,则只显示部分文字。然而在Macintosh和MS-Window平台,长于文本框的文本串将字串起来,即在可能的地方,用词间分割的虚线显示多行。
下面的例子(mmct14.m)建立了含有MATLAB版本号的文本框。
>> Hc_ver = uimenu(gcf, ' Style ' , ' text ' ,...
' Position ' ,[10 10 150 20],...
' String ' ,[ ' MATLAB Version ' ,version]);
与其它的文本对象,如:坐标标题和坐标标志不同,函数的编著者对用在uicontrol文本串的字体不明显地控制。用在uicontrol文本串的字体和命令窗口的字体一致,可由用户设定。
X window系统的用户在激活MATLAB时,可以给出命令行的参量,如
matlab -fn 9x14bold
该命令在命令窗和uicontrol文本串中使用9x14bold字体。Mocintosh对命令窗和uicontrol文本串使用相同的字体,但字体可以由用户在命令窗的Options菜单中用Text Style项来设定。PC用户具有选项,可从命令窗口的Options菜单的Command Window Font项来设置命令窗口字体,并从同一菜单中的Uicontrol Font项,为uincontrol文本串设置不同的字体。我们希望未来的MATLAB版本会在uimenu和uicontrol文本串中增加控制字体的属性。
可编辑文本框
编辑文本框,象静态文本框一样,在屏幕上显示字符。但与静态文本框不同,可编辑文本框允许用户动态地编辑或重新安排文本串,就象使用文本编辑器或文字处理器一样。在 ' String ' 属性中有该信息。可编辑文本框uicontrol的 ' Style ' 属性值是 ' edit ' 。可编辑文本框典型地用在让用户输入文本串或特定值。
可编辑文本框可包含一行或多行文本。单行可编辑文本框只接受一行输入,而多行可编辑文本框可接受行以上的输入。单行可编辑文本框的输入以Return键结尾。在X window和MS-Window系统中,多行文本输入以Control-Return键结尾,而在Macintosh中用Command-Return键。
下面的例子(mmct15.m)建立了静态文本标志和一个单行可编辑文本框。用户可以在文本框中输入颜色映象名,而后回调字符串把它放到在图中。
>>Hc_label=uicontrol(gcf, ' Style ' , ' text ' ,...
' Position ' [10 10 70 20],...
' String ' , ' Colormap: ' );
>>Hc_map =uicontrol(gcf, ' Style ' , ' edit ' ,...
' Position ' [80 10 60 20],...
' String ' , ' hsv ' ,...
' callback ' , ' coloormap(eval(get(Hc_map,''String''))) ' );
通过把 ' Max ' 属性及 ' Min ' 属性设置成数值,诸如Max-Min>1,建立多行可编辑文本框。Max属性不指定最大的行数。多行可编辑文本框可具有无限多行。
一个多行可编辑文本框表示如下:
>>Hc_multi=uicontrol(gcf, ' Style ' , ' edit ' ,...
' Position ' ,[20 50 75 75],...
' String ' , ' Line 1 |Line 2|Line 3 ' ...
' Max ' ,2);
多行字符串被指定为单个引号的字符串,用垂直条字符 ' | ' 指明在何处分行。
滑标
滑标,或称滚动条,包括三个独立的部分,分别是滚动槽、或长方条区域,代表有效对象值范围;滚动槽内的指示器,代表滑标当前值;以及在槽的两端的箭头。滑标uicontrol的 ' Style ' 属性值是 ' slider ' 。
滑标典型地用于从几个值域范围中选定一个。滑标值有三种方式设定。方法一:鼠标指针指向指示器,移动指示器。拖动鼠标时,要按住鼠标按钮,当指示器位于期望位置后松开鼠标。方法二:当指针处于槽中但在指示器的一侧时,单击鼠标按钮,指示器按该侧方向移动距离约等于整个值域范围的10% ;方法三:在滑标不论哪端单击鼠标箭头;指示器沿着箭头的方向移动大约为滑标范围的1% 。滑标通常与所用文本uicontrol对象一起显示标志、当前滑标值及值域范围。
下面的例子(mmct16.m)实现了一个滑标,可以用于设置视点方位角。用了三个文本框分别指示滑标的最大值,最小值和当前值。
>> 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'',num22str(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 ' )));
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 ' )));
滑标的 ' Position ' 属性包含熟悉的向量[left bottom width height],其单位由 ' Units ' 属性设定。滑标的方向取决于宽与高之比。如果width > height就画水平方向的滑标,如果width < height就画垂直方向的滑标。仅在X-Window系统平台中,如果滑标的一个方向的大小比另一个方向小4倍,就不显示。其它操作平台上的滑标均有箭头。
弹出式菜单
弹出式菜单典型地用于向用户提出互斥的一系列选项清单,让用户可以选择。弹出式菜单,不同于前面论述过的下拉式菜单,不受菜单条的限制。弹出式菜单可位于图形窗口内的任何位置。弹出式菜单的 'Style' 属性值是 ' popupmenu ' 。
当关闭时,弹出式菜单以矩形或按钮的形式出现,按钮上含有当前选择的标志,在标志右侧有一个向下的箭头或凸起的小方块来表明uicontrol对象是一个弹出式菜单。当指针处在弹出式uicontrol之上并按下鼠标时,出现其它选项。移动指针到不同的选项,松开鼠标就关闭弹出式菜单,显示新的选项。MS-Windows 和某些X Window系统平台允许用户单击弹出式菜单,打开它,而后单击另一个选项来进行选择。
当选择一个弹出项时, ' Value ' 属性值设置成选择向量所选元素的下标。选项的标志指定为一个字符串,用垂直条 ' | ' 分隔,与指定多行文本的方法一样。下面的例子(mmct17.m)建立了图形颜色的弹出式菜单。回调函数把图形的 ' Color ' 属性值设定为所选值。每种与颜色相关的RGB值存储在弹出控制框的 ' UserDate ' 属性中。所有句柄图形对象的 ' UserData ' 属性仅仅为单独矩阵提供孤立的存储。
>> Hc_fcolor = uicontrol(gcf, ' Style ' , ' popumenu ' ,...
' Position ' ,[20 20 80 20],...
' String ' , ' Black|Red|Yellow|Green|Cyan|Blue|Magenta|White ' ,...
' Value ' ,1,...
UserData ' ,[[0 0 0];...
[1 0 0];...
[1 1 0];...
[0 1 0];...
[0 1 1];...
[0 0 1];...
[1 0 1];...
[1 1 1];...
CallBack ' ,[...
' UD=get(Hc_fcolor, ' ' UserData ' ' ); ' ,...
' set(gcf, ' ' Color ' ' ,UD(get(Hc_fcolor, ' ' Value ' ' ),:)) ' ]);
弹出式菜单的 ' Position ' 属性含有熟悉的向量[left bottom width height],其中宽度与高度决定了弹出对象的大小。在X Window和Macintosh系统中,就是被关闭的弹出式菜单的大小。打开时,菜单展开适合显示屏幕大小所有的选项。在MS-Windows系统中,高度值基本上被忽略,这些平台建立高度足够的弹出式菜单,显示一行文本而不管height的值。
框架
框架uicontrol对象仅是带色彩的矩形区域。框架提供了视觉的分隔性。在这点上,框架与uimenu的 ' Sepatator ' 属性相似。框架典型地用于组成无线按钮或其它uicontrol对象。在其它对象放入框架之前,框架应事先定义。否则,框架可能覆盖控制框使它们不可见。
下面的例子(mmct18.m)建立了一个框架,把两个按钮和一个标志放入其中。
>> Hc_frame = uicontrol(gcf,' Style ', ' frame ' , ' Position ' ,[250 200 95 65]);
>> Hc_pb1 = uicontrol(gcf, ' Style ' , ' pudhbutton ' ,...
' Position ' ,[255 205 40 40], ' String ' , ' OK ' );
>> Hc_pb2 = uicontrol(gcf, ' Style ' , ' pushbutton ' ,...
' Position ' ,[300 205 40 40], ' String ' , ' NOT ' );
>> Hc_1b1 = uicontrol(gcf, ' Style ' , ' text ' ,...
' Position ' ,[255 250 85 10], ' Str ' , ' Push Me ' );
控制框属性
如句柄图形对象建立函数一样,uicontrol属性可在对象建立时定义,或如上所示,用set命令来改变。所有可设定的属性,包括字符串文本、回调串、甚至控制框函数类型都可以用set来改变。本章后面有若干例子。
表21.2列出了MATLAB 4.2版本中uicontrol对象的属性及其值。带有*的属性为非文件式的,使用时需加小心。由{}括起来的属性值是缺省值。
表21.2
Uicontrol 对象属性
BackgroundColor
uicontrol背景色。3元素的RGB向量或MATLAB一个预先定义的颜色名称。缺省的背景色是浅灰色。
Callback
MATLAB回调串,当uicontrol激活时,回调串传给函数eval;初始值为空矩阵。
ForegroundColor
uicontrol前景(文本)色。3元素的RGB向量或MATLAB一个预先定义的颜色名称。缺省的文本色是黑色。
HorizontalAlignment
left:
{center}:
right:
标志串的水平排列
相对于uicontrol文本左对齐
相对于uicontrol文本居中
相对于uicontrol文本右对齐
Max
属性 ' Value ' 的最大许可值。最大值取决于uicontrol的 ' Type ' 当uicontrol处于on状态时,无线按钮及检查框将Value设定为Max;该值定义了弹出式菜单最小下标值或滑标的最大值。当Max-Min>1时,可编辑文本框是多行文本。缺省值为1
Min
属性 ' Value ' 的最小许可值。最小值取决于uicontrol的 ' Type ' uicontrol处于off状态时。无线按钮及检查框将Value设定为Min;该值定义了弹出式菜单最小下标值或滑标的最小值。当Max-Min>1时,可编辑文本框是多行文本。缺省值为0
Position
位置向量[left bottom width height]。其中,[left height]表示相对于图形对象左下角的uicontrol的左下角位置。[widht height]表示uicontrol的尺寸大小,其单位由属性Units确定。
Enable*
{on}:
off:
控制框使能状态
uicontrol使能。激活uicontrol,将Callback字符串传给eval
unicntrol不使能,标志串模糊不清。激活unicontrol不起作用
String
文本字符串,在按钮键,无线按钮,检查框和弹出式菜单上指定uicontrol的标志。对于可编辑文本框,该属性设置成由用户输入的字符串。对弹出式菜单或可编辑文本框中多个选项或,每一项用垂直条(|)分隔,整个字符串用引号括起来。框架和滑标,不用引号
Style
{pushbutton}:
radiobutton:
checkbox:
edit:
text:
slider:
frame:
popumenu:
定义uicontrol对象的类型
按钮键:选择时执行一个动作。
无线按钮键:单独使用时,在两个状态之间切换;成组使用时,让用户选择一个选项
检查框:单独使用时,在两个状态之间切换;成组使用时,让用户选择一个选项
可编辑框:显示一个字符串并可让用户改变
静态文本框:显示一个字符串
滑标:让用户在值域范围内选择一个值。
框架:显示包围一个或几个uicontrol的框架,使其形成一个逻辑群。
弹出式菜单 :含有许多互斥的选择的弹出式菜单
Units
inches:
centimeters:
normalized:
points:
{pixels}:
位置属性值的单位
英寸
厘米
归一化的坐标值,图形的左下角映射为[0 0]而右上角的映射为为[1 1]
打印设置点,等于1/72 英寸
屏幕的象素。计算机屏幕分辨率的最小单位。
Value
uicontrol的当前值。无线按钮和检查框在 ' on ' 状态时,value设为Max,当是 ' off ' 状态时,value设为Min。由滑标将滑标的value设置为数值(Min≤Value≤Max),弹出式菜单把value值设置所选择选项的下标(1≤Value≤Max)。文本对象和按钮不设置该属性。
ButtonDownFcn
当uicontrol被选择时,MATLAB回调串传给函数eval。初始值为空矩阵
Children
Uicontrol对象一般无子对象,通常返回空矩阵
Clipping
{on}:
off:
限幅模式
对uicontrol对象无作用效果
对uicontrol对象无作用效果
DestroyFcn
只对Macintosh 4.2 版本。没有文件说明
Interrruptible
{on}:
off:
指定ButtonDownFcn和CallBack串是否可中断
回调不能由其它回调中断
回调串可被中断
Parent
包含uicontrol对象的图形句柄
*Select
值为[on|off]
*Tag
文本串
Type
只读对象辩识串,通常为uicontrol
UserData
用户指定的数据。可以是矩阵,字符串等等
Visible
{on}:
off:
uicontrol对象的可视性
uicontrol对象在屏幕上可见
uicontrol对象不可见,但仍然存在
控制框布置的考虑
uicontrol的属性 ' Position ' 和 ' Units ' 用于分配图形窗口中对象的位置。uicontrol的缺省 ' Position ' 向量为[20 20 60 20],以象素表示。该值是缺省 ' Units ' 值。这是一个60×20 象素uicontrol的象素矩形,uicontrol左下角位于父图形左下角的靠右边20个象素点,靠上边20 个象素。缺省的图形尺寸大约为560×420个象素,位于显示屏的中上部。利用这些信息,uicontrol的布置就变成了一个2维几何布局问题。
要加若干限制。比如,MS-Window忽略位置向量高度值,仅有足够高度以显示一行文本。在所有其它情况下,必须保证控制框足够大以容纳控制框标志字符串。因为显示控制框 ' String ' 属性值所用的字体与用在命令窗口的字体一致,所以,用户对于标志每个控制框的字体属性无法控制,不同平台用不同字体,整体上可由用户改变。
通常确定控制框的大小和位置是一个尝试的过程。即使结果很满意,图形在另一个平台上的外观也许会很不一样,还需调整。通常希望把控制框制作得比所需要的更大一些,以便在所有平台上其标志都可读。
正因为图形有缺省尺寸,不能保证图形都具有缺省大小。若在现有的图形窗口内加上uicontrol和uimenu,则图形尺寸会比缺省值大或小。另外,用户可以在任何时候,对任何图形重调尺寸,除非把图形的 ' Resize ' 属性值置 ' off ' ,才可避免这样做。
当把uicontrol加到尺寸可能重新调整的图形时,有两点需要考虑:属性 ' Units ' 和由固定字体标志字符串所加的约束。若uicontrol的位置是以绝对单位指定如:象素、英寸、厘米或点,则窗口尺寸的重调不会影响uicontrol的大小和位置。uicontrol相对于图形左下角的位置不变;若图形变小,则某些uicontrol可能不可见。
若uicontrol的位置以归一化单位指定,则当图形尺寸调整时,uicontrol相互之间及与图形本身之间的关系保持不变。但是,使用归一化的单位有一个缺点,即如果图形变小,uicontrol对象大小也要调整,则uicontrol的标志可能看不见,因为字体大小是固定的。任何超出调整后的uicontrol的部分就被删去。希望以后MATLAB版本会给程序员对uicontrol和uimenu 的标记字符串的字体属性有更多的控制框。
M 文件举例
下面例子说明了本章所讨论的某些控制框的用法。精通MATLAB工具箱中的函数mmclock在屏幕上生成一个数字钟,它用任选参数设定钟的位置。它使用了框架、文本、无线按钮、检查框和按钮键uicontrol。
为了在PC上运行这个例子,在命令窗的Option菜单中选择Enable Background Process菜单项。这样将引起MATLAB进入无限循环和死锁。为了在Macintosh上得到较好的结果,关掉Option菜单的Background Operation检查标记。X Windows系统版本不需任何调整。
首先,建立函数的语句和帮助文本。
function T=mmclock(X,Y)
%MMCLOCK Place a digital clock on the screen.
% MMCLOCK places a digital clock at the upper-right corner
% of the display screen.
% MMCLOCK(X,Y) places a digital clock at position X pixels
% to the right and Y pixels above the bottom of the screen.
% T=MMCLOCK returns the current date and time as a string
% when ' Close ' is pressed.
设定初始值,分析输入参量。
fsize=[200 150]; sec=1; mil=0;
mstr=[ ' Jan ' ; ' Feb ' ; ' Mar ' ; ' Apr ' ; ' May ' ; ' Jun '
' Jul ' ; ' Aug ' ; ' Sep ' ; ' Oct ' ; ' Nov ' ; ' Dec ' ];
scr=get(0, ' ScreenSize ' );
if nargin= =0
figpos=[scr(3)-fsize(1)-20 scr(4)-fsize(2)-5 fsize(1:2)];
elseif nargin= =2
figpos={X Y fsize(1:2)];
else
error( ' Invalid Arguments ' );
end
建立图形,在图中设置uicontrol为某些缺省值。
Hf_clock=figure( ' Position ' ,figpos ' ,...
' Color ' ,[.7 .7 .7],...
' NumberTitle ' , ' off ' ,...
' Name ' , ' Digital Clock ' );
set(Hf_clock, ' DefaultUicontrolUnits ' , ' normalized ' ,...
' DefaultUicontrolBackgroundColor ' ,get(Hf_clock, ' Color ' ));
对秒建立Close 按钮键、无线按钮;对24小时建立检查框。
Hc_close=uicontrol( ' Style ' , ' push ' ,...
' Position ' ,[.65 .05 .30 .30],...
' BackgroundColor ' ,[.8 .8 .9],...
' String ' , ' Close ' ,...
' CallBack ' , ' close(gcf) ' );
Hc_sec=uicontrol( ' Style ' , ' radiobutton ' ,...
' Position ' ,[.05 .05 .50 .13],...
' Value ' ,sec,...
' String ' , ' Seconds ' );
Hc_mil=uicontrol( ' Style ' , ' checkbox ' ,...
' Position ' ,[.05 .22 .50 .13],...
' Value ' ,mil,...
' String ' , ' 24-Hour ' );
对日期和时间显示创建框架和文本串。
Hc_dframe=uicontrol( ' Style ' , ' frame ' , ' Position ' ,[.04 .71 .92 .24]);
Hc_date =uicontrol( ' Style ' , ' text ' , ' Position ' ,[.05 .72 .90 .22]);
Hc_tframe=uicontrol( ' Style ' , ' frame ' , ' Position ' ,[.04 .41 .92 .24]);
Hc_time=uicontrol( ' Style ' , ' text ' , ' Position ' ,[.05 .42 .90 .22]);
循环,直到按钮键回调函数关闭图形,每秒更新显示一次。
while find(get(0, ' Children ' ) = = Hf_clock % Looop while clock exists
sec = get(Hc_sec, ' Value ' );
mil = get(Hc_mil, ' Value ' );
now=fix(clock);
datestr=sprintf( ' %s %2d %4d ' ,mstr(now(2),:,now(3),now(1));
if mil
suffx= ' ' ;
else
if now(4)>12
suffix= ' pm ' ;
now(4)=rem(now(4),12);
else
suffix= ' am ' ;
end
end
timestr=[num2str9now(4)) ' : ' sprintf( ' %02d ' ,now(5))];
if sec
timestr=[timestr ' : sprintf( ' %02d,now(6))];
end
timestr=[timestr suffix];
set(Hc_date. ' String ' ,datestr);
set(Hc_time, ' String ' ,timestr);
pause(1)
end
最后,如果有需,返回日期和时间字符串。
if nargout
T=[datestr ' - ' timestr];
end
虽然这个例子说明了如何用uicontrol建立一个完整的个GUI函数,但并不实用。因为该函数保持循环直至Close按钮按下,非等到时钟图形关闭,命令窗口才能使用。
注意,上例只含有一个回调函数字符串,即在按钮键回调串中的 ' close ' 语句。其它按钮值是在While循环中得到,而不是按钮本身用回调函数激发一个动作。更复杂的M文件需要复杂的回调。
21.5 编程和回调考虑
用户句柄图形界面的基础部分已经阐述过了,现在是应用它的时候了。正如所见,在命令行通过输入uimenu和uicontrol来建立效率不高。脚本或函数M文件使用更为简便。假定想实现一个M文件,首先确定是否要编写脚本文件或函数文件。
脚本与函数
脚本文件似乎是当然的选择。在脚本中,所有的命令都在命令工作窗口执行,因此随时可以使用所有的MATLAB函数和对象句柄。将信息传给回调函数无任何困难。然而这里有几种权衡。首先,当所有的变量都是可利用时,工作空间内充斥了变量名和变量值,即使它们已经不再有用。其次,如果用户使用clear命令,重要的对象句柄就可能丢失。另一个缺点是:用脚本文件定义回调字符串可能变得十分复杂。例如,以下有一个滑标的文件片段,节选自精通MATLAB工具箱中脚本文件mmsetclr
Hc_rsli=uicontrol(Hf_fig, ' Style ' , ' slider ' ,...
' Positon ' ,[.10 .55 .35 .05],...
' min ' ,0, ' max ' ,1, ' Value ' ,initrgb(1),...
' CallBack ' ,[...
' set(Hc_nfr,''BackgroundColor'', ' ,...
' [get(Hc_rsli,''Val''),get(Hc_gsli,''Val''),get(Hc_bsli,''Val'')]), ' ,...
' set(Hc_ncur,''String'', ' ,...
' sprintf(''[%.2f %.2f %.2f]'',get(Hc_nfr,''BakgroundColor''))), ' ,...
' hv=rgb2hsv(get(Hc_nfr,''BakgroundColor'')); ' ,...
' set(Hc_hsli,''Val'',hv(1)), ' ,...
' set(Hc_hcur,''String'',sprintf(''%.2f'',hv(1))), ' ,...
' set(Hc_ssli,''Val'',hv(2)), ' ,...
' set(Hc_scur,''String'',sprintf(''%.2f'',hv(2))), ' ,...
' set(Hc_vsli,''Val'',hv(3)), ' ,...
' set(Hc_vcur,''String'',sprintf(''%.2f'',hv(3))), ' ,...
' set(Hc_rcur,''String'',sprintf(''%.2f'',get(Hc_rsli,''Val''))) ' ]);
另一个问题是,脚本文件比函数文件运行得慢,脚本在第一次运行时要编译。最后一点,脚本文件没有函数灵活。函数可接受输入参量并返回值。因此,函数可用作其它函数的参变量。
函数不会使命令窗工作空间拥挤;当反复调用时运行快速;接受输入参量并返回值;回调字符串书写不复杂。因此,在许多场合,函数M文件是最佳的选择。
考虑前面脚本文件中滑标定义的例子。以下是等价的文件片段,取自精通MATLAB工具箱中函数文件mmsetc。
Hc_rsli=uicontrol(Hf_fig, ' Style ' , ' slider ' ,...
' Position ' ,[.10 .55 .35 .05],...
' Min ' ,0, ' Max ' ,1, ' Value ' ,initrgb(1),...
' CallBack ' , ' mmsetc(0,''rgb2new'') ' );
注意回调字符串以不同的参量调用mmsetc。这是一个在回调中使用递归函数调用的例子。然而函数本身有它自己的问题。主要的困难源于要将回调字符串传给eval并在命令窗口工作空间中运行,而其余的程序码在函数工作空间内执行。这里用前面章节所讨论的变量和函数的大量规则。在函数内定义的变量在命令窗口工作空间不存在,因此不在回调串中使用。同时在命令窗工作空间的变量在函数本身内部也不存在。
有若干既能解决该问题又能利用函数优点的方法。全局变量、' UserData ' 属性、仅用于回调的特殊函数M文件和递归函数调用均是创建GUI函数十分有用的工具。