c++ - wxWidgets 程序创建后动态创建新的 Sizer,渲染不正确(新手)
问题描述
我有以下 GUI,它是在当前位置用一个空的 sizer 创建的。尺寸器可能是折叠的,因为它的比例是 0,但我是这样画的,所以你可以看到它。
当您单击“+需要”按钮时,程序会创建一个带有一堆按钮和控件的新 sizer,然后将其添加到这个 sizer。然而,它们并没有出现在它们应该出现的地方。如您在此处看到的,新的 sizer 及其内容实际上已折叠并位于左上角。
这显然不是我想要的。但是,当我通过单击并拖动其中一个边缘来调整窗口大小时,所有内容都会弹出到位:
我试过调用我能想到的 ->Layout() 和 ->Fit() 的每一个组合,但我就是无法让它工作。这是在程序加载时创建 GUI 的代码,由框架构造函数调用。它创建“needs_sizer_wrap”,它是 BoxSizer,一开始是空的,新的动态尺寸器在按钮单击时被添加到。注意在图像中它显示为“needsSizerWrap”,但代码实际上是“needs_sizer_wrap”
// creates the basic GUI
void MullSimple_2Frame::createGUI()
{
// mainPanel
main_panel = new wxPanel(this, wxID_ANY);
// mainPanelSizer (vertical)
wxBoxSizer *main_panel_sizer = new wxBoxSizer(wxVERTICAL);
// deckInfo (horizontal)
// deck data along top like deck name, deck id, deck set
wxBoxSizer *deck_info_sizer = new wxBoxSizer(wxHORIZONTAL);
main_panel_sizer->Add(deck_info_sizer, wxSizerFlags(0).Expand());
// DECK ID
// label
wxStaticText *label1 = new wxStaticText(main_panel, wxID_ANY, "DECK ID: ");
deck_info_sizer->Add(label1, wxSizerFlags(0).Expand());
// value
deck_info_id = new wxStaticText(main_panel, wxID_ANY, "-1");
deck_info_sizer->Add(deck_info_id, wxSizerFlags(0).Expand());
// DECK NAME
// label
wxStaticText *label2 = new wxStaticText(main_panel, wxID_ANY, ", NAME: ");
deck_info_sizer->Add(label2, wxSizerFlags(0).Expand());
// value
deck_info_name = new wxTextCtrl(main_panel, wxID_ANY, "");
deck_info_name->Bind(wxEVT_TEXT, &MullSimple_2Frame::ChangeDeckValue, this);
deck_info_sizer->Add(deck_info_name, wxSizerFlags(0).Expand());
// DECK SET
// label
wxStaticText *label3 = new wxStaticText(main_panel, wxID_ANY, ", SET: ");
deck_info_sizer->Add(label3, wxSizerFlags(0).Expand());
// value
deck_info_set = new wxTextCtrl(main_panel, wxID_ANY, "");
deck_info_set->Bind(wxEVT_TEXT, &MullSimple_2Frame::ChangeDeckValue, this);
deck_info_sizer->Add(deck_info_set, wxSizerFlags(0).Expand());
// DECK SAVED
// can't do stuff unless the deck is saved. saving allows us to set data_vars.
// label
wxStaticText *label4 = new wxStaticText(main_panel, wxID_ANY, ", SAVED: ");
deck_info_sizer->Add(label4, wxSizerFlags(0).Expand());
// value
deck_info_if_saved = new wxStaticText(main_panel, wxID_ANY, "FALSE");
deck_info_sizer->Add(deck_info_if_saved, wxSizerFlags(0).Expand());
// progSizer (horizontal)
// program contains 3 "columns"
wxBoxSizer *prog_sizer = new wxBoxSizer(wxHORIZONTAL);
main_panel_sizer->Add(prog_sizer, wxSizerFlags(1).Expand());
// PROGRAM COLUMN 1: DECK CASTABLES
// castables column
wxBoxSizer *deck_casts_sizer = new wxBoxSizer(wxVERTICAL);
prog_sizer->Add(deck_casts_sizer, wxSizerFlags(1).Expand());
// castables title
wxStaticText *deck_casts_title = new wxStaticText(main_panel, wxID_ANY, "Castables", wxDefaultPosition, wxSize(-1, 30), wxALIGN_CENTER_HORIZONTAL);
deck_casts_title->SetBackgroundColour(*wxYELLOW);
deck_casts_sizer->Add(deck_casts_title, wxSizerFlags(0).Expand());
// castables content
for ( int i = 0; i < 25; i++ )
{
// need to set a size so that they're small enough to all fit on my crappy laptio
wxTextCtrl *text_ctrl = new wxTextCtrl(main_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 20));
text_ctrl->Bind(wxEVT_TEXT, &MullSimple_2Frame::ChangeDeckValue, this);
deck_castable_inputs.push_back(text_ctrl);
deck_casts_sizer->Add(text_ctrl, wxSizerFlags(0).Expand());
}
// PROGRAM COLUMN 2: DECK LANDS
wxBoxSizer *deck_lands_sizer = new wxBoxSizer(wxVERTICAL);
prog_sizer->Add(deck_lands_sizer, wxSizerFlags(1).Expand());
// lands title
wxStaticText *deck_lands_title = new wxStaticText(main_panel, wxID_ANY, "Lands", wxDefaultPosition, wxSize(-1, 30), wxALIGN_CENTER_HORIZONTAL);
deck_lands_title->SetBackgroundColour(*wxGREEN);
deck_lands_sizer->Add(deck_lands_title, wxSizerFlags(0).Expand());
// lands content
for ( int i = 0; i < 25; i++ )
{
wxTextCtrl *text_ctrl = new wxTextCtrl(main_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 20));
text_ctrl->Bind(wxEVT_TEXT, &MullSimple_2Frame::ChangeDeckValue, this);
deck_land_inputs.push_back(text_ctrl);
deck_lands_sizer->Add(text_ctrl, wxSizerFlags(0).Expand());
}
// PROGRAM COLUMN 3: HAND
wxBoxSizer *hand_sizer = new wxBoxSizer(wxVERTICAL);
prog_sizer->Add(hand_sizer, wxSizerFlags(1).Expand());
// hand title
wxStaticText *hand_title = new wxStaticText(main_panel, wxID_ANY, "Hand", wxDefaultPosition, wxSize(-1, 30), wxALIGN_CENTER_HORIZONTAL);
hand_title->SetBackgroundColour(*wxBLUE);
hand_sizer->Add(hand_title, wxSizerFlags(0).Expand());
// hand content
for ( int i = 0; i < 7; i++ )
{
wxTextCtrl *text_ctrl = new wxTextCtrl(main_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 20));
hand_inputs.push_back(text_ctrl);
hand_sizer->Add(text_ctrl, wxSizerFlags(0).Expand());
}
// PROGRAM COLUMN 4: MULL OPTS
wxBoxSizer *mull_opts_sizer = new wxBoxSizer(wxVERTICAL);
prog_sizer->Add(mull_opts_sizer, wxSizerFlags(3).Expand());
// MULL OPTS HORIZONTAL 1: MULL_OPTS_BUTTONS
wxBoxSizer *mull_opts_but_sizer = new wxBoxSizer(wxHORIZONTAL);
mull_opts_sizer->Add(mull_opts_but_sizer, wxSizerFlags(0).Expand());
// add need button
mull_opts_but_add_need = new wxButton(main_panel, wxID_ANY, "+ Need");
mull_opts_but_add_need->SetMinSize(wxSize(-1, 50));
mull_opts_but_add_need->Bind(wxEVT_BUTTON, &MullSimple_2Frame::addNeedGlobal, this);
mull_opts_but_sizer->Add(mull_opts_but_add_need, wxSizerFlags(1).Expand());
// remove need button
mull_opts_but_remove_need = new wxButton(main_panel, wxID_ANY, "- Need");
mull_opts_but_remove_need->SetMinSize(wxSize(-1, 50));
mull_opts_but_remove_need->Bind(wxEVT_BUTTON, &MullSimple_2Frame::removeNeedGlobal, this);
mull_opts_but_sizer->Add(mull_opts_but_remove_need, wxSizerFlags(1).Expand());
// reset all button
mull_opts_but_reset_needs = new wxButton(main_panel, wxID_ANY, "Reset All");
mull_opts_but_reset_needs->SetMinSize(wxSize(-1, 50));
mull_opts_but_reset_needs->Bind(wxEVT_BUTTON, &MullSimple_2Frame::resetNeedsGlobal, this);
mull_opts_but_sizer->Add(mull_opts_but_reset_needs, wxSizerFlags(1).Expand());
// calculate button
mull_opts_but_calculate = new wxButton(main_panel, wxID_ANY, "Calculate");
mull_opts_but_calculate->SetMinSize(wxSize(-1, 50));
mull_opts_but_calculate->Bind(wxEVT_BUTTON, &MullSimple_2Frame::calcNeedsGlobal, this);
mull_opts_but_sizer->Add(mull_opts_but_calculate, wxSizerFlags(1).Expand());
// needs sizer wrap, contains the needs, starts out empty
needs_sizer_wrap = new wxBoxSizer(wxVERTICAL);
mull_opts_sizer->Add(needs_sizer_wrap, wxSizerFlags(0).Expand());
// MULL OPTS HORIZONTAL 2: NEEDS (in a stack)
// Make on base need we can use as a model
// at the bottom of the main panel stretches the log output
// fixed height so set proportion 0
wxBoxSizer *output_sizer = new wxBoxSizer(wxHORIZONTAL);
main_panel_sizer ->Add(output_sizer, wxSizerFlags(0).Expand());
log_output = new wxTextCtrl(main_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 100), wxTE_MULTILINE);
log_output->SetBackgroundColour(*wxYELLOW);
output_sizer ->Add(log_output, wxSizerFlags(1).Expand());
main_panel->SetSizerAndFit(main_panel_sizer);
this->Fit();
}
这是在单击 + 需要按钮时插入附加大小调整器的代码
void MullSimple_2Frame::addNeedGUI()
{
wxBoxSizer *need_sizer = new wxBoxSizer(wxVERTICAL);
// NEED ITEM HORIZONTAL 1: grid of filters, 4 columns
// we'll put the same filters for every deck (for now),
// and no custom filter ability
std::vector<std::string> filters_in_deck;
filters_in_deck.push_back("Land");
...
// fixed 2 rows with 4 cols in each row
wxGridSizer *base_need_filters_sizer = new wxGridSizer(2, 4, 0, 0);
need_sizer->Add(base_need_filters_sizer, wxSizerFlags(0).Expand());
for ( unsigned int i = 0; i < filters_in_deck.size(); i++ )
{
wxCheckBox *filter_check = new wxCheckBox(this->main_panel, wxID_ANY, myHelpFxns::ToWxString(filters_in_deck[i]));
base_need_filters_sizer->Add(filter_check, wxSizerFlags(1).Expand());
}
// NEED ITEM HORIZONTAL 2: line options
wxBoxSizer *base_need_line_sizer = new wxBoxSizer(wxHORIZONTAL);
need_sizer->Add(base_need_line_sizer, wxSizerFlags(0).Expand());
// line item -> "("
wxButton *need_line_open_brack_but = new wxButton(this->main_panel, wxID_ANY, "(", wxDefaultPosition, wxSize(50, -1));
base_need_line_sizer->Add(need_line_open_brack_but, wxSizerFlags(0).Expand());
// line item -> apply filters logic (any/all)
wxComboBox *need_line_apply_filters_combo = new wxComboBox(this->main_panel, wxID_ANY);
need_line_apply_filters_combo->Append("Any");
need_line_apply_filters_combo->Append("All");
base_need_line_sizer->Add(need_line_apply_filters_combo, wxSizerFlags(1).Expand());
// line item -> cards to draw combo box
wxComboBox *need_line_cards_draw_combo = new wxComboBox(this->main_panel, wxID_ANY);
need_line_cards_draw_combo->Append("1 to Draw");
...
base_need_line_sizer->Add(need_line_cards_draw_combo, wxSizerFlags(1).Expand());
// line item -> source colors combo
wxComboBox *need_line_source_colors_combo = new wxComboBox(this->main_panel, wxID_ANY);
need_line_source_colors_combo->Append("Any");
...
base_need_line_sizer->Add(need_line_source_colors_combo, wxSizerFlags(1).Expand());
// line item -> cost colors combo
wxComboBox *need_line_cost_colors_combo = new wxComboBox(this->main_panel, wxID_ANY);
need_line_cost_colors_combo->Append("Any");
...
base_need_line_sizer->Add(need_line_cost_colors_combo, wxSizerFlags(1).Expand());
// line item -> cost amount combo
wxComboBox *need_line_cost_amount_combo = new wxComboBox(this->main_panel, wxID_ANY);
need_line_cost_amount_combo->Append("Any");
...
base_need_line_sizer->Add(need_line_cost_amount_combo, wxSizerFlags(1).Expand());
// line item -> specific card input
wxTextCtrl *need_line_specific_card_input = new wxTextCtrl(this->main_panel, wxID_ANY, wxEmptyString);
base_need_line_sizer->Add(need_line_specific_card_input, wxSizerFlags(1).Expand());
// line item -> ")"
wxButton *need_line_close_brack_but = new wxButton(this->main_panel, wxID_ANY, ")", wxDefaultPosition, wxSize(50, -1));
base_need_line_sizer->Add(need_line_close_brack_but, wxSizerFlags(0).Expand());
// line item -> "AND"
wxButton *need_line_and_but = new wxButton(this->main_panel, wxID_ANY, "AND", wxDefaultPosition, wxSize(50, -1));
base_need_line_sizer->Add(need_line_and_but, wxSizerFlags(0).Expand());
// line item -> "OR"
wxButton *need_line_or_but = new wxButton(this->main_panel, wxID_ANY, "OR", wxDefaultPosition, wxSize(50, -1));
base_need_line_sizer->Add(need_line_or_but, wxSizerFlags(0).Expand());
// NEED ITEM HORIZONTAL 3: NEED INLINE BUTTONS
wxBoxSizer *base_need_buts_sizer = new wxBoxSizer(wxHORIZONTAL);
need_sizer->Add(base_need_buts_sizer, wxSizerFlags(0).Expand());
wxButton *need_but_add_need_after_but = new wxButton(this->main_panel, wxID_ANY, "+");
base_need_buts_sizer->Add(need_but_add_need_after_but, wxSizerFlags(0).Expand());
wxButton *need_but_remove_this_but = new wxButton(this->main_panel, wxID_ANY, "-");
base_need_buts_sizer->Add(need_but_remove_this_but, wxSizerFlags(0).Expand());
needs_sizer_wrap->Add(need_sizer, wxSizerFlags(0).Expand().Border(wxALL, 10));
//needs_sizer_wrap->Layout();
//needs_sizer_wrap->Fit(need_sizer);
}
解决方案
直到刚才我才意识到这一点,但是根据文档,当您在顶级窗口上调用 Layout 时
使用窗口大小调整子级布局或调整窗口唯一子级的大小以覆盖其整个区域。
此类重写基类 Layout() 方法以检查此窗口是否仅包含一个子窗口——通常是这种情况,wxPanel 通常被创建为 wxTopLevelWindow 的唯一子窗口——如果是这种情况,则调整此子窗口的大小覆盖整个客户区。
所以我猜想在只有 1 个子窗口的框架上调用 Layout 将不起作用,因为该调用只会尝试调整面板的大小,但面板不会改变大小,因此不会尝试重新布局其新子窗口。
似乎有效的方法是添加类似
this->main_panel->Layout();
到结束MullSimple_2Frame::addNeedGUI()
。这会强制在面板而不是框架上重新布局。
或者,根据文档,您可以只使用尺寸大小的框架并只添加main_panel
到它。但正如我在另一个答案中所说,通常只有一个窗口的大小调整器没有多大意义。
推荐阅读
- c# - C# 从字符串中设置字段
- microsoft-graph-api - Microsoft Teams 会议应用程序是否适用于实时活动?
- amazon-web-services - A Global Variable(State) in AWS for Serverless Orchestration
- python - Pass input to commands run in terminal with python
- c++ - winsock 可以使用 linux 之类的 write 调用写入文件和套接字吗?
- c# - 本机 Xamarin 中的 Device.StartTimer 等效项
- c# - 如何将 ASP.NET Core 身份链接到另一个实体?
- c# - 使用 C# 备份和恢复电源计划
- arrays - 如何将表 1 上的结构数组与 BigQuery 中表 2 的普通列连接起来
- robotframework - 我应该使用强制标签还是默认标签