Why are my panel controls all on top of one another?

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
User avatar
bsenftner
Experienced Solver
Experienced Solver
Posts: 85
Joined: Thu May 26, 2016 9:19 pm

Why are my panel controls all on top of one another?

Post by bsenftner »

WxWidgets 3.0.2, developing in Visual Studio Community 2013, targeting Windows and Linux

I have a top level frame, with a notebook, that holds a series of panels. I am trying to create three sets of controls for this panel, with each set of controls inside a static box. However, every attempt gives me all the controls on top of one another in the upper left of the panel. I'm working with another developer, and he's using wxPoint to position his controls, but none of the examples or samples I'm seeing use explicit pixel positioning, and I suspect he'll have problems when the application is run on different OSes, or someone has a different sized system font than him...

I've modeled my logic after examples in "Cross Platform GUI Programming with wxWidgets" and the "dialogs" sample that comes with wxWidgets, specifically the SettingsDialog. The SettingsDialog has staticBoxes used to enclose groups of parameters, and that is what I want. About the only difference between the dialog sample and my logic is that I'm on a wxPanel, and the sample uses a wxDialog. Should that matter?

Trying to get this figured out, I reduced to a single set of controls (from three different sets) and have only a few of the controls for this first set:

Code: Select all

	wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);	// the outer container 
	wxBoxSizer *boxSizer0 = new wxBoxSizer(wxVERTICAL);	

	topSizer->Add(boxSizer0, 1, wxGROW | wxALL, 10);

	// a static box to enclose all parameters:
	wxStaticBox* enrollStaticBox = new wxStaticBox(this, ID_INTERFACES_ENROLL_ENCLOSINGBOX, wxT("Auto-enrollment on directory addition:"));
	
	// a static box sizer to help with the layout
	wxStaticBoxSizer* enrollStaticBoxSizer = new wxStaticBoxSizer(enrollStaticBox, wxVERTICAL);
	
	boxSizer0->Add(enrollStaticBoxSizer, 0, wxGROW | wxALL, 5);


	wxString enrollExplainer = wxT("Explaining the auto-enrolling logic here");
	wxStaticText* enrollExplainerSt = new wxStaticText(this, ID_INTERFACES_ENROLL_EXPLAINER, enrollExplainer);
	//
	enrollStaticBoxSizer->Add(enrollExplainerSt, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);

	wxCheckBox* cbEnabled = new wxCheckBox(this, ID_INTERFACES_ENROLL_ENABLEDCHECKBOX,
		wxT("Yes, auto-enroll as images are added to this directory"));
	cbEnabled->SetValue(m_enrollParams.m_enabled);
	//
	enrollStaticBoxSizer->Add(cbEnabled, 0, wxGROW | wxALL, 5);

	wxTextCtrl* tcEnroll_directory = new wxTextCtrl(this, ID_INTERFACES_ENROLL_DIRECTORYST,
		m_enrollParams.m_directory.c_str());
	//
	enrollStaticBoxSizer->Add(tcEnroll_directory, 0, wxGROW | wxALIGN_LEFT | wxALL, 5);

	SetSizerAndFit(topSizer);
This part of the panel's construction. I've been trying things for hours, and nothing seems to make a difference: tried adding spacers, tried without any wxStaticBox enclosing everything... the controls are always just collapsed on top of eachother.
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 469
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: Why are my panel controls all on top of one another?

Post by New Pagodi »

That seems to layout correctly for me.

If you're just starting out, coding the UI elements by hand can be tricky. You may want to look into a UI builder such as wxFormbuilder. Even if you don't want to use the code it produces, it can still give examples of how to lay things out that you can learn from.

Other options include wxGlade and wxCrafter (and I think there are a few others).
User avatar
xaviou
Super wx Problem Solver
Super wx Problem Solver
Posts: 437
Joined: Mon Aug 21, 2006 3:18 pm
Location: Annecy - France
Contact:

Re: Why are my panel controls all on top of one another?

Post by xaviou »

