C++ wxWidgets Sizer 问题(初学者)
C++ wxWidgets Sizer issue (beginner)
我是 wxWidgets 和 sizer 的新手。我在框架构造函数中创建了以下结构
wxBoxSizer *frameSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *deckListLeftSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *deckListRightSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *logOutputSizer = new wxBoxSizer(wxVERTICAL);
// 10 inputs on left
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, -1, wxT(""), wxPoint(-1, -1), wxSize(-1, -1));
deckInputCastables.push_back(textCtrl);
deckListLeftSizer->Add(textCtrl, wxEXPAND );
}
// 10 inputs on right
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, -1, wxT(""), wxPoint(-1, -1), wxSize(-1, -1));
deckInputLands.push_back(textCtrl);
deckListRightSizer->Add(textCtrl, wxEXPAND );
}
logOutput = new wxStaticText(this, wxID_ANY, "Output Terminal", wxPoint(-1, -1), wxSize(-1, -1));
logOutput->SetBackgroundColour(*wxRED);
logOutputSizer->Add(logOutput);
frameSizer->Add(deckListLeftSizer, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5);
frameSizer->Add(deckListRightSizer, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5);
frameSizer->Add(logOutputSizer, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5);
frameSizer->Fit(this);
SetSizer(frameSizer);
这是它的样子:
我想要的是蓝色的 StaticText 来填充它的整个 sizer,因此它占据 window 右边的 1/3,垂直和水平拉伸。此外,每个 TextCtrl 都已垂直拉伸以填充其大小调整器,但不是水平拉伸。当我调整框架大小时,我不想要任何未使用的 space,所以每个 textctrl 都会垂直和水平扩展。我做错了什么?
谢谢
@GeoffL,
首先 - 没有 blue Static Text
只有 Red
一个。
第二个 - 如您所见,wxALIGN_* 选项仅在主要方向上起作用,即传递给 wxBoxSizer() 构造函数的那个。
您可能想要的是(未经测试):
logOutput = new wxStaticText(this, wxID_ANY, "Output Terminal", wxPoint(-1, -1), wxSize(-1, -1));
logOutput->SetBackgroundColour(*wxRED);
logOutputSizer->Add(logOutput, 0, wxEXPAND | wxALIGN_CENTER_VERTICAL, 0 );
wx展开 | wxALIGN_CENTER_VERTICAL 将扩展 sizer 并将控件垂直居中。
你还省略了所有地方的 wxALL 选项,因为它对存在的 wxALIGN 选项没有用。
您也可以在控件构造函数中省略 wxPoint() 和 wxSize() 参数,因为 (-1, -1) 是默认值
除了伊戈尔上面说的,我还要补充两点。首先,我会在将项目添加到 sizer 时使用 wxSizerFlags。我认为这确实有助于阐明用于添加项目的所有数字和选项的作用。其次,通常只有一个项目(例如 logOutputSizer
)的 sizer 没有任何作用。我会摆脱它。
考虑到这两点,为了回答您的问题,有必要对 sizer 标志使用比例参数和 Expand
方法来获得您想要的布局。例如:
wxBoxSizer *frameSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *deckListLeftSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *deckListRightSizer = new wxBoxSizer(wxVERTICAL);
// 10 inputs on left
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
deckInputCastables.push_back(textCtrl);
deckListLeftSizer->Add(textCtrl, wxSizerFlags(1).Expand());
}
// 10 inputs on right
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
deckInputLands.push_back(textCtrl);
deckListRightSizer->Add(textCtrl, wxSizerFlags(1).Expand());
}
logOutput = new wxStaticText(this, wxID_ANY, "Output Terminal");
logOutput->SetBackgroundColour(*wxRED);
frameSizer->Add(deckListLeftSizer, wxSizerFlags(1).Expand());
frameSizer->Add(deckListRightSizer, wxSizerFlags(1).Expand());
frameSizer->Add(logOutput, wxSizerFlags(1).Expand());
frameSizer->Fit(this);
SetSizer(frameSizer);
产生这个输出。
这是一个开始,但它将所有内容捆绑在一起,没有任何分离。要在项目之间添加一点分隔,您可以对 sizer 标志使用 Border 方法。但是,如果您只是使用 wxALL
为每个项目添加所有边框,您将获得多个双边框。例如,如果一个项目既有底部边框,它下面的项目也有顶部边框,则项目之间会有双边框。考虑到这一点,以下代码将在每个项目周围放置一个边框:
wxBoxSizer *frameSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *deckListLeftSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *deckListRightSizer = new wxBoxSizer(wxVERTICAL);
// 10 inputs on left
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
deckInputCastables.push_back(textCtrl);
deckListLeftSizer->Add(textCtrl, wxSizerFlags(1).Expand().Border(wxBOTTOM));
}
// 10 inputs on right
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
deckInputLands.push_back(textCtrl);
deckListRightSizer->Add(textCtrl, wxSizerFlags(1).Expand().Border(wxBOTTOM));
}
logOutput = new wxStaticText(this, wxID_ANY, "Output Terminal");
logOutput->SetBackgroundColour(*wxRED);
frameSizer->Add(deckListLeftSizer, wxSizerFlags(1).Expand().Border(wxTOP|wxLEFT|wxRIGHT));
frameSizer->Add(deckListRightSizer, wxSizerFlags(1).Expand().Border(wxTOP|wxRIGHT));
frameSizer->Add(logOutput, wxSizerFlags(1).Expand().Border(wxTOP|wxBOTTOM|wxRIGHT));
frameSizer->Fit(this);
SetSizer(frameSizer);
这会生成如下布局:
重新排列边框选项以防止出现双边框的方法有很多种,上面的例子只是其中的一种。
最后,使用面板将框架中的所有项目分组通常是个好主意。它提供了更好看的背景,并允许您使用 Tab 键在控件之间移动。这是展示这个想法的最后一个例子:
wxPanel* panel = new wxPanel(this,wxID_ANY);
wxBoxSizer *panelSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *deckListLeftSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *deckListRightSizer = new wxBoxSizer(wxVERTICAL);
// 10 inputs on left
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(panel, wxID_ANY, wxEmptyString);
deckInputCastables.push_back(textCtrl);
deckListLeftSizer->Add(textCtrl, wxSizerFlags(1).Expand().Border(wxBOTTOM));
}
// 10 inputs on right
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(panel, wxID_ANY, wxEmptyString);
deckInputLands.push_back(textCtrl);
deckListRightSizer->Add(textCtrl, wxSizerFlags(1).Expand().Border(wxBOTTOM));
}
logOutput = new wxStaticText(panel, wxID_ANY, "Output Terminal");
logOutput->SetBackgroundColour(*wxRED);
panelSizer->Add(deckListLeftSizer, wxSizerFlags(1).Expand().Border(wxTOP|wxLEFT|wxRIGHT));
panelSizer->Add(deckListRightSizer, wxSizerFlags(1).Expand().Border(wxTOP|wxRIGHT));
panelSizer->Add(logOutput, wxSizerFlags(1).Expand().Border(wxTOP|wxBOTTOM|wxRIGHT));
panel->SetSizerAndFit(panelSizer);
this->Fit();
这会生成此布局:
不需要为面板使用 sizer,因为当框架只有一个子项时,该子项会自动扩展以填充框架的所有 space。
我是 wxWidgets 和 sizer 的新手。我在框架构造函数中创建了以下结构
wxBoxSizer *frameSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *deckListLeftSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *deckListRightSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *logOutputSizer = new wxBoxSizer(wxVERTICAL);
// 10 inputs on left
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, -1, wxT(""), wxPoint(-1, -1), wxSize(-1, -1));
deckInputCastables.push_back(textCtrl);
deckListLeftSizer->Add(textCtrl, wxEXPAND );
}
// 10 inputs on right
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, -1, wxT(""), wxPoint(-1, -1), wxSize(-1, -1));
deckInputLands.push_back(textCtrl);
deckListRightSizer->Add(textCtrl, wxEXPAND );
}
logOutput = new wxStaticText(this, wxID_ANY, "Output Terminal", wxPoint(-1, -1), wxSize(-1, -1));
logOutput->SetBackgroundColour(*wxRED);
logOutputSizer->Add(logOutput);
frameSizer->Add(deckListLeftSizer, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5);
frameSizer->Add(deckListRightSizer, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5);
frameSizer->Add(logOutputSizer, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5);
frameSizer->Fit(this);
SetSizer(frameSizer);
这是它的样子:
我想要的是蓝色的 StaticText 来填充它的整个 sizer,因此它占据 window 右边的 1/3,垂直和水平拉伸。此外,每个 TextCtrl 都已垂直拉伸以填充其大小调整器,但不是水平拉伸。当我调整框架大小时,我不想要任何未使用的 space,所以每个 textctrl 都会垂直和水平扩展。我做错了什么?
谢谢
@GeoffL,
首先 - 没有 blue Static Text
只有 Red
一个。
第二个 - 如您所见,wxALIGN_* 选项仅在主要方向上起作用,即传递给 wxBoxSizer() 构造函数的那个。
您可能想要的是(未经测试):
logOutput = new wxStaticText(this, wxID_ANY, "Output Terminal", wxPoint(-1, -1), wxSize(-1, -1));
logOutput->SetBackgroundColour(*wxRED);
logOutputSizer->Add(logOutput, 0, wxEXPAND | wxALIGN_CENTER_VERTICAL, 0 );
wx展开 | wxALIGN_CENTER_VERTICAL 将扩展 sizer 并将控件垂直居中。
你还省略了所有地方的 wxALL 选项,因为它对存在的 wxALIGN 选项没有用。
您也可以在控件构造函数中省略 wxPoint() 和 wxSize() 参数,因为 (-1, -1) 是默认值
除了伊戈尔上面说的,我还要补充两点。首先,我会在将项目添加到 sizer 时使用 wxSizerFlags。我认为这确实有助于阐明用于添加项目的所有数字和选项的作用。其次,通常只有一个项目(例如 logOutputSizer
)的 sizer 没有任何作用。我会摆脱它。
考虑到这两点,为了回答您的问题,有必要对 sizer 标志使用比例参数和 Expand
方法来获得您想要的布局。例如:
wxBoxSizer *frameSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *deckListLeftSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *deckListRightSizer = new wxBoxSizer(wxVERTICAL);
// 10 inputs on left
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
deckInputCastables.push_back(textCtrl);
deckListLeftSizer->Add(textCtrl, wxSizerFlags(1).Expand());
}
// 10 inputs on right
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
deckInputLands.push_back(textCtrl);
deckListRightSizer->Add(textCtrl, wxSizerFlags(1).Expand());
}
logOutput = new wxStaticText(this, wxID_ANY, "Output Terminal");
logOutput->SetBackgroundColour(*wxRED);
frameSizer->Add(deckListLeftSizer, wxSizerFlags(1).Expand());
frameSizer->Add(deckListRightSizer, wxSizerFlags(1).Expand());
frameSizer->Add(logOutput, wxSizerFlags(1).Expand());
frameSizer->Fit(this);
SetSizer(frameSizer);
产生这个输出。
这是一个开始,但它将所有内容捆绑在一起,没有任何分离。要在项目之间添加一点分隔,您可以对 sizer 标志使用 Border 方法。但是,如果您只是使用 wxALL
为每个项目添加所有边框,您将获得多个双边框。例如,如果一个项目既有底部边框,它下面的项目也有顶部边框,则项目之间会有双边框。考虑到这一点,以下代码将在每个项目周围放置一个边框:
wxBoxSizer *frameSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *deckListLeftSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *deckListRightSizer = new wxBoxSizer(wxVERTICAL);
// 10 inputs on left
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
deckInputCastables.push_back(textCtrl);
deckListLeftSizer->Add(textCtrl, wxSizerFlags(1).Expand().Border(wxBOTTOM));
}
// 10 inputs on right
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString);
deckInputLands.push_back(textCtrl);
deckListRightSizer->Add(textCtrl, wxSizerFlags(1).Expand().Border(wxBOTTOM));
}
logOutput = new wxStaticText(this, wxID_ANY, "Output Terminal");
logOutput->SetBackgroundColour(*wxRED);
frameSizer->Add(deckListLeftSizer, wxSizerFlags(1).Expand().Border(wxTOP|wxLEFT|wxRIGHT));
frameSizer->Add(deckListRightSizer, wxSizerFlags(1).Expand().Border(wxTOP|wxRIGHT));
frameSizer->Add(logOutput, wxSizerFlags(1).Expand().Border(wxTOP|wxBOTTOM|wxRIGHT));
frameSizer->Fit(this);
SetSizer(frameSizer);
这会生成如下布局:
重新排列边框选项以防止出现双边框的方法有很多种,上面的例子只是其中的一种。
最后,使用面板将框架中的所有项目分组通常是个好主意。它提供了更好看的背景,并允许您使用 Tab 键在控件之间移动。这是展示这个想法的最后一个例子:
wxPanel* panel = new wxPanel(this,wxID_ANY);
wxBoxSizer *panelSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer *deckListLeftSizer = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *deckListRightSizer = new wxBoxSizer(wxVERTICAL);
// 10 inputs on left
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(panel, wxID_ANY, wxEmptyString);
deckInputCastables.push_back(textCtrl);
deckListLeftSizer->Add(textCtrl, wxSizerFlags(1).Expand().Border(wxBOTTOM));
}
// 10 inputs on right
for ( int i = 0; i < 10; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(panel, wxID_ANY, wxEmptyString);
deckInputLands.push_back(textCtrl);
deckListRightSizer->Add(textCtrl, wxSizerFlags(1).Expand().Border(wxBOTTOM));
}
logOutput = new wxStaticText(panel, wxID_ANY, "Output Terminal");
logOutput->SetBackgroundColour(*wxRED);
panelSizer->Add(deckListLeftSizer, wxSizerFlags(1).Expand().Border(wxTOP|wxLEFT|wxRIGHT));
panelSizer->Add(deckListRightSizer, wxSizerFlags(1).Expand().Border(wxTOP|wxRIGHT));
panelSizer->Add(logOutput, wxSizerFlags(1).Expand().Border(wxTOP|wxBOTTOM|wxRIGHT));
panel->SetSizerAndFit(panelSizer);
this->Fit();
这会生成此布局:
不需要为面板使用 sizer,因为当框架只有一个子项时,该子项会自动扩展以填充框架的所有 space。