wxWidgets:如何改变和显示sizer的内容

wxWidgets: How to change and display content of sizer

在我的代码中,我拥有 MyFrame class,我在其中创建了包含 wxBitmapToggleButton 指针的 wxGridSizer。调用 MyFrame 构造函数后一切正常,但是当我需要更改 sizer 内容时(使用事件函数之一)我只能看到一个 wxBitmapToggleButton 对象。

class MyFrame : public wxFrame {
public:
    MyFrame();
private:
    // own classes needed in application
    GameBoard *gb;
    Player* player;
    bool lightTheme;
    wxGridSizer *gridSizer; // sizer which contains these buttons
    std::vector<wxBitmapToggleButton *> cardImages; // stores wxBitmapToggleButtons pointers managed by gridSizer
    void OnCardSelect(wxCommandEvent& event); // event function
    void displayImages(); // function which adds wxBitmapToggleButtons to sizer
};

MyFrame::MyFrame() : wxFrame(NULL, wxID_ANY, "SET Card Game") {
    // ...
    // init GameBoard, Player and lightTheme
    topSizer = new wxBoxSizer(wxVERTICAL);
    gridSizer = new wxGridSizer(4, 6, 0, 0);
    displayImages(); // create and display wxBitmapToggleButtons in sizer
    // ...
    // some other layout
    topSizer -> Add(gridSizer);
    this -> SetSizer(topSizer);
    topSizer -> Fit(this);
    topSizer -> SetSizeHints(this);
}

void MyFrame::OnCardSelect(wxCommandEvent& event) {
    wxBitmapToggleButton *selectedCard = dynamic_cast<wxBitmapToggleButton *>(event.GetEventObject());
    player -> toggleChosen(int(selectedCard -> GetId()));
    if(player -> readyToCheck()) {
        const std::vector<int> chosen = player -> getChosen();
        for(int card : chosen) {
            cardImages[card] -> SetValue(false);
            player -> toggleChosen(card);
        }
        if(gb -> isOk(chosen)) {
            // do some modifications on GameBoard
            displayImages();
        }
    }
}
// most important method, it should display card images stored in GameBoard
void MyFrame::displayImages() {
    const std::vector<Card> table = gb -> getTable();
    for(wxBitmapToggleButton* ptr : cardImages) {
    // delete all old wxBitmapToggleButtons from sizer
        gridSizer -> Detach(ptr);
        ptr -> Destroy();
    }
    cardImages.clear();
    for(int i = 0; i < table.size(); i++) {
        wxBitmap bmp = getCardImage(table[i].getCode(), lightTheme, 0.1); // load image
        cardImages.push_back(new wxBitmapToggleButton(this, i, bmp, wxDefaultPosition, wxSize(bmp.GetWidth() + 10, bmp.GetHeight() + 10))); // create wxBitmapTogglebutton from loaded image ...
        gridSizer -> Add(cardImages[i], 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxALL, 5); // ... and add it to sizer
        this -> Connect(i, wxEVT_TOGGLEBUTTON, wxCommandEventHandler(MyFrame::OnCardSelect)); // connect created button to event
    }
}

这些图像仅在调用构造函数和调用事件函数后显示结果: https://postimg.cc/gallery/uzc2zmii/

我认为您只需要在 displayImages() 方法的末尾调用 Layout();。正如文档所述:

Call this to force layout of the children anew, e.g. after having added a child to or removed a child (window, other sizer or space) from the sizer

此外,在 displayImages 方法中,我认为您可以只调用 gridSizer->Clear(true); 而不是使用 for 循环来清除 sizer 的先前内容。