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).
Related
I'm learning wxWidgets and am trying to make minesweeper using wxButtons. I use the following code to create and position the buttons:
int length = 10;
wxGridSizer *grid = new wxGridSizer(length, length, 0, 0);
wxButton *buttons[length*length];
for (int i=0; i<length*length; i++){
buttons[i] = new wxButton(this, wxID_ANY);
grid->Add(buttons[i], 1, wxEXPAND | wxALL);
if (mineField[i]){
Bind(wxEVT_BUTTON, &MainWindow::isMine, this);
} else {
Bind(wxEVT_BUTTON, &MainWindow::notMine, this);
}
}
I expect this to generate a 10x10 grid of buttons, but instead it positions all of the buttons at (0,0). I have been Googling the problem for a while now but I can't find the issue. How do I position the buttons in a 10x10 grid? Thanks.
To make the grid sizer layout the buttons, you need to either
set it to be the sizer for a window or
add it to another sizer.
Assuming the code above is from the constructor of your main frame window, you would set grid to be the sizer for the frame like this
SetSizer(grid);
On the other hand, if you have other controls in the frame and need to add grid to another sizer, you could do that something like this:
otherSizer->Add(grid,wxSizerFlags(0));
Obviously, 'otherSizer' should be replaced with the name of the other sizer. There are many options that can be used with wxSizerFlags to get the exact layout you want.
In addition, as mentioned above, it's sometimes helpful to end all the code the creates and organizes the controls your using with a call to the Layout() method.
Another tactic you can use is to have a single panel be the only child of the frame and then set a sizer for the panel. This works because in wxWidgets whenever a top level window such as a frame has a single child, that child is automatically sized to fill all of the available area.
Using this technique, a layout with a text control along the top and the grid underneath it could be created like this:
// Create the controls
wxPanel* bgPanel = new wxPanel(this, wxID_ANY);
wxTextCtrl* text = new wxTextCtrl(bgPanel, wxID_ANY);
wxGridSizer *grid = new wxGridSizer(length, length, 0, 0);
wxButton *buttons[length*length];
for (int i=0; i<length*length; i++){
buttons[i] = new wxButton(bgPanel, wxID_ANY);
grid->Add(buttons[i], 1, wxEXPAND | wxALL);
if (mineField[i]){
Bind(wxEVT_BUTTON, &MainWindow::isMine, this);
} else {
Bind(wxEVT_BUTTON, &MainWindow::notMine, this);
}
}
// Create a sizer for the panel and add the text control and grid to it.
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
mainSizer->Add(text, wxSizerFlags(0).Expand().Border(wxALL));
mainSizer->Add(grid,wxSizerFlags(1).Expand().Border(wxLEFT|wxRIGHT|wxBOTTOM));
bgPanel->SetSizer(mainSizer);
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();
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).
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
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.