现象
HAT 程序在处理 TESTING_THREAD_DONE 事件时,出现非法操作引起程序退出。疑为转换指针类型时发生错误。
分析
MainFrame.cpp 文件里的函数 MainFrame::OnTestingThreadDone( wxCommandEvent& event ) 有下面的代码:
ReportPanel* rp = (ReportPanel*) FindWindowById(ID_REPORTWINDOW);
在 MainFrame.h 文件里,ID_REPORTWINDOW 由 DialogBlocks 自动定义:
#define ID_REPORTWINDOW 10016
在项目中查找 10016,TaskPanel.h 文件里有下面的定义:
#define ID_MIDDLELINE_OUTER 10016
在 里对应的控件是:
wxToggleButton* itemToggleButton37 = new wxToggleButton( _panel, ID_MIDDLELINE_OUTER, _("Outer"), wxDefaultPosition, wxDefaultSize, 0 );
因此在使用 FindWindowById() 时因为 ID 重复,找到的窗口实际上是 wxToggleButton,将这个指针强制转换为 ReportPanel 类型时,发生非法操作错误。
解决方案
因为 DialogBlocks 虽然能够保证在一个文件里生成不相重复的 ID,但它不能避免不同文件间的 ID 冲突。因此有两个解决方案:
- 对于不同的文件使用不同的分段,例如 11xxx,12xxx,13xxx 等分段,例如:使用 DialogBlocks 把
ID_REPORTWINDOW重新定义为:#define ID_REPORTWINDOW 11016
但这个方法会造成 ID 的浪费,另外可用的分段数终究有限。优点是安全。使用时要注意做好文档工作,详细记录 ID 的分配情况。
- 使用 wxWindow 的静态函数
FindWindowById的第二个参数 parent 来限定搜索范围。FindWindowById的定义如下:static wxWindow* FindWindowById(long id, wxWindow* parent = NULL);
如果 parent 为 NULL,则从最顶层窗口开始寻找。也可以使用成员函数
FindWindow在当前窗口的子窗口里寻找指定 ID 对应的窗口,FindWindow的定义如下:wxWindow* FindWindow(long id) const;
这种方法也有其局限性,例如对于下面的情况:
10001 +- 10003 | +- 10002(2) | +- 10004; +- 10002(1)
使用本方法查找 10002 不能保证查找到 10002(1),此时还是只能采取方法1提出的方案。
Leave a Reply
You must be logged in to post a comment.