Layout inside control/component Topic is solved

Are you writing your own components and need help with how to set them up or have questions about the components you are deriving from ? Ask them here.
Post Reply
JohnD
Earned some good credits
Earned some good credits
Posts: 118
Joined: Fri Nov 21, 2008 2:18 pm

Layout inside control/component

Post by JohnD » Wed Mar 18, 2009 1:27 pm

In the past when developing my own components, I've had problems getting sizers to work. They work fine in my TopFrame to lay out my controls, but when I try and use Sliders internally in my components, things just go wrong.

Is there some simple rule to using sliders inside a component I may have missed? Say I have MyWindow : wxWindow, would the top level slider inside MyWindow be attached to this, or to some intermediate window/frame?

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Wed Mar 18, 2009 1:43 pm

You might need to post code, and screenshots of how they're wrong

JohnD
Earned some good credits
Earned some good credits
Posts: 118
Joined: Fri Nov 21, 2008 2:18 pm

Post by JohnD » Wed Mar 18, 2009 2:01 pm

I since hard-coded positions in the last lot I tried, but will do when I try again. IIRC, what happened was the sizer seemed tho be totally ignored... all the controls inside my component would be placed on top of each other, nothing resized, etc.

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Wed Mar 18, 2009 5:29 pm

JohnD wrote:I since hard-coded positions in the last lot I tried, but will do when I try again. IIRC, what happened was the sizer seemed tho be totally ignored... all the controls inside my component would be placed on top of each other, nothing resized, etc.
This usually happens when there is a parenting issue (like adding components to the frame and then adding the sizer to the panel), or you plain forgot to do ->SetSizer() or ->Add() components to the sizer.

JohnD
Earned some good credits
Earned some good credits
Posts: 118
Joined: Fri Nov 21, 2008 2:18 pm

Post by JohnD » Mon Mar 23, 2009 1:58 pm

So I'm trying this on a new component now and get the same problem. Let me paste some code:

First, in the TopFrame constructor, I set up my primary layout sizer:

Code: Select all

wxBoxSizer *topLevelSizerV = new wxBoxSizer(wxVERTICAL);
wxWindow *topLevelPanel = new wxPanel(this);
Many child sizers and standard wx controls are added, without problems... sizing the main window even works :)

I now add the code to add an instance of my new control, a thin bar which should stretch the entire width of the main window:

Code: Select all

topLevelSizerV->Add(new TimelineWindow(topLevelPanel));
This class is as below:

Code: Select all

class TimelineWindow : public wxWindow
{
/* Needed for wxWidgets */
DECLARE_CLASS(TimelineWindow)

public:
	TimelineWindow( wxWindow* parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);

protected:
	DECLARE_EVENT_TABLE()
};

TimelineWindow::TimelineWindow( wxWindow* parent, const wxPoint &pos, const wxSize &size)
	: wxWindow(parent, wxID_ANY, pos, size,wxBORDER_SUNKEN)
{
	wxWindow *topLevelPanel = new wxPanel(this);
	wxBoxSizer *topLevelSizer = new wxBoxSizer(wxHORIZONTAL);

	wxButton *startButton = new wxButton(this,wxID_ANY,"Start");
	wxButton *pauseButton = new wxButton(this,wxID_ANY,"Pause");
	wxButton *stopButton = new wxButton(this,wxID_ANY,"Stop");

	topLevelSizer->Add(startButton,1,wxEXPAND);
	topLevelSizer->AddStretchSpacer();
	topLevelSizer->Add(pauseButton,1,wxEXPAND);
	topLevelSizer->AddStretchSpacer();
	topLevelSizer->Add(stopButton,1,wxEXPAND);

	topLevelPanel->SetSizer(topLevelSizer);
	topLevelSizer->SetSizeHints(this);
}
So note my control internally creates a horizontal sizer and a intermediary panel to attach the buttons to. The result is shown in the attached image:
Image
The control doesn't expand to fit the whoe top-frame's width, and the buttons certainly are not following any layout properly.

