WinForms control docking in wxWidgets - c++

I'm new to wxWidgets since I never use GUI when programming in C++. Now I have to. I want to make the UI responsive using something like the DockStyle.Right/Bottom/Fill from WinForms. Since I have no code I tried before, the question is very short and not the best but I hope someone can help me.
EDIT:
That is what I currently have. When I uncomment SetMaxSize there is 30px space at the bottom but the panel (blue) is not visible:
namespace tms {
MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) {
this->InitialiseComponents();
}
void MainFrame::InitialiseComponents() {
this->panelChatLog = new wxPanel(this, wxID_ANY);
this->panelChatLog->SetBackgroundColour(wxColour(0, 255, 0));
this->panelChatInput = new wxPanel(this, wxID_ANY);
this->panelChatInput->SetBackgroundColour(wxColour(0, 0, 255));
this->panelChatInput->SetMinSize(wxSize(0, 30));
//this->panelChatInput->SetMaxSize(wxSize(0, 30));
this->sizerPanels = new wxBoxSizer(wxVERTICAL);
this->sizerPanels->Add(this->panelChatLog, 1, wxEXPAND | wxALL);
this->sizerPanels->Add(this->panelChatInput, 1, wxEXPAND | wxALL);
this->SetSizer(this->sizerPanels);
}
void MainFrame::OnExit(wxCommandEvent& event) {
this->Close(true);
}
}

Learning sizers can be a little tricky at first. But once you've absorbed the concept, they can be a very effective tool for laying out windows and controls for your application.
In the specific case above, when you uncomment the SetMaxSize line, you're setting both the min width and max width of the window to be 0 - which means the window has a width of 0. Instead you can use the special value of -1 which means the min width is and max width are unspecified. Consequently the sizer will pick the best width for the window:
this->panelChatInput->SetMinSize(wxSize(-1, 30));
this->panelChatInput->SetMaxSize(wxSize(-1, 30));
Alternately, you can use the proportion property when adding the lower panel to sizer. If you set the proportion to 0, the window will take it's minimum size (in the vertical direction). It will still expand in the horizontal direction because of the wxEXPAND flag is set.
...
this->panelChatInput->SetMinSize(wxSize(-1, 30));
this->sizerPanels = new wxBoxSizer(wxVERTICAL);
this->sizerPanels->Add(this->panelChatLog, 1, wxEXPAND | wxALL);
this->sizerPanels->Add(this->panelChatInput, 0, wxEXPAND | wxALL);
...
Either way, you'll get a layout that looks like this:
I think that's what you're trying to accomplish. Sorry if I'm misunderstanding.
Also as I mentioned above, visual tools like wxFormbuilder, wxCrafter, and wxGlade can be of help to see how all these numbers and properties translate to the actual layout of the windows in your application's forms. I know they really helped me.

Related

Distribute and centre items over wxBoxSizer's full orientation without stretching

I am just learning about sizers and am kind of confused on how to accomplish this.
If I have a single horizontal box sizer in a frame and add two buttons to it (each with proportion "1") then they will both stretch to take up the full horizontal width of the sizer (which equals the full horizontal width of the frame) and be distributed evenly (see example 1 below).
Example 1 code:
wxFrame* frame = new wxFrame(nullptr, wxID_ANY, "Frame");
wxPanel* panel = new wxPanel(frame, wxID_ANY);
wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
wxButton* buttonOk = new wxButton(panel, wxID_OK, "Ok");
wxButton* buttonCancel = new wxButton(panel, wxID_CANCEL, "Cancel");
buttonSizer->Add(buttonOk, 1, wxALL, 10);
buttonSizer->Add(buttonCancel, 1, wxALL, 10);
panel->SetSizerAndFit(buttonSizer);
frame->Show();
However, what if I want these buttons to keep their original size (not be stretched), but still be distributed evenly amongst the frame, and furthermore still be centred horizontally inside each wxSizerItem? I.e. so that both "columns" of the horizontal sizer take up half the dialog, and each button is centred in each of those columns? How would I accomplish this? Here is a drawing. The buttons should be their default size.
______________________________________
| | Button 1 | | Button 3 | |
--------------------------------------
The following code does not work:
buttonSizer->Add(buttonOk, 0, wxALL, 10);
buttonSizer->Add(buttonCancel, 0, wxALL, 10);
One way to do it is with stretch spacers:
buttonSizer->AddStretchSpacer();
buttonSizer->Add(buttonOk, 0, wxALL, 10);
buttonSizer->AddStretchSpacer();
buttonSizer->Add(buttonCancel, 0, wxALL, 10);
buttonSizer->AddStretchSpacer();

wxWidgets fitting big wxGrid in wxFlexGridSizer

