Search code examples
c++wxwidgets

Having trouble laying out wxWidgets frame


I am trying to create some dialogs using wxWidgets. I am struggling with how to get them to layout in an appealing and standard way. In the example below I am trying to create box layout with a row of ok & cancel button below it. The image below it is what I actually get.

Form2::Form2() :wxFrame(nullptr, wxID_ANY, L"Simple form")
{
    wxBoxSizer* bSizer1;
    bSizer1 = new wxBoxSizer(wxVERTICAL);

    wxStaticBox* box = new wxStaticBox(this, wxID_ANY, "BOX");
    wxStaticBoxSizer *sz = new wxStaticBoxSizer(box, wxVERTICAL);
    wxBoxSizer* box2 = new wxBoxSizer(wxHORIZONTAL);
    box2->Add(new wxStaticText(box, wxID_ANY, "static text"));
    box2->AddSpacer(10);
    newText = new wxTextCtrl(box, wxID_ANY, "add me");
    box2->Add(newText);
    box2->AddSpacer(10);
    wxButton* btnAdd = new wxButton(box, wxID_ANY, "Add");
    box2->Add(btnAdd);
    sz->Add(box2,0, wxALL, 5);
    lstFile = new wxListBox(box, wxID_ANY, wxDefaultPosition, wxSize(400,500), 0, NULL, wxLB_SINGLE | wxLB_NEEDED_SB);
    sz->Add(lstFile, 0, wxALL, 5);
    bSizer1->Add(sz);

    wxStdDialogButtonSizer* stb = new wxStdDialogButtonSizer( );
    stb->AddButton(new wxButton(this, wxID_OK));
    stb->AddButton(new wxButton(this, wxID_CANCEL));
    stb->Realize();
    bSizer1->Add(stb);

    this->SetSizer(bSizer1);
    this->Layout();
    this->Centre(wxBOTH);           
}

enter image description here

First of all, I don't understand why I need the box2->AddSpacer commands, when according to the documentation I should have been able to add left padding to the TextControl and Button by using wxLEFT, 10 in their respective Add commands, but that didn't do anything.

Next issue is that the 3 objects on the top row should be aligned vertically, but setting vertical alignment on all 3 components like this box2->Add(newText, wxALIGN_CENTER);''' orwxALIGN_CENTER_VERTICAL``` merely changes the spacing between them.

enter image description here

The most serious issue is that the ok and cancel buttons don't appear at all. If I remove the bSizer1->Add(stb) command the OK button appears at the very top, presumably covering the Cancel button, but I can't be sure.

I dont' know where to look for help. The documentation doesn't include much in the way of examples, and the sample code is kind of a dog's breakfast. Most of them have rather haphazard layouts.


Solution

  • Before I begin, one important advice: if you create your layouts in code (and not loading them from XRC), then do use wxSizerFlags to make your code much more readable (see the motivating example in the documentation link). Writing sizer code by hand is still, unfortunately, error prone, as the compiler can't really help you much, but with wxSizerFlags it becomes much less so.

    To answer your first question, using borders definitely should and does work, it's hard to know what exactly went wrong for you without seeing what you did, but Add(whatever, wxSizerFlags().Border(wxLEFT, 10)) does leave a 10px gap to the left of "whatever". The main problem with this is that you must never use hardcoded values in pixels, so please don't do this and use something like DoubleBorder(wxLEFT) instead.

    Second issue is due to the fact that you don't align your wxStaticText vertically and also because you seem to pass the alignment as proportion argument of Add() -- which explains why it modifies your layout instead (buttons expand now). With wxSizerFlags you wouldn't have made this mistake.

    I'm less sure about the issue with the buttons, your code seems correct and my initial idea would be that your frame is just too small to show the buttons, but this doesn't explain why would they appear on the top of it. Nevertheless, you should call SetSizerAndFit() on the frame instead of just SetSizer() to make sure that the minimal frame size is big enough to show its entire contents (BTW you don't need to call Layout(), although it does no harm).


    Finally, writing sizer code by hand is annoying. Especially when starting, it can be useful to do it in a visual dialog editor first to make sure your layout works before transcribing it into C++ (and some of dialog editors can generate C++ code for you directly). Samples are nice to look up details of use of something, but they indeed won't teach you how to create nice layouts as it's not really their goal, they tend to be as simple as possible to demonstrate their topic instead. And most of them are quite old and so don't even use wxSizerFlags as they really ought to (any patches changing them to use it would be definitely welcome...).