What am I missing?

User avatar
doublemax
Moderator
Moderator
Posts: 13991
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Mon Mar 23, 2009 4:12 pm

Code: Select all

        wxButton *startButton = new wxButton(this,wxID_ANY,"Start");
        wxButton *pauseButton = new wxButton(this,wxID_ANY,"Pause");
        wxButton *stopButton = new wxButton(this,wxID_ANY,"Stop");
i think these should have topLevelPanel as parent
Use the source, Luke!

JohnD
Earned some good credits
Earned some good credits
Posts: 118
Joined: Fri Nov 21, 2008 2:18 pm

Post by JohnD » Mon Mar 23, 2009 4:24 pm

Good catch, but making that change makes things even worse. The control is the same size as before (about 40% as wide as the main window) but now the buttons aren't just on top of each other, they're invisible/missing!

User avatar
doublemax
Moderator
Moderator
Posts: 13991
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Mon Mar 23, 2009 4:41 pm

How about this?

Code: Select all

class TimelineWindow : public wxPanel
{
/* Needed for wxWidgets */
DECLARE_CLASS(TimelineWindow)

public:
        TimelineWindow( wxWindow* parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);

protected:
        DECLARE_EVENT_TABLE()
};

TimelineWindow::TimelineWindow( wxWindow* parent, const wxPoint &pos, const wxSize &size)
        : wxPanel(parent, wxID_ANY, pos, size,wxBORDER_SUNKEN)
{
        wxBoxSizer *topLevelSizer = new wxBoxSizer(wxHORIZONTAL);

        wxButton *startButton = new wxButton(this,wxID_ANY,"Start");
        wxButton *pauseButton = new wxButton(this,wxID_ANY,"Pause");
        wxButton *stopButton = new wxButton(this,wxID_ANY,"Stop");

        topLevelSizer->Add(startButton,1,wxEXPAND);
        topLevelSizer->AddStretchSpacer();
        topLevelSizer->Add(pauseButton,1,wxEXPAND);
        topLevelSizer->AddStretchSpacer();
        topLevelSizer->Add(stopButton,1,wxEXPAND);

        this->SetSizer(topLevelSizer);
        this->SetAutoLayout(true);

        topLevelSizer->SetSizeHints(this);
} 
Use the source, Luke!

JohnD
Earned some good credits
Earned some good credits
Posts: 118
Joined: Fri Nov 21, 2008 2:18 pm

Post by JohnD » Mon Mar 23, 2009 6:49 pm

Still not quite right:

Code: Select all

TimelineWindow::TimelineWindow( wxWindow* parent, const wxPoint &pos, const wxSize &size)
	: wxWindow(parent, wxID_ANY, pos, size,wxBORDER_SUNKEN)
{
	wxBoxSizer *topLevelSizer = new wxBoxSizer(wxHORIZONTAL);
	wxButton *btnRestart = new wxButton(this,ID_RESTART,"New procedure");
	wxButton *btnNext = new wxButton(this,ID_NEXT,"Next Step");

	topLevelSizer->Add(btnRestart,1,wxEXPAND);
	topLevelSizer->AddStretchSpacer();
	topLevelSizer->Add(btnNext,1,wxEXPAND);

	this->SetSizer(topLevelSizer);
	this->SetAutoLayout(true);
	topLevelSizer->SetSizeHints(this);
}
Image

User avatar
doublemax
Moderator
Moderator
Posts: 13991
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Mon Mar 23, 2009 7:20 pm

you probably missed that i derived the control from wxPanel, not wxWindow
Use the source, Luke!

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Mon Mar 23, 2009 9:53 pm

Yup, just building on what doublemax said, deriving from wxWindows if often not the easiest. wxWindow is meant as a rather abstract base class for all widgets, and it doesn't do that much itself; it leaves much work to be done by its children. Deriving from wxPanel will make it much easier for you since wxPanel does handle usual stuff.

