eight 发表于 2007-1-13 13:36

[原创]关于guidata和guihandles的一点心得

这两天 help guidata and help guihandles 了一下,明白了一些以前没有注意的问题,在这里介绍一下,欢迎大家讨论并指正:

... excerpt from the GUI setup code ...

    f = openfig('mygui.fig');
    data = guihandles(f); % initialize it to contain handles
    data.errorString = 'Total number of mistakes: ';
    data.numberOfErrors = 0;
    guidata(f, data);% store the structure

    ... excerpt from the slider's callback ...

    data = guidata(gcbo); % get the struct, use the handles:
    set(data.valueEdit, 'String',...
      num2str(get(data.valueSlider, 'Value')));

上面代码是从help guidata拷贝出来的,解释一下:

f = openfig('mygui.fig');%打开窗体并返回其句柄f

data = guihandles(f);%创建句柄结构体data并把窗体中所有资源添加到该句柄结构体中,这里的“资源”是指控件或者组件,以下简称句柄域。在我的测试中,用了两种不同的窗体,一种是fig文件方式的GUI窗体,另一种是普通的一个figure,得到的data分别是GUI上的控件句柄(Tag属性值作为域名)和figure上的组件句柄(这个应该是默认的,包括各菜单和工具栏等)。

guidata(f, data);%把结构体存储到句柄f中

data = guidata(gcbo); %从当前对象的句柄中获取所有资源的handles和用户的数据(即用户定义的域),这两者的总体以下简称数据域

以上是我写的解释,实际上在“[转帖]函数结构与参数传递”一文中,就有上面几个函数的介绍:
=========================================================
关于handles:
实际上这个handles是MATLAB中GUI编程中最常用的一个句柄管理变量。
handles的生成:handles = guihandles( figurehandle );将figure中所有对象中“Tag”属性有值的句柄的handle采集在一起。handles是结构名,每个“Tag”域名里保持此对象的句柄。
handles的保存:guidata( figurehandle, handles );handles将保存在figure对象的“ApplicationData”的一个域名里。
handles的使用:handles = guidata( h );其中为figure中任意一个对象的句柄。
=========================================================

因此,如果用户定义的域没有做save的操作,则在后续的处理中,不能访问该域,以下是对上述两种窗体的不同情形检测的结果,得到的结论是一样。

===============普通的一个figure====================================================

f = figure(1);
data = guihandles(f); % initialize it to contain handles
data.a = 'Total number of mistakes: ';
guidata(f, data);% store the structure in the figure's application data
data.b = 0;

c = guidata(f); % returns previously stored data
c

在输出的c中,只有域a的数据,没有域b的数据。如果此时把guidata(f, data);注释掉,则c为空,就连句柄f中所有资源的handles也没有记录下来,说明数据域和句柄域分开存放(也许matlab实际存储时候对于资源的句柄只有一个副本,这个没有深究),guihandles读取的是句柄域信息,guidata读取的是数据域(包括句柄和用户数据)信息。
===========================================================
===============fig文件方式的GUI窗体(部分代码)=========================================

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdatareserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
handles.abc=2;
%guidata(hObject, handles);

% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton2 (see GCBO)
% eventdatareserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
handles

假设先运行button1,后运行button2,则button2回调函数中的handles没有abc域。另外,有两个值得注意的地方,其一是在各回调函数中不需要用类似data = guidata(gcbo);的语句,以下是matlab的解释(help guidata 就可以看到):Note that GUIDE generates callback functions to which a structure of handles is passed automatically as an input argument. This eliminates the need to call "data = guidata(gcbo);" in callbacks written using GUIDE. 其二,假如button1回调函数中的guidata(hObject, handles);没有注释掉,则button2回调函数中的handles是有abc域的,这一点毫无疑问。但是细心的读者会发现,两个回调函数的hObject是不同的,也就是说,在button1回调函数中的guidata(hObject, handles);是把handles存入button1对应的hObject中,那为何在button2的回调函数中能够通过省略的“handles = guidata(gcbo);”语句把新增加在button1上的数据域abc读取出来呢?这个原因我没有时间具体深究下去(也许《精通GUI》一书上有,呵呵),不过我估计答案如下:根据图形对象继承关系(参见《精通GUI》一书图3.3),使用guidata函数时,会“寻根问底”地访问该对象的父对象(这里为该GUI的主figure);或者save的时候就直接保存到其父对象(这里为该GUI的figure)中,所以无论自定义的域在哪个button中save,通过button1或通过button2都可以读取到该域的数据。
========================================================
update(additive words) in blue

[ 本帖最后由 eight 于 2007-1-16 13:14 编辑 ]

yangzhijing521 发表于 2007-1-16 09:52

支持八兄!辛苦了!为大家贡献很大啊!:handshake

eight 发表于 2007-1-16 12:32

原帖由 yangzhijing521 于 2007-1-16 09:52 发表
支持八兄!辛苦了!为大家贡献很大啊!:handshake


呵呵,应该的,谢谢大家的支持!:loveliness:

[ 本帖最后由 eight 于 2007-1-16 12:48 编辑 ]

geoer 发表于 2007-1-17 08:11

就快放假回家了,在家也没电脑用,多带几个eight贴回去研究吧,哈哈:lol 。

lxq 发表于 2007-1-17 13:41

我看书上的一个例子
uimenu(hplot,'Label','&Sin','callback',['t=-pi:pi/20:pi;','plot(t,sin(t);',...
    'set(hgon,"Enable","on");','set(hgoff,"Enable","on");',...
    'set(hbon,"Enable","on");','set(hboff,"Enable","on");']);
出现这样的错误:

??? Error: Unexpected MATLAB expression.

??? Error using ==> t=-pi:pi/20:pi;plot(t,sin(t)set(hgon,"Enable","on");set(hgoff,"Enable","on");set(hbon,"Enable","on");set(hboff,"Enable","on");

??? Error while evaluating uimenu Callback

请问eight这是哪里出的问题?谢谢

eight 发表于 2007-1-17 15:29

原帖由 lxq 于 2007-1-17 13:41 发表
我看书上的一个例子
uimenu(hplot,'Label','&Sin','callback',['t=-pi:pi/20:pi;','plot(t,sin(t);',...
    'set(hgon,"Enable","on");','set(hgoff,"Enable","on&q ...


plot(t,sin(t); 那里漏了一个括号,并且注意Enable等关键词外面使用两个单引号(非一个双引号),应该就没有问题:


uimenu(hplot,'Label','&Sin','callback',['t=-pi:pi/20:pi;','plot(t,sin(t));',...
    'set(hgon,''Enable'',''on'');','set(hgoff,''Enable'',''on'');',...
    'set(hbon,''Enable'',''on'');','set(hboff,''Enable'',''on'');']);

lxq 发表于 2007-1-17 19:19

谢谢了:)

太疏忽了噢:(
页: [1]
查看完整版本: [原创]关于guidata和guihandles的一点心得