Hi
New Pagodi wrote:If you're just starting out, coding the UI elements by hand can be tricky.
But I think this is the best way to understand the sizers concept.
This is also the best way to have optimized code.
But this is of course my own opinion.

To avoid errors, I generally write my code as a tree (using indentation).
For example:

Code: Select all

wxBoxSizer *mainszr=new wxBoxSizer(wxVERTICAL);
    wxBoxSizer *hszr=new wxBoxSizer(wxHORIZONTAL);
        wxStaticText *label=new wxStaticText(this, -1, _T("Filename:"));
        hszr->Add(label, 0, wxALL|wxALIGN_CENTER_VERTICAL, 0);
        wxTextCtrl *txtFilename=new wxTextCtrl(this, -1, wxEmptyString);
        hszr->Add(txtFilename, 1, wxLEFT|wxALIGN_CENTER_VERTICAL, 5);
        wxButton *btnBrowse=new wxButton(this, -1, _T("..."), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
        hszr->Add(btnBrowse, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 5);
    mainszr->Add(hszr, 0, wxALL|wxEXPAND, 5);

    ......
SetSizer(mainszr);
@bsenftner : With your code, this will give something like the following :

Code: Select all

    wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);   // the outer container 
        wxBoxSizer *boxSizer0 = new wxBoxSizer(wxVERTICAL);   
            // a static box to enclose all parameters:
            wxStaticBox* enrollStaticBox = new wxStaticBox(this, ID_INTERFACES_ENROLL_ENCLOSINGBOX, wxT("Auto-enrollment on directory addition:"));
            // a static box sizer to help with the layout
            wxStaticBoxSizer* enrollStaticBoxSizer = new wxStaticBoxSizer(enrollStaticBox, wxVERTICAL);
            
                wxString enrollExplainer = wxT("Explaining the auto-enrolling logic here");
                wxStaticText* enrollExplainerSt = new wxStaticText(this, ID_INTERFACES_ENROLL_EXPLAINER, enrollExplainer);
                enrollStaticBoxSizer->Add(enrollExplainerSt, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
                
                wxCheckBox* cbEnabled = new wxCheckBox(this, ID_INTERFACES_ENROLL_ENABLEDCHECKBOX, wxT("Yes, auto-enroll as images are added to this directory"));
                    cbEnabled->SetValue(m_enrollParams.m_enabled);
                enrollStaticBoxSizer->Add(cbEnabled, 0, wxGROW | wxALL, 5);
                
                wxTextCtrl* tcEnroll_directory = new wxTextCtrl(this, ID_INTERFACES_ENROLL_DIRECTORYST, m_enrollParams.m_directory.c_str());
                enrollStaticBoxSizer->Add(tcEnroll_directory, 0, wxGROW | wxALIGN_LEFT | wxALL, 5);

            boxSizer0->Add(enrollStaticBoxSizer, 0, wxGROW | wxALL, 5);
        topSizer->Add(boxSizer0, 1, wxGROW | wxALL, 10);
SetSizerAndFit(topSizer);
But I confirm the first response of New Pagodi : all seems to be correct.

Can you post a screenshot of the result ?

Regards
Xav'
My wxWidgets stuff web page : X@v's wxStuff
User avatar
bsenftner
Experienced Solver
Experienced Solver
Posts: 85
Joined: Thu May 26, 2016 9:19 pm

Re: Why are my panel controls all on top of one another?

Post by bsenftner »

Here's a screen shot of the result:
badUI.jpg
badUI.jpg (46.84 KiB) Viewed 2677 times
The notebook's 4 tabs are external to this issue. It's the "Interfaces" controls I'm trying to build, and as you can see they are all collapsed.

I think I need to rebuild my wxWidgets library. The wxWidgets library build scripts seem to be buggy, though. I ask for a static lib for x64, and I get an x86 library. (I'm doing this on Win10.) Tried fixing the build scripts, but backed out of that confusion. Tried using DialogBlocks and their wxWidgets auto-building system, which is the library build I'm using now, but I am suspecting that is built wrong too. Between this layout issue, and one last week where I could not get events to reach a dialog, I think my version of the library is wonky.

I see there are pre-built dlls for Windows; are there any pre-built x64 static libraries of wxWidgets?

I also hear mention of other wxWidgets interactive layout tools. Any recommendations? I was surprised to learn that I could not get DialogBlocks to use wxStaticBox correctly - the staticBoxes were always empty, with no explanation or means to put controls inside them (yes, I know they need to be siblings, but I could not get that to work either...)
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 469
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: Why are my panel controls all on top of one another?

Post by New Pagodi »

bsenftner wrote:I also hear mention of other wxWidgets interactive layout tools. Any recommendations?
Here's a list.
catalin
Moderator
Moderator
Posts: 1618
Joined: Wed Nov 12, 2008 7:23 am
Location: Romania

Re: Why are my panel controls all on top of one another?

Post by catalin »

bsenftner wrote:

Code: Select all

	wxStaticBox* enrollStaticBox = new wxStaticBox(this, ID_INTERFACES_ENROLL_ENCLOSINGBOX, wxT("Auto-enrollment on directory addition:"));
make sure that 'this' is the notebook page and not something else.
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4204
Joined: Sun Jan 03, 2010 5:45 pm

Re: Why are my panel controls all on top of one another?

Post by PB »

It's likely that the issue lies outside the code you posted. I took your code verbatim (only changed the IDs to wxID_ANY) and it looks as expected when embedded in a panel which is the only child of a wxFrame (wxWidgets trunk):
frame.png
frame.png (17.39 KiB) Viewed 2665 times
SSCCE:

Code: Select all

#include <wx/wx.h>

class MyPanel : public wxPanel
{
public:
    MyPanel(wxWindow* parent)
        : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
    {
        wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);   // the outer container
        wxBoxSizer *boxSizer0 = new wxBoxSizer(wxVERTICAL);

        topSizer->Add(boxSizer0, 1, wxGROW | wxALL, 10);

        // a static box to enclose all parameters:
        wxStaticBox* enrollStaticBox = new wxStaticBox(this, wxID_ANY, wxT("Auto-enrollment on directory addition:"));

        // a static box sizer to help with the layout
        wxStaticBoxSizer* enrollStaticBoxSizer = new wxStaticBoxSizer(enrollStaticBox, wxVERTICAL);

        boxSizer0->Add(enrollStaticBoxSizer, 0, wxGROW | wxALL, 5);


        wxString enrollExplainer = wxT("Explaining the auto-enrolling logic here");
        wxStaticText* enrollExplainerSt = new wxStaticText(this, wxID_ANY, enrollExplainer);
        //
        enrollStaticBoxSizer->Add(enrollExplainerSt, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);

        wxCheckBox* cbEnabled = new wxCheckBox(this, wxID_ANY,
                                               wxT("Yes, auto-enroll as images are added to this directory"));
        // cbEnabled->SetValue(m_enrollParams.m_enabled);
        //
        enrollStaticBoxSizer->Add(cbEnabled, 0, wxGROW | wxALL, 5);

        wxTextCtrl* tcEnroll_directory = new wxTextCtrl(this, wxID_ANY,
                                                        "m_enrollParams.m_directory.c_str()");
        //
        enrollStaticBoxSizer->Add(tcEnroll_directory, 0, wxGROW | wxALIGN_LEFT | wxALL, 5);

        SetSizerAndFit(topSizer);
    }
};

class MyApp : public wxApp
{
public:
    virtual bool OnInit()
    {
        wxFrame* f = new wxFrame(NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(400, 200));
        
        new MyPanel(f);
        f->Show();
        return true;
    }
};
wxIMPLEMENT_APP(MyApp);
User avatar
bsenftner
Experienced Solver
Experienced Solver
Posts: 85
Joined: Thu May 26, 2016 9:19 pm

Re: Why are my panel controls all on top of one another?

Post by bsenftner »

Looking at some other correctly working wxWidgets code creating an interface, I see a creation of a wxStaticBoxSizer, but no creation of a wxStaticBox. I thought both had to be created separate?

In this other code, I see this to create:

Code: Select all

wxStaticBoxSizer *content = new wxStaticBoxSizer(wxHORIZONTAL, this, "XML Content");
And then when a wxStaticBox is needed, I see this:

Code: Select all

content->GetStaticBox()
Is that creation signature new wxStaticBoxSizer(wxHORIZONTAL, this, "XML Content") creating both a wxStaticBox & wxStaticBoxSizer?

This other code is in my application, and works fine. The documentation I've seen for wStaticBoxSizer explicitly says the wxStaticBox needs to be created separately. Is that old information?
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4204
Joined: Sun Jan 03, 2010 5:45 pm

Re: Why are my panel controls all on top of one another?

Post by PB »

bsenftner wrote:This other code is in my application, and works fine. The documentation I've seen for wStaticBoxSizer explicitly says the wxStaticBox needs to be created separately. Is that old information?
If you read my previous post you would know that using static box and sizer the way you do is not an issue. Did you also do what catalin suggested?

Anyway, I believe that the first paragraph of wxWidgets documentation for wxStaticBoxSizer answers your questions:
wxStaticBoxSizer is a sizer derived from wxBoxSizer but adds a static box around the sizer.

The static box may be either created independently or the sizer may create it itself as a convenience. In any case, the sizer owns the wxStaticBox control and will delete it in the wxStaticBoxSizer destructor.

Note that since wxWidgets 2.9.1 you are encouraged to create the windows which are added to wxStaticBoxSizer as children of wxStaticBox itself, see this class documentation for more details.
User avatar
bsenftner
Experienced Solver
Experienced Solver
Posts: 85
Joined: Thu May 26, 2016 9:19 pm

Re: Why are my panel controls all on top of one another?

Post by bsenftner »

Yes, I did verify that my this pointer is the wPanel.

The documentation I'm using as my primary source is the "Cross Platform GUI Programming with wxWidgets", (just purchased from Amazon 3 weeks ago) and that does not describe the "convenience" constructor for a wxStaticBoxSizer that also creates a wxStaticBox. So my book examples all do a two step creation. Not being familiar with the one step creation method, I asked when I noticed it in other code...

Any you can probably tell, I'm grasping at straws.

It took me more than a day to get my original build of wxWidgets (unicode, static library, x64) and all indications led me to believe I have a bad build. I just don't want to repeat that confusion of creating my version of the libraries again.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Why are my panel controls all on top of one another?

Post by doublemax »

From the docs:
Note that since wxWidgets 2.9.1 you are encouraged to create the windows which are added to wxStaticBoxSizer as children of wxStaticBox itself, see this class documentation for more details.
Did you try that?

http://docs.wxwidgets.org/3.0/classwx_s ... sizer.html
Use the source, Luke!
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4204
Joined: Sun Jan 03, 2010 5:45 pm

Re: Why are my panel controls all on top of one another?

Post by PB »

bsenftner wrote:The documentation I'm using as my primary source is the "Cross Platform GUI Programming with wxWidgets"
The book is about a decade old. This is pretty much an eternity in the IT world. It can probably be still used but one should be careful and at least: (1) read the changelog since the version it covers (2.6?), particularly the incompatible changes part; (2)the up-to-date online documentation for a particular class.
bsenftner wrote:It took me more than a day to get my original build of wxWidgets (unicode, static library, x64) and all indications led me to believe I have a bad build. I just don't want to repeat that confusion of creating my version of the libraries again.
At least on MSW, building wxWidgets is extremely easy, using the provided makefiles or project files which cover both major compilers on the platform (MSVC and GCC), see the docs/install.txt. I am not a programmer myself and I'm not very bright on top of that, but even I could make wxWidgets build and work both for MSVC and GCC.

I know, time's always short but one can save lot of time and frustration when planning a bit. I don't mean the above as preaching, just a friendly advice. :)
Post Reply