JohnD
Earned some good credits
Earned some good credits
Posts: 118
Joined: Fri Nov 21, 2008 2:18 pm

Post by JohnD » Mon Mar 23, 2009 10:57 pm

My heart jumped then - I had indeed missed wxPanel, but it makes no difference. The first button appears nicely but the 2nd one is not visible, I can only assume it is underneath the 1st.

I am really frustrated why this is so difficult... sizers on my TopFrame window all work just fine. I don't need to be manually handling resize events in my class do I?

And for a slight side-question, why do examples for wx have the topPanel approach in the top-frame, I I used in my first code posted in this thread? How exactly does that work?

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Tue Mar 24, 2009 2:53 pm

I don't know what's your problem. This works for me :

Code: Select all

#include "wx/wx.h"

class TimelineWindow : public wxPanel
    {
        /* Needed for wxWidgets */
        // DECLARE_CLASS(TimelineWindow) disabled so i don't have to define it...
        
    public:
        TimelineWindow( wxWindow* parent, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize);
        
    protected:
        DECLARE_EVENT_TABLE()
    };

BEGIN_EVENT_TABLE(TimelineWindow,wxPanel)
END_EVENT_TABLE()

TimelineWindow::TimelineWindow( wxWindow* parent, const wxPoint &pos, const wxSize &size)
: wxPanel(parent, wxID_ANY, pos, size,wxBORDER_SUNKEN)
{
    wxBoxSizer *topLevelSizer = new wxBoxSizer(wxHORIZONTAL);
    
    wxButton *startButton = new wxButton(this,wxID_ANY, wxT("Start"));
    wxButton *pauseButton = new wxButton(this,wxID_ANY, wxT("Pause"));
    wxButton *stopButton = new wxButton(this,wxID_ANY, wxT("Stop"));
    
    topLevelSizer->Add(startButton,1,wxEXPAND);
    topLevelSizer->AddStretchSpacer();
    topLevelSizer->Add(pauseButton,1,wxEXPAND);
    topLevelSizer->AddStretchSpacer();
    topLevelSizer->Add(stopButton,1,wxEXPAND);
    
    this->SetSizer(topLevelSizer);
    this->SetAutoLayout(true);
    
    topLevelSizer->SetSizeHints(this);
}

class MyApp: public wxApp
	{
		bool OnInit();
		
		wxFrame *frame;
	public:
        
	};

IMPLEMENT_APP(MyApp)


bool MyApp::OnInit()
{
    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    frame = new wxFrame((wxFrame *)NULL, -1,  wxT("Hello wxWidgets"), wxPoint(50,50), wxSize(800,600));
	
    wxPanel* topLevelPanel = new wxPanel(frame);
    
    sizer->Add(new TimelineWindow(topLevelPanel));
	topLevelPanel->SetSizer(sizer);
    
    frame->Show();
    return true;
} 
If this still doesn't help you, try making a minimal compilable sample demonstrating the issue

User avatar
doublemax
Moderator
Moderator
Posts: 13991
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Tue Mar 24, 2009 3:28 pm

i tested the code and it works for me, too. Maybe the problem lies "outside", e.g. where you create an instance of that class and add it to a sizer?
And for a slight side-question, why do examples for wx have the topPanel approach in the top-frame, I I used in my first code posted in this thread? How exactly does that work?
If a wxFrame has exactly one child, it will always get automatically resized to cover the whole client area, so you don't need a sizer for that. It's recommended to use a wxPanel as container for your gui elements because it handles tab-navigation and some other stuff for you.
Use the source, Luke!

JohnD
Earned some good credits
Earned some good credits
Posts: 118
Joined: Fri Nov 21, 2008 2:18 pm

Post by JohnD » Tue Mar 24, 2009 4:33 pm

Thanks guys, since you got that to run as expected I'll dig into the top-frame code and look for something there.

Post Reply