damao_pq 发表于 2007-4-27 18:34:42

GUI 菜单操作未定义句柄问题(找到问题的原因,但不知怎么解决)

figure
h_menu=uimenu('label','Option');
h_sub1=uimenu(h_menu,'label','Grid on',...
'callback',[...
'grid on,',...
'set(h_sub1,''checked'',''on''),',...
'set(h_sub2,''checked'',''off''),',...
]);
h_sub2=uimenu(h_menu,'label','Grid off',...
'callback',[...
'grid off,',...
'set(h_sub2,''checked'',''on''),',...
'set(h_sub1,''checked'',''off''),',...
]);

运行后出现错误,h_sub1上已经定义了?,不知为什么,调了一个下午搞不通。

??? Undefined function or variable 'h_sub1'.

??? Error using ==> grid on,set(h_sub1,'checked','on'),set(h_sub2,'checked','off'),
Undefined function or variable 'h_sub1'.

??? Error while evaluating uimenu Callback



PS:
刚才一直在论坛里逛,到了第17页,在看<两窗口间参数传递的简单例子>时,wm210 提到“在程序一定要对每个对象的Tag属性进行设置,否则,你是一定不能实现传递的.并且对tag进行设置的时候,最好都设置成和其句柄对应.” 突然有了启发:加上tag后就可行了
figure
h_menu=uimenu('label','Option');
h_sub1=uimenu(h_menu,'label','Grid on',...
    'tag','h_sub1',...
    'callback',[...
    'grid on,',...
    'set(h_sub1,''checked'',''on''),',...
    'set(h_sub2,''checked'',''off''),',...
    ]);
h_sub2=uimenu(h_menu,'label','Grid off',...
    'tag','h_sub2',...
    'callback',[...
    'grid off,',...
    'set(h_sub2,''checked'',''on''),',...
    'set(h_sub1,''checked'',''off''),',...
    ]);


又ps.
关了matlab,重起后,不加tag也行了,谢谢热心的penght 、 shunfly


PS.ps.ps
上面是脚本文件形式的能运行,但只要在前加上function 变成函数文件就会出错,不知要怎么设置?

??? Invalid handle object.
??? Error using ==> grid on,set(h_sub1,'checked','on'),set(h_sub2,'checked','off'),
Invalid handle object.
??? Error while evaluating uimenu Callback

****************************************
*******************************************
昨天晚上睡觉时想了一下,脚本文件能运行,函数文件不能运行,可能是函数运行完就释构了,找不到句柄。
找到了一个替代办法,感觉不是特别好,不知有没有更好的办法,期待高手解答。

临时方法:

function Gui_menu
figure
h_menu=uimenu('label','Option','tag','h_menu');
h_sub1=uimenu(h_menu,'label','Grid on',...
    'tag','h_sub1',...
    'callback',[...
    'grid on,',...
   'set(findobj(gcf,''tag'',''h_sub1''),''checked'',''on''),',...
    'set(findobj(gcf,''tag'',''h_sub2''),''checked'',''off''),',...
    ]);
h_sub2=uimenu(h_menu,'label','Grid off',...
    'tag','h_sub2',...
    'callback',[...
    'grid off,',...
    'set(findobj(gcf,''tag'',''h_sub2''),''checked'',''on''),',...
    'set(findobj(gcf,''tag'',''h_sub1''),''checked'',''off''),',...
    ]);

[ 本帖最后由 damao_pq 于 2007-4-28 09:38 编辑 ]

penght 发表于 2007-4-27 19:03:07

我调试了,程序没问题

shunfly 发表于 2007-4-27 19:06:51

我要是哪天吃饱了,网速好了
我真希望花一个晚上熬熬夜
整理整理版面的的FAQ

wm210 发表于 2007-4-28 11:19:58

TAG是每个对象特有的识别码,每个对象都有一个独一无二的识别码,就象我们每人都有一个身份证一样.MATLAB中也一样.

在MATLAB中,脚本文件中出现的变量它的作用域相当于全局变量的作用域,因而你可以在整个在整个系统中都可以使用它,而不需刻意的去考虑参数传递的问题.所以你的脚本程序可以运行,但function 却不可以运行.主要就是两种文件中的变量的作用域的问题造成的.

如果把你的脚本文件变成function的文件,你的程序可以这么改:

    jet.m程序如下:

function   jet
globalh
h=figure;
h_menu=uimenu('label','Option');
h_sub1=uimenu(h_menu,'label','Grid on','tag','h_sub1','callback',...
   ['globalh;',...
       'h_sub1=getappdata(h,''h_sub1'');',...
       'h_sub2=getappdata(h,''h_sub2'');',...
       'grid on;',...
    'set(h_sub1,''checked'',''on'');',...
    'set(h_sub2,''checked'',''off'');']);
setappdata(h,'h_sub1',h_sub1);
h_sub2=uimenu(h_menu,'label','Grid off','tag','h_sub2','callback',...
   ['globalhandles;',...
      'h_sub1=getappdata(h,''h_sub1'');',...
      'h_sub2=getappdata(h,''h_sub2'');',...
    'grid off,',...
    'set(h_sub2,''checked'',''on''),',...
    'set(h_sub1,''checked'',''off''),']);
