Layout inside control/component Topic is solved
Layout inside control/component
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?
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?
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 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.
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:
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:
This class is as below: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:
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?
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);
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));
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);
}
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?
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");
Use the source, Luke!
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!
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);
}
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.
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?
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?
I don't know what's your problem. This works for me :
If this still doesn't help you, try making a minimal compilable sample demonstrating the issue
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;
}
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?
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.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?
Use the source, Luke!