7.3 使用布局控件进行编程
现在我们开始使用布局控件进行窗口布局,首先,创建一个顶层的布局控件(任何类型的布局控件都可以),使用 wxWindow::SetSizer 函数将它和你的顶层窗口绑定.现在你可以在这个顶层布局控件中放置你的窗口或者其它控件元素了.如果你想让你的顶层窗口的大小适合所有控件所需要的大小,你可以调用 wxSizer::Fit 函数,将那个顶层窗口的指针作为其参数.想要顶层窗口在以后的执行过程中尺寸永远不小于初始尺寸,可以使用 wxSizer:: SetSizeHints 函数,将顶层窗口的指针作为参数,这将使得 wxWindow::SetSizeHints 函数以合适的参数被调用。
除了使用上面介绍的方法依次调用三个函数以外,你还可以直接通过调用 wxWindow::SetSizerAndFit 函数来达到同样的效果,这会使得上面的三个函数依次被调用。
如果在你的 frame 窗口里使用了 panel,你可能不知道到底该给 frame 还是 panel 指定布局控件.这个问题应该这样看,如果你的 frame 窗口中只有一个 panel,所有其它的窗口和控件都是 panel 的子窗口,那么 wxWidgets 已经知道怎样将这个 panel 以合适的大小和位置放置在 frame 上了,因此你只需要给 panel 绑定一个布局控件,以便其可以对所有 panel 的子窗口进行布局.而如果你的 frame 窗口中有多个 panel,那么首先你不得不为 frame 绑定一个布局控件以便对 panel 进行布局,然后针对每个 panel 还应该绑定一个布局控件,以便对 panel 中的子窗口进行布局。
接下来的小节里,我们来依次描述一下每一种布局控件类型以及使用它们的方法:
使用 wxBoxSizer 进行编程
wxBoxSizer 可以将它的容器子元素进行横向或者纵向的排列(具体的排列方式在构造函数中指定).如果采用横向排列的方法,则子元素在纵向上可以指定居中,顶部对齐,底部对齐,如果采用纵向排列的方法,子元素在横向上可以指定居中,左对齐或者右对齐的方式.前一小节提到过的缩放因子用来指示在主要方向上的缩放,比如对于横向排列来说,缩放因子指的就是在横向上子元素的缩放比例. 下图演示了上一小节最后一幅图采用纵向排列的样子。
你可以使用 wxBoxSizer 的 Add 方法增加一个子元素:
// 增加一个窗口
void Add(wxWindow* window, int stretch = 0, int flags = 0,
int border = 0);
// 增加一个布局控件
void Add(wxSizer* window, int stretch = 0, int flags = 0,
int border = 0);
第一个参数是要增加的窗口或者布局控件的指针
第二个参数是前面说过的缩放因子
第三个参数是一个比特位列表,用来指示新增的子元素的对齐和边界的行为.对齐比特位用来指示当垂直排列的布局控件的宽度发生改变时子元素的水平对齐方式,或者是水平排列的布局控件的高度改变时子元素的垂直对齐方式,默认的值为 wxALIGN_LEFT | wxALIGN_TOP,可选的值列举在下表中:
0 | 子元素保留原始大小。 |
---|---|
wxGROW | 子元素随这布局控件一起改变大小. 等同于 wxEXPAND。 |
wxSHAPED | 子元素保持原有比例按缩放因子缩放。 |
wxALIGN_LEFT | 左对齐。 |
wxALIGN_RIGHT | 右对齐。 |
wxALIGN_TOP | 顶端对齐。 |
wxALIGN_BOTTOM | 底部对齐。 |
wxALIGN_CENTER_HORIZONTAL | 水平居中。 |
wxALIGN_CENTER_VERTICAL | 垂直居中。 |
wxALIGN_CENTER | 水平或者垂直居中. wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL。 |
wxLEFT | 边界间隔位于子元素左面。 |
wxRIGHT | 边界间隔位于子元素右面。 |
wxTOP | 边界间隔位于子元素上面。 |
wxBOTTOM | 边界间隔位于子元素下面。 |
wxALL | 边界间隔位于子元素四周.wxLEFT | wxRIGHT | wxTOP | wxBOTTOM。 |
第四个参数指定边界间隔的大小
当然你也可以直接增加一段空白,下面演示了增加空白区域的几种方法:
// 增加一段空白 (旧方法)
void Add(int width, int height, int stretch = 0, int flags = 0,
int border = 0);
// 增加一段固定大小的空白
void AddSpacer(int size);
// 增加一个可缩放的空白
void AddStretchSpacer(int stretch = 1);
上面第二种方法相当于调用 Add(size, size, 0),第三种则相当于调用 Add(0, 0, stretch)。
我们来举这样一个例子,一个对话框包含一个多行文本框和两个位于底端的按钮.我们可以以这样的角度去看待这些窗口,首先是一个顶层的垂直布局,包含一个多行文本框和一个底层的子布局控件,这个子布局控件是一个水平的布局控件,它包含一个 OK 按钮,被放置在左面,和一个 Cancel 按钮,被放置在右面.当对话框的大小发生变化的时候,我们希望多行文本框随着对话框大小的变化而变化,而按钮则保持它们原来的大小,并且在水平方向上居中排列,如下图所示:
下面列出了实现上述对话框所使用的代码:
MyDialog::MyDialog(wxWindow *parent, wxWindowID id,
const wxString &title )
: wxDialog(parent, id, title,
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL );
// 创建一个最小大小为 100x60 的多行文本框
topSizer->Add(
new wxTextCtrl( this, wxID_ANY, "My text.",
wxDefaultPosition, wxSize(100,60), wxTE_MULTILINE),
1, // 垂直方向可缩放,缩放因子为 1
wxEXPAND| // 水平方向可缩放
wxALL, // 四周都由空白边框
10 ); // 空白边框大小为 10
wxBoxSizer *buttonSizer = new wxBoxSizer( wxHORIZONTAL );
buttonSizer->Add(
new wxButton( this, wxID_OK, "OK" ),
0, // 水平方向不可缩放
wxALL, // 四周有空白边框:(注意默认为顶部对齐)
10 ); // 空白边框大小为 10
buttonSizer->Add(
new wxButton( this, wxID_CANCEL, "Cancel" ),
0, // 水平方向不可缩放
wxALL, // 四周有空白边框:(注意默认为顶部对齐)
10 ); // 空白边框大小为 10
topSizer->Add(
buttonSizer,
0, // 垂直方向不可缩放
wxALIGN_CENTER ); // 无边框并且居中对齐
SetSizer( topSizer ); // 绑定对话框和布局控件
topSizer->Fit( this ); // 调用对话框大小
topSizer->SetSizeHints( this ); // 设置对话框最小大小
}
使用 wxStaticBoxSizer 编程
wxStaticBoxSizer 是一个继承自 wxBoxSizer 的布局控件,除了实现 wxBoxSizer 的功能,另外还在整个布局的范围以外增加了一个静态的边框 wxStaticBox,这个 wxStaticBox 需要手动创建并且在 wxStaticBoxSizer 的构造函数中作为参数传入,Add 函数和 wxBoxSizer 的 Add 函数用法相同。
下图演示了使用 wxStaticBoxSizer 对一个复选框进行布局的样子:
对应的代码:
MyDialog::MyDialog(wxWindow *parent, wxWindowID id,
const wxString &title )
: wxDialog(parent, id, title,
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
// 创建一个顶层布局控件
wxBoxSizer* topLevel = new wxBoxSizer(wxVERTICAL);
// 创建静态文本框和静态文本框布局控件
wxStaticBox* staticBox = new wxStaticBox(this,
wxID_ANY, wxT("General settings"));
wxStaticBoxSizer* staticSizer = new wxStaticBoxSizer(staticBox,
wxVERTICAL);
topLevel->Add(staticSizer, 0,
wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
// 在其中增加一个复选框
wxCheckBox* checkBox = new wxCheckBox( this, ID_CHECKBOX,
wxT("&Show splash screen"), wxDefaultPosition, wxDefaultSize);
staticSizer->Add(checkBox, 0, wxALIGN_LEFT |wxALL, 5);
SetSizer(topLevel);
topLevel->Fit(this);
topLevel->SetSizeHints(this);
}
使用 wxGridSizer 编程
wxGridSizer 布局控件可以以二维表的方式排列它的子元素,这个二维表的每个表格的大小都是相同的,都等于最长的那个表格的长度和最高的那个表格的高度.创建一个 wxGridSizer 需要指定它的行数和列数,以及一个额外的行间距和列间距.Add 方法和 wxBoxSizer 的用法相同。
下图演示了一个两行三列的网格布局控件,由于有一个很大的按钮,导致这个格的大小很大,从而导致所有的表格的大小都跟着变大:
代码如下:
MyDialog::MyDialog(wxWindow *parent, wxWindowID id,
const wxString &title )
: wxDialog(parent, id, title,
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
// 创建一个顶层网格布局控件
wxGridSizer* gridSizer = new wxGridSizer(2, 3, 0, 0);
SetSizer(gridSizer);
wxButton* button1 = new wxButton(this, ID_BUTTON1, wxT("One"));
gridSizer->Add(button1, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button2 = new wxButton(this, ID_BUTTON2, wxT("Two (the second button)"));
gridSizer->Add(button2, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button3 = new wxButton(this, ID_BUTTON3, wxT("Three"));
gridSizer->Add(button3, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button4 = new wxButton(this, ID_BUTTON4, wxT("Four"));
gridSizer->Add(button4, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button5 = new wxButton(this, ID_BUTTON5, wxT("Five"));
gridSizer->Add(button5, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button6 = new wxButton(this, ID_BUTTON6, wxT("Six"));
gridSizer->Add(button6, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
gridSizer->Fit(this);
gridSizer->SetSizeHints(this);
}
使用 wxFlexGridSizer 编程
wxFlexGridSizer 同样采用二维表来对其子元素进行布局,和 wxGridSizer 不同的是,它不要求所有的表格的大小都是一样的,只要求同一列上所有表格的宽度是相同的并且同一行上所有表格的高度是相同的,也就是说,行的高度或者列的宽度仅由这一行或者这一列上的子元素决定.另外还可以给行和列指定是否缩放,这意味着当整个布局控件的大小发生变化的时候,可以指定某些行或者列随着整个布局控件的缩放而缩放。
创建一个 wxFlexGridSizer 可以指定行数,列数额外的垂直间距和水平间距.调用 Add 函数的方法和 wxBoxSizer 相同。
下图演示了一个使用 wxFlexGridSizer 进行布局的对话框的样子,正如你看到的那样,和 wxGridSizer 相比整个布局显的更紧凑了,因为中间很宽的那一列不再影响其它列的宽度了。
初始情况下,我们看不出来设置第一列可以改变大小的效果,不过如果我们如下图所示的那样改变这个对话框的水平方向的大小,,我们就可以看到第一列占用了额外增加的空间,并且第一列的子元素也为居中方式显式。
代码如下:
MyDialog::MyDialog(wxWindow *parent, wxWindowID id,
const wxString &title )
: wxDialog(parent, id, title,
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
//创建一个复杂网格布局控件
wxFlexGridSizer* flexGridSizer = new wxFlexGridSizer(2, 3, 0, 0);
this->SetSizer(flexGridSizer);
//让第一列可变大小
flexGridSizer->AddGrowableCol(0);
wxButton* button1 = new wxButton(this, ID_BUTTON1, wxT("One"));
flexGridSizer->Add(button1, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button2 = new wxButton(this, ID_BUTTON2, wxT("Two (the second button)"));
flexGridSizer->Add(button2, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button3 = new wxButton(this, ID_BUTTON3, wxT("Three"));
flexGridSizer->Add(button3, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button4 = new wxButton(this, ID_BUTTON4, wxT("Four"));
flexGridSizer->Add(button4, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button5 = new wxButton(this, ID_BUTTON5, wxT("Five"));
flexGridSizer->Add(button5, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
wxButton* button6 = new wxButton(this, ID_BUTTON6, wxT("Six"));
flexGridSizer->Add(button6, 0, wxALIGN_CENTER_HORIZONTAL|
wxALIGN_CENTER_VERTICAL|wxALL, 5);
flexGridSizer->Fit(this);
flexGridSizer->SetSizeHints(this);
}
使用 wxGridBagSizer 编程
这种布局控件用来模拟现实世界中的那种固定位置和大小的基于布局控件的布局.它将它的子元素按照一个虚拟的网格进行排列,不过子元素的位置是通过 wxGBPosition 对象指定的,对象的大小使用 wxGBSpan 指定,对象的大小不仅限于一个网格。
创建 wxGridBagSizer 的可选参数包括垂直和水平方向的间隔(默认为 0),Add 函数需要提供的参数包括子元素的位置和大小,另外的可选标记和边框大小参数的意义和 wxBoxSizer 是一样的。
下图演示了一个使用 wxGridBagSizer 进行布局的例子,我们指定了其中一个按钮的大小为两个单元列,我们还指定了第二行和第三列的大小是可以变化的,这样当我们改变对话框的大小的时候,就会出现如下面另外一幅图的效果。
相关代码如下:
MyDialog::MyDialog(wxWindow *parent, wxWindowID id,
const wxString &title )
: wxDialog(parent, id, title,
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
wxGridBagSizer* gridBagSizer = new wxGridBagSizer();
SetTopSizer(gridBagSizer);
wxButton* b1 = new wxButton(this, wxID_ANY, wxT("One (0,0)"));
gridBagSizer->Add(b1, wxGBPosition(0, 0));
wxButton* b2 = new wxButton(this, wxID_ANY, wxT("Two (2,2)"));
gridBagSizer->Add(b2, wxGBPosition(2, 2), wxGBSpan(1, 2),
wxGROW);
wxButton* b3 = new wxButton(this, wxID_ANY, wxT("Three (3,2)"));
gridBagSizer->Add(b3, wxGBPosition(3, 2));
wxButton* b4 = new wxButton(this, wxID_ANY, wxT("Four (3,3)"));
gridBagSizer->Add(b4, wxGBPosition(3, 3));
gridBagSizer->AddGrowableRow(3);
gridBagSizer->AddGrowableCol(2);
gridBagSizer->Fit(this);
gridBagSizer->SetSizeHints(this);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论