首页 > 解决方案 > 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);
}

标签: c++wxwidgets

解决方案


直到刚才我才意识到这一点,但是根据文档,当您在顶级窗口上调用 Layout 时

使用窗口大小调整子级布局或调整窗口唯一子级的大小以覆盖其整个区域。

此类重写基类 Layout() 方法以检查此窗口是否仅包含一个子窗口——通常是这种情况,wxPanel 通常被创建为 wxTopLevelWindow 的唯一子窗口——如果是这种情况,则调整此子窗口的大小覆盖整个客户区。

所以我猜想在只有 1 个子窗口的框架上调用 Layout 将不起作用,因为该调用只会尝试调整面板的大小,但面板不会改变大小,因此不会尝试重新布局其新子窗口。

似乎有效的方法是添加类似

this->main_panel->Layout();

到结束MullSimple_2Frame::addNeedGUI()。这会强制在面板而不是框架上重新布局。

或者,根据文档,您可以只使用尺寸大小的框架并只添加main_panel到它。但正如我在另一个答案中所说,通常只有一个窗口的大小调整器没有多大意义。


推荐阅读