7.4 更多关于布局的话题

这一节里,我们将讨论一些更深入的话题,在进行窗口布局的时候,你可以在脑子里考虑这些事情.

对话框单位

尽管布局控件可以让基本控件的大小随着平台的不同语言的不同进行相应的改变,但是有些情况下,你还是需要手动指定控件的大小(比如在对话框中增加一个列表框的时候).如果你希望这些手动指定的大小也随着平台的不同字体的不同进行相应的变化,你应该使用对话框单位来代替象素单位.对话框单位是基于应用程序当前字体的字符宽度和高度所取的一个平均值的,因此总能很好的和当前的字体对应.wxWidgets也提供了相关的转换函数包括: ConvertDialogToPixels,ConvertPixelsToDialog等,还包括一个宏wxDLG_UNIT(window, ptOrSz)用来直接将使用对话框单位wxPoint对象或者wxSize对象转换为象素单位.所以你可以使用下面的代码来指定那些你不得不指定的控件大小:

wxListBox* listBox = new wxListBox(parent, wxID_ANY,
    wxDefaultPosition, wxDLG_UNIT(parent, wxSize(60, 20)));

你也可以在XRC文件中使用对话框单位,只需要在相应的值前面增加一个"d"字符就可以了.

平台自适应布局

尽管不同平台的对话框的绝大部分都是相同的,但是在风格上确是存在着一些不同.比如在Windows和Linnx平台上,右对齐或者居中放置的OK,Cancel和Help按钮都是可以接受的,但是在Mac OsX上,Help按钮通常位于左面,而Cancel和OK按钮则通常依序位于右面.

要作到这种不同平台上按钮顺序的自适应,你需要使用wxStdDialogButtonSizer布局控件,这个控件继承自wxBoxSizer,因此使用方法并没有太大的不同,只是它依照平台的不同对某些按钮进行特殊的排列.

这个布局控件的构造函数没有参数,要增加按钮可以使用两种方法:传递按钮指针给AddButton函数,或者(日过你没有使用标准的标识符的话),使用SetAffirmativeButton, SetNegativeButton, and SetCancelButton来设置按钮的特性.如果使用AddButton,那么按钮应使用下面的这些标识符: wxID_OK, wxID_YES, wxID_CANCEL, wxID_NO, wxID_SAVE, wxID_APPLY, wxID_HELP和 wxID_CONTEXT_HELP.

然后,在所有的按钮都增加到布局控件以后,调用Realize函数以便布局控件调整按钮的顺序,如下面的代码所示:

wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
dialog->SetSizer(topSizer);
wxButton* ok = new wxButton(dialog, wxID_OK);
wxButton* cancel = new wxButton(dialog, wxID_CANCEL);
wxButton* help = new wxButton(dialog, wxID_HELP);
wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer;
topSizer->Add(buttonSizer, 0, wxEXPAND|wxALL, 10);
buttonSizer->AddButton(ok);
buttonSizer->AddButton(cancel);
buttonSizer->AddButton(help);
buttonSizer->Realize();

或者作为一个更方便的手段,你可以使用wxDialog::CreateButtonSizer函数,它基于一些按钮标记的列表来自动创建平台自适应的按钮,并将其放在一个布局控件中,如果你查看src/generic目录中的对话框代码的实现,你会发现大量的地方使用了 CreateButtonSizer函数.这个函数支持的按钮标记如下表所示:

wxYES_NO 增加YES和No按钮各一个.
wxYES 增加一个标识符为wxID_YES的Yes按钮.
wxNO 增加一个标识符为wxID_NO的No按钮.
wxNO_DEFAULT 让No按钮作为默认按钮,否则Yes或OK按钮将成为默认按钮.
wxOK 增加一个标识符为wxID_OK的OK按钮.
wxCANCEL 增加一个标识符为wxID_CANCEL的Cancel按钮.
wxAPPLY 增加一个标识符为wxID_APPLY的Apply按钮.
wxHELP 增加一个标识符为wxID_HELP的Help按钮.

使用CreateButtonSizer函数,上面例子中的代码可以简化为:

wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
dialog->SetSizer(topSizer);
topSizer->Add(CreateButtonSizer(wxOK|wxCANCEL|wxHELP), 0,
              wxEXPAND|wxALL, 10);

另外一种给不同的平台指定不同布局的方法是在XRC文件中指定平台属性.其中的参数部分的值可以通过一个"|"符号加上unix, win,mac或者os2来指定特定平台上的界面布局.在应用程序运行的时候,XRC文件将只会创建那些和当前运行平台符合的控件.另外如果没有使用 XRC的话,DialogBlocks程序还支持针对不同的平台生成预置条件的C++代码.

当然你也可以给不同的平台指定不同的XRC文件,不过这样作的话维护起来就有点不方便了.

动态布局

有时候你可能需要动态更改对话框的布局,比如你可以会增加一个"Detail"按钮,当这个按钮被按下的时候显式更多的选项,当然你可以使用平常的办法,调用wxWindow::Show函数来隐藏某个控件,不过wxSizer也提供了一个单独的方法,你可以使用wxSizer:: Show函数并且传递False参数,以便告诉wxSizer不要计算其中的窗口的大小,当然调用这个函数以后,你需要调用wxSizer:: Layout函数来强制更新对应的窗口.