setappdata(h,'h_sub2',h_sub2);


这个程序我已经验证了,OK.

请记住,使用function形式的程序时,一定要记得参数传递!

[ 本帖最后由 wm210 于 2007-4-28 11:38 编辑 ]

damao_pq 发表于 2007-4-28 21:28:15

谢谢wm210的指教,恍然大悟,我原来的问题就是那个目标都没了,用全局变量,试验了一下,只要弹出figure后,我在command里打上clear all,再点菜单也不行了,全局变量释放了,找不到目标了。

      加了tag相当在figure下注册了(guihandles(gcf)下就有这个目标),再用‘tag'去找相当于照名去找那个人了,惟一目标找到了,也就成功。现在感觉用find这个方法还行。

       用全局变量这个问题,想了想当函数多时,全局变量容易相互干扰,总不太舒服,受wm210的启发,索性再用一个appdata,感觉这样好一点,不知还有没有更好的办法,请大家探讨。

function   jet

h=figure;
setappdata(0,'h',h);                        %%%%
h_menu=uimenu('label','Option');
h_sub1=uimenu(h_menu,'label','Grid on','tag','h_sub1','callback',...
    ['h=getappdata(0,''h'');',...         %%%%%
    'h_sub1=getappdata(h,''h_sub1'');',...
    'h_sub2=getappdata(h,''h_sub2'');',...
    'grid on;',...
    'set(h_sub1,''checked'',''on'');',...
    'set(h_sub2,''checked'',''off'');']);
setappdata(h,'h_sub1',h_sub1);
h_sub2=uimenu(h_menu,'label','Grid off','tag','h_sub2','callback',...
    ['h=getappdata(0,''h'');',...
    'h_sub1=getappdata(h,''h_sub1'');',...
    'h_sub2=getappdata(h,''h_sub2'');',...
    'grid off,',...
    'set(h_sub2,''checked'',''on''),',...
    'set(h_sub1,''checked'',''off''),']);
setappdata(h,'h_sub2',h_sub2);

