现象
使用 DialogBlocks 建立自定义窗口类,使用 wxFlexGridSizer 布局控件。主窗口类使用这个自定义的窗口类作为子控件。因为这个子控件在程序开始运行隐藏,只在执行某项任务完成后才显示,结果在显示时位置和尺寸都不对,几乎不可见,使用鼠标调整主窗口尺寸后这个子控件的布局和尺寸才随之变化达到设计意图。
Still waters run deep.
使用 DialogBlocks 建立自定义窗口类,使用 wxFlexGridSizer 布局控件。主窗口类使用这个自定义的窗口类作为子控件。因为这个子控件在程序开始运行隐藏,只在执行某项任务完成后才显示,结果在显示时位置和尺寸都不对,几乎不可见,使用鼠标调整主窗口尺寸后这个子控件的布局和尺寸才随之变化达到设计意图。
HAT 程序在处理 TESTING_THREAD_DONE 事件时,出现非法操作引起程序退出。疑为转换指针类型时发生错误。
在编译手工编码的 MpiProdave.cpp/MpiProdave.h 时,使用 DialogBlocks MinGW Debug (Non-Unicode)标准编译器设置发生编译错误如下。这种错误在其他非 DialogBlocks 生成的某些 c++ 文件编译时也会出现。而使用 MinGW Unicode Debug 标准编译设置时则没有编译错误发生。
g++.exe -c -o MinGWDebug/MpiProdave.o -fno-pcc-struct-return -fstrict-aliasing -Wall -Wno-write-strings -D__WXMSW__ -D__GNUWIN32__ -D__WIN95__ -D__WXDEBUG__ -ggdb -O0 -Wall -Wno-write-strings -I"C:/wx/include" -I"C:/wx/contrib/include" -I"C:/wx/lib/gcc_lib/mswd" src\MpiProdave.cpp *** In file included from C:/wx/include/wx/toplevel.h:317, *** from C:/wx/include/wx/dialog.h:17, *** from C:/wx/include/wx/msw/msgdlg.h:16, *** from C:/wx/include/wx/msgdlg.h:49, *** from src\MpiProdave.cpp:17: *** C:/wx/include/wx/msw/toplevel.h:122: error: expected identifier before numeric constant *** C:/wx/include/wx/msw/toplevel.h:122: error: expected `,' or `...' before numeric constant *** C:/wx/include/wx/msw/toplevel.h:122: error: ISO C++ forbids declaration of `parameter' with no type *** mingw32-make.exe: *** [MinGWDebug/MpiProdave.o] Error 1
wxWidgets 与 IBPP 一同使用(连接 wxWidgets 库)时,
make -f makefile.gcc all g++.exe -c -o MinGWUnicodeDebug/all_in_one.o -fno-rtti -fno-pcc-struct-return -fstrict-aliasing -Wall -Wno-write-strings -D__WXMSW__ -D__GNUWIN32__ -D__WIN95__ -DUNICODE -D__WXDEBUG__ -ggdb -O0 -Wall -Wno-write-strings -I"C:/wx/include" -I"C:/wx/contrib/include" -I"C:/wx/lib/gcc_lib/mswud" ibpp\core\all_in_one.cpp In file included from ibpp\core\all_in_one.cpp:35: ibpp\core\_ibpp.cpp: In member function `ibpp_internals::GDS* ibpp_internals::GDS::Call()': ibpp\core\_ibpp.cpp:142: error: cannot convert `const char*' to `const WCHAR*' for argument `1' to `HINSTANCE__* LoadLibraryW(const WCHAR*)' ibpp\core\_ibpp.cpp:162: error: cannot convert `char*' to `WCHAR*' for argument `2' to `DWORD GetModuleFileNameW(HINSTANCE__*, WCHAR*, DWORD)' ibpp\core\_ibpp.cpp:170: error: cannot convert `char*' to `WCHAR*' for argument `1' to `WCHAR* lstrcatW(WCHAR*, const WCHAR*)' ... ...
针对第二种情况,不使用 wxWidgets 的编译选项 -fno-rtti,重新编译 IBPP(all_in_one.cpp)。
即在 Makefile 里把下面一行:
CPPFLAGS= -fno-rtti -fno-pcc-struct-return -fstrict-aliasing -Wall -Wno-write-strings -D__WXMSW__ -D__GNUWIN32__ -D__WIN95__
改为
CPPFLAGS=-fno-pcc-struct-return -fstrict-aliasing -Wall -Wno-write-strings -D__WXMSW__ -D__GNUWIN32__ -D__WIN95__
故障消除。
private:
wxLocale _locale;
if (_locale.Init(wxLANGUAGE_FRENCH, 0)) {
wxLocale::AddCatalogLookupPathPrefix(wxT("resources"));
_locale.AddCatalog(_T("default"));
}
这里重要的是行1:不能设置为 wxLANGUAGE_CHINESE_SIMPLIFIED,否则系统报错“不能设置为指定语言”。而 Windows 2000 操作默认支持法语,这里实际上绕过了系统的检查。
注意:使用这个方法,菜单(菜单条和弹出式菜单)无法汉化,其余用户界面控件显示正常。有时会有字符宽度问题。
窗口关系如下:
wxScrolledWindow > wxBoxSizer > wxPanel derived
从 wxPanel derived 函数内部调用如下代码:
// ajust chart window size SetSizeHints(w, h); // ask containing sizer to request scroll window for resizing GetParent()->GetSizer()->FitInside(GetParent());
在 wxFrame 窗口中嵌入 wxSplitWindow,程序初始运行时隐藏,待载入数据后显示,但显示时未铺满 wxFrame 的用户区域,手动 resize 后,尺寸调整至正常。
给父窗口(此处是 wxFrame)发送 wxSizeEvent,代码如下(代码片段在 wxFrame 派生类的一个函数中):
_contentwnd->Show(); // send resize event to frame to make split window fit into content area wxSizeEvent sizeEvent(GetSize()); wxPostEvent(this, sizeEvent);
从 wxPanel 派生一个新类,使用 OnPaint() 画背景(灰色边线的矩形),父窗口 resize 时新类的窗口中画出的背景发生重叠。
在包含新类的父窗口 style 属性页中选中 wx_FULL_REPAINT_ON_RESIZE。
frame 窗口关闭时(似乎)已经强行关闭了所有线程,因此使用线程指针 Delete() 将出现内存错误。
拦截程序菜单中的退出事件和主Frame的 wxEVT_CLOSE_WINDOW 事件(called when the user closes the frame via the window decorations),删除线程。参见 hats/MainFrame.cpp
更好的解决方案:有无一个统一的节点,所有导致应用程序关闭(主窗口关闭)的过程都在关闭主窗口之前调用这个节点,而这个节点又可以重载(虚拟)?
wxMutexGuiEnter(); // 进行 GUI 操作 // ... wxMutexGuiLeave();
在非主线程(非GUI线程)中如果要对GUI进行直接操作就必须使用这种方法,否则会出现同步错误,引起程序非正常终止。
注意这种方法的局限性:多个线程对于GUI的操作严格互锁,交替进行。例如在非GUI线程中有下列代码:
wxMutexGuiEnter();
wxLogDebug(_T("%d..."), i);
wxMutexGuiLeave();
如果下拉主菜单,则Log窗口的输出暂时停止,待菜单回卷后才继续进行。
最安全的方法还是使用自定义命令事件传递,例如在非GUI线程中可以这样:
// send done event to give hint wxCommandEvent doneEvent(wxEVT_COMMAND_MENU_SELECTED, TESTING_THREAD_DONE); wxPostEvent(_frame, doneEvent);
用来停止 work thread。