Problem
I have a wxGrid with many rows (>200) placed inside a wxFlexGridSizer. The problem is that my button below the grid disappears. Same thing with a wxBoxSizer works using the proportion setting.
The result should look like the wxBoxSizer solution.
Is there a way to use a wxFlexGridSizer in such situation?
wxBoxSizer (working)
wxGrid *grid = new wxGrid(this, wxID_ANY);
grid->CreateGrid(0, 2);
grid->SetDefaultRowSize(20);
grid->AppendRows(200);
wxButton *button = new wxButton(this, wxID_ANY, "button");
wxBoxSizer *bsMain = new wxBoxSizer(wxHORIZONTAL);
bsMain->Add(grid, 1, wxALL, 5);
bsMain->Add(button, 0, wxALL, 5);
SetSizer(bsMain);
wxGridSizer (not working)
wxGrid *grid = new wxGrid(this, wxID_ANY);
grid->CreateGrid(0, 2);
grid->SetDefaultRowSize(20);
grid->AppendRows(200);
wxButton *button = new wxButton(this, wxID_ANY, "button");
wxFlexGridSizer *fgsMain = new wxFlexGridSizer(1, 0, 0);
fgsMain->Add(grid, 1, wxALL, 5);
fgsMain->Add(button, 0, wxALL, 5);
fgsMain->AddGrowableRow(0);
fgsMain->AddGrowableCol(0);
SetSizer(fgsMain);
I tried to use AddGrowableRow for both rows, proportion setting, wxEXPAND flag.
There is a similar question here, but the solution is a workaround:
Fitting a big grid (wxGrid) in a dialog (wxDialog)
(Screenshoots are made with wxFormBuilder v3.8.1)
By default, wxGrid will try to show all of its 200 rows on screen, which won't leave enough place for the button. You may call SetInitialSize() (or specify the initial size when creating the grid in its ctor) to change this.
Unrelated to this question, but I strongly advise you to use more readable wxSizerFlags-based API rather than the old Add() overloads. You also shouldn't hardcode the border size in pixels, this is always wrong for some platforms and gets even worse on high DPI displays (and using wxSizerFlags would have taken care of this automatically).

wxWidgets trying to fill whole area

I've got a problem when I'm trying to prepare gui using wxWidgets.
I want to create some buttons which will cover whole area under the textbox.
It looks pretty nice when program starts, but when I want to resize it horizontally the buttons are not moving. Any ideas?
mainFrame::mainFrame(std::string title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(800, 600))
{
wxBoxSizer* vertSizer = new wxBoxSizer(wxVERTICAL);
vertSizer->Add(
new wxTextCtrl(this, -1, "My text", wxDefaultPosition, wxSize(100,80), wxTE_MULTILINE),
1, // vertically stretchable
wxEXPAND | wxALL, // horizontally stretchable, borders all around
10); // Add text box to parent sizer
wxBoxSizer* horizSizer = new wxBoxSizer(wxHORIZONTAL); // Make child sizer, will contain buttons
wxSizerFlags ButtonFlags(1); // Make controls stretch hoizontally (to cover entire sizer area)
ButtonFlags.Expand().Center().Border(wxALL,10); // Make controls expand vertically, add border
horizSizer->Add(new wxButton(this,123,"OK"), ButtonFlags); // Add first button
horizSizer->Add(new wxButton(this, 124,"Abort"), ButtonFlags); // Add second button
horizSizer->Add(new wxButton(this, 125,"Ignore"), ButtonFlags); // Add third button
vertSizer->Add(horizSizer); // Add child sizer to parent sizer
SetSizerAndFit(vertSizer);
}
This happens because you didn't tell your main sizer (vertSizer) to grow the horizSizer to fill all the available space, you need to add wxSizerFlags().Expand() to the one but last line to fix this.
Additionally, using ButtonFlags.Expand().Center() doesn't make sense: you can either expand or centre, but not both at once, so choose one. Finally, DoubleBorder() is preferable to Border(wxALL, 10).

GUI layout with wxSizer, wxSashWindow