这样的话,在command里打上rmappdata(h,'h_sub1')后,对'h_sub1'也会失去作用。同样要命的是rmappdata(0,'h‘),连锅都端了,还想吃什么饭,^V^
只是不怕clear all了,呵呵~~

SCIE 发表于 2007-4-28 21:53:22

看看我的实现如何?
以下代码可以都放到 jet.m 里,这样的实现我想可以天不怕地不怕了,呵呵^_^
function jet
h = figure;
h_menu = uimenu('label', 'Option');
h_sub1 = uimenu(h_menu, 'label', 'Grid on');
h_sub2 = uimenu(h_menu, 'label', 'Grid off');
set(h_sub1, 'CallBack', {@sub1_callback, h_sub2});
set(h_sub2, 'CallBack', {@sub2_callback, h_sub1});

function sub1_callback(h_sub1, Event, h_sub2)
grid on;
set(h_sub1, 'checked', 'on')
set(h_sub2,'checked' ,'off');

function sub2_callback(h_sub2, Event, h_sub1)
grid off;
set(h_sub2, 'checked', 'on')
set(h_sub1,'checked' ,'off');

damao_pq 发表于 2007-4-28 22:19:27

刚才又想了想,既然appdata能实现,那guidata也能实现吧,就试了试:


function   guidata_experiment

h=figure;
handles=guihandles(h);
handles.h_menu=uimenu('label','Option');
handles.h_sub1=uimenu(handles.h_menu,'label','Grid on','tag','h_sub1','callback',...
    ['handles=guidata(gcf);',...
      'grid on;',...
    'set(handles.h_sub1,''checked'',''on'');',...
    'set(handles.h_sub2,''checked'',''off'');']);
handles.h_sub2=uimenu(handles.h_menu,'label','Grid off','tag','h_sub2','callback',...
    ['handles=guidata(gcf);',...
    'grid off,',...
    'set(handles.h_sub2,''checked'',''on''),',...
    'set(handles.h_sub1,''checked'',''off''),']);
guidata(h,handles);

PS.
还是SCIE方法高明,刚才没更新网页,等贴上这个,才发现SCIE的高明方法,佩服佩服!
要向各位多多学习。

[ 本帖最后由 damao_pq 于 2007-4-28 22:30 编辑 ]

shunfly 发表于 2007-4-29 02:00:01

我的风格
所有的控件菜单回掉函数通用一个入口function jet
h = figure;
h_menu = uimenu('label', 'Option');
h_sub1 = uimenu(h_menu, 'label', 'Grid on' , 'tag','mGridOn');
h_sub2 = uimenu(h_menu, 'label', 'Grid off', 'tag','mGridOff');
set(h_sub1, 'CallBack', {@Action,h_sub2});
set(h_sub2, 'CallBack', {@Action,h_sub1});

function Action(hObject, eventdata,handles)
hTag = get(hObject,'tag');
switch hTag
    case 'mGridOn'
      grid on;
    case 'mGridOff'
      grid off;
end
      set(hObject,'checked', 'on');
      set(handles,'checked', 'off');

[ 本帖最后由 shunfly 于 2007-5-8 23:45 编辑 ]

shunfly 发表于 2007-4-29 02:02:46

PS:
参数传递等
搜索一下版面吧
CWIT总结过
连楼上的wm210翻帖子学习经验
后来翻历史遗留帖子也总结了好几次
我都记得给加了几次分
有空多翻帖子吧
关于GUI/混合编程

wildyoung 发表于 2007-5-8 23:12:27

原帖由 shunfly 于 2007-4-29 02:00 发表 http://www.simwe.com/forum/images/common/back.gif
我的风格
所有的控件菜单回掉函数通用一个入口

function jet
h = figure;
h_menu = uimenu('label', 'Option');
h_sub1 = uimenu(h_menu, 'label', 'Grid on' , 'tag','mGridOn');
h_sub2 = uimenu(h_m ...

所有的控件菜单回掉函数通用一个入口
这种方法很棒、很简洁,

function Action(hObject, eventdata,handles)

版主能详细解释下,Action函数中的三个形参的来龙去脉吗?
我一直很困惑hObject, eventdata,handles这三个东东究竟代表哪些空间中的句柄或是数据,
代表的这些数据或句柄的生命周期究竟有多长能、在内存中的模型究竟是怎样的呢?......

麻烦版主指点迷津,不胜感激。

shunfly 发表于 2007-5-8 23:30:22

hObject代表回掉句柄
比如菜单,工具栏
eventdata在MATLABR13为空
handles相当于一个参数
你可以看看GUIDE自动形成的回调函数

wildyoung 发表于 2007-5-8 23:39:44

原帖由 shunfly 于 2007-5-8 23:30 发表 http://www.simwe.com/forum/images/common/back.gif
hObject代表回掉句柄
比如菜单,工具栏
eventdata在MATLABR13为空
handles相当于一个参数
你可以看看GUIDE自动形成的回调函数

还是有很多迷惑的地方,
比如,
hObject包含了程序中所有被创建的对象的句柄呢,还是只是其中的一部分呢?
hObject好像是系统自动创建的吧,要是自己定义了一个变量,名字也叫hObject,
会不会覆盖了系统自动创建的hObject呢?
是不是随时随处都可以直接调用hObject中包含的句柄呢?
如果应用程序创建的对象很多的话,那么程序会不会背负一个庞大的句柄结构,
从而占据很大内存,影响程序运行速度呢?

谢谢shunfly指点,不胜感激。

shunfly 发表于 2007-5-8 23:49:03

hObject与CALLBACK结合的,是哪个CALLBACK那么就是哪个的句柄
PS:以下仅仅是我个人的GUI风格
   摸索得到你自己的风格即可,不必照搬

function jet
    h       = figure('menubar','none');
    h_menu= uimenu('label', 'Option');
    h_sub1= uimenu(h_menu, 'label', 'Grid on' , 'tag','mGridOn');
    h_sub2= uimenu(h_menu, 'label', 'Grid off', 'tag','mGridOff');
    hObject = 4;
    x       = 0:0.1:6;
    y       = sin(x);
    set(h_sub1, 'CallBack', {@Action,{x,y}});
    set(h_sub2, 'CallBack', {@Action,h});
function Action(hObject, eventdata,data)
    fprintf('当前的CALLBACK句柄的TAG为%s\n',get(hObject,'tag'));
    hTag = get(hObject,'tag');
    switch hTag
      case 'mGridOn'
            grid on;
            plot(data{1},data{2});
      case 'mGridOff'
            grid off;
            set(data,'color','w');
    end

[ 本帖最后由 shunfly 于 2007-5-9 00:05 编辑 ]

wildyoung 发表于 2007-5-9 15:09:44

原帖由 shunfly 于 2007-5-8 23:49 发表 http://www.simwe.com/forum/images/common/back.gif
hObject与CALLBACK结合的,是哪个CALLBACK那么就是哪个的句柄
PS:以下仅仅是我个人的GUI风格
   摸索得到你自己的风格即可,不必照搬

function jet
    h       = figure('menubar','none');
    h_men ...

我模拟了你的程序,很有收获,不过有两个问题:
1. 程序中的 hObject=4;是什么意思呢,这一句应该每什么作用吧?
2.如果有50个以上的菜单项目的话,
switch case 结构将会变得很庞大,会不会影响运行速度呢:

shunfly 发表于 2007-5-9 15:42:42

第一问见12楼你的疑问

hObject包含了程序中所有被创建的对象的句柄呢,还是只是其中的一部分呢?
hObject好像是系统自动创建的吧,要是自己定义了一个变量,名字也叫hObject,

你的第二问
我说过你仅仅是我的GUI风格
这样共用一个CALLBACK,显然你必须要程序区分到底是哪个菜单响应
所以来个switch tag
当然,你如果在{@Action,{菜单1,y}});提示
那么就不需要switch了
这其实和一个菜单对应一个CALLBACK差不多

yansiping 发表于 2009-6-7 22:41:28

太厉害了 佩服
页: [1]
查看完整版本: GUI 菜单操作未定义句柄问题(找到问题的原因,但不知怎么解决)