I'm trying to create a window which is splitted into 2, 3, 4 etcc different resizable views in mainwindow and I'd like to implement that with wxWidgets in C::B. Actually th canvas itself splits the windows in the requested numbers, but it doesn't place any sash alongn the border of views so that it's very diffciult to notice which view starts where and ends where.
I create everything on run time and I was planing to place the sash, or panels around borders of views and hoping to work in my case but the main frame is reluctant to place the panels, and sashwidnwos at the correct position and stops processing the OnSize event. That is previously working codes is not functioning properly if I add the below code with sizers and panels during resizing.
MainFrame *frame = new MainFrame(NULL, wxT("wxWidgets OSG Sample"),
wxDefaultPosition, wxSize(width, height));
wxToolBar* toolbar = new wxToolBar(frame, wxID_ANY,wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL);
//wxSashLayoutWindow* win = new wxSashLayoutWindow(frame, ID_WINDOW_TOP,wxPoint(50,10), wxSize(200, 30),
// wxSW_3D | wxCLIP_CHILDREN);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
wxPanel* panel = new wxPanel(frame, ID_TBbutton, wxPoint(300,0), wxSize(5,500));
panel->SetWindowStyle(wxDOUBLE_BORDER);
// panel->SetStyle(wx_3D)
wxPanel* panel1 = new wxPanel(frame, ID_TBbutton);
sizer->Add( panel, 0, wxALL, 0 );
frame->SetSizer(sizer);
frame->SetToolBar(toolbar);
Please find below very basic example of MDI form with wxSashLayoutWindow:
bool SashWindowTestApp::OnInit()
{
wxMDIParentFrame* mainFrame = new wxMDIParentFrame(NULL, ID_TEST_FRAME,
wxT("Sash window test"), wxPoint(0, 0), wxSize(500, 400),
wxDEFAULT_FRAME_STYLE);
// top window
wxSashLayoutWindow* topWindow = new wxSashLayoutWindow(mainFrame,
ID_WINDOW_TOP, wxDefaultPosition, wxSize(200, 100),
wxSW_3D);
topWindow->SetDefaultSize(wxSize(1000, 100));
topWindow->SetAlignment(wxLAYOUT_TOP);
topWindow->SetBackgroundColour(*wxGREEN);
topWindow->SetSashVisible(wxSASH_BOTTOM, true);
// bottom window
wxSashLayoutWindow* bottomWindow = new wxSashLayoutWindow(mainFrame,
ID_WINDOW_BOTTOM, wxDefaultPosition, wxSize(200, 200),
wxSW_3D);
bottomWindow->SetDefaultSize(wxSize(1000, 200));
bottomWindow->SetAlignment(wxLAYOUT_BOTTOM);
bottomWindow->SetBackgroundColour(*wxYELLOW);
bottomWindow->SetSashVisible(wxSASH_TOP, true);
wxLayoutAlgorithm layout;
layout.LayoutMDIFrame(mainFrame);
mainFrame->Show(true);
return true;
}
In order to have a fully working sash window your frame has to react on EVT_SASH_DRAGGED

wxScrolledWindow scrollbar not working

I have the following child-parent relasions in my application:
The problem is that there is no visible ( or working ) scrollbar in wxScrolledWindow.
Code:
wxCollapsiblePane* collpane = new wxCollapsiblePane(this, ID_COLLPANE, "Tiles\t\t\t\t", wxDefaultPosition, wxDefaultSize, wxCP_NO_TLW_RESIZE);
wxSizer* sz = new wxBoxSizer(wxVERTICAL);
sz->Add(collpane,0,wxALIGN_RIGHT,10);
SetSizer(sz);
wxWindow* cPane = collpane->GetPane();
wxSizer* panesz = new wxBoxSizer(wxVERTICAL);
wxBitmap pic("test.bmp",wxBITMAP_TYPE_BMP);
wxScrolledWindow* scr = new wxScrolledWindow(cPane,ID_PANEL,wxDefaultPosition, wxSize(150,300));
scr->SetScrollbars(2,2,10,10);
wxClientDC dc(this);
scr->DoPrepareDC(dc);
panesz->Add( new wxBitmapButton(scr,-1,pic, wxDefaultPosition, wxSize(50,50) ), 1, wxALIGN_CENTER, 0 );
/* more button adding here */
cPane->SetSizer(panesz);
panesz->SetSizeHints(cPane);
How can I get the scrollbar to show and scroll the buttons?
To have scrollbars you need to indicate to wxScrolledWindow its full logical (as opposed to possibly smaller physical) size using SetVirtualSize() method. This can be done either just by calling it directly or by associating a sizer with the scrolled window, adding elements to this sizer and calling FitInside().
In the default state, for the scroll bars to appear the virtual size of the window has to be larger than the actual size of the window.
scr->SetVirtualSize(wxSize(2000,2000));
However, in version 3.1 this is not enough to get the scroll bars to appear. One also has to set the scroll rate. (This feels like a bug to me as it seems there ought to be a default setting that works.)
scr->SetScrollRate(1, 1);
You should modify the
wxWindow* cPane = collpane->GetPane();
wxSizer* panesz = new wxBoxSizer(wxVERTICAL);
wxBitmap pic("test.bmp",wxBITMAP_TYPE_B ...
You should put a jpg. After modifying this, it will work for sure ;) Trust me.