I want to add a varying amount of 2d squares on the bottom of a panel, whose widgets are inside a box sizer.
I made a Square class widget, that takes in a position, size, and color, and made 3 instances of it that I've added to the box sizer.
The problem is, they are placed from top left, instead of bottom left, how I would like.
Square.h
#pragma once
#include <wx/wx.h>
class Square : public wxWindow
{
wxPoint position;
wxSize size;
wxBrush brushColor;
public:
Square(wxPanel* parent, wxPoint rectPosition, wxSize rectSize, wxColour rectColor);
void PaintEvent(wxPaintEvent& evt);
void Draw(wxDC& dc);
DECLARE_EVENT_TABLE()
};
Square.cpp
#include "Square.h"
BEGIN_EVENT_TABLE(Square, wxPanel)
EVT_PAINT(Square::PaintEvent)
END_EVENT_TABLE()
Square::Square(wxPanel* parent, wxPoint position, wxSize size, wxColour color) : wxWindow(parent, wxID_ANY)
{
this->position = position;
this->size = size;
this->brushColor = wxBrush(color);
}
void Square::PaintEvent(wxPaintEvent& evt)
{
wxPaintDC dc(this);
Draw(dc);
}
void Square::Draw(wxDC& dc)
{
dc.SetBrush(brushColor);
dc.DrawRectangle(position.x, position.y, size.x, size.y);
}
MainWindow.cpp
#include "MainWindow.h"
#include "Square.h"
MainWindow::MainWindow(const wxString& title) : wxFrame(nullptr, wxID_ANY, title)
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxHORIZONTAL);
wxPanel* sidePanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
wxPanel* largePanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
mainSizer->Add(sidePanel, 1, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 5);
mainSizer->Add(largePanel, 7, wxEXPAND | wxALL, 5);
this->SetSizerAndFit(mainSizer);
wxBoxSizer* squareSizer = new wxBoxSizer(wxHORIZONTAL);
Square* red_square = new Square(largePanel, wxDefaultPosition, wxSize(20, 20), wxColour(255, 0, 0));
Square* green_square = new Square(largePanel, wxDefaultPosition, wxSize(20, 20), wxColour(0, 255, 0));
Square* blue_square = new Square(largePanel, wxDefaultPosition, wxSize(20, 20), wxColour(0, 0, 255));
squareSizer->Add(red_square, 1, wxEXPAND);
squareSizer->Add(green_square, 1, wxEXPAND);
squareSizer->Add(blue_square, 1, wxEXPAND);
largePanel->SetSizerAndFit(squareSizer);
}
When using sizers, to align a window (or control) to the bottom of its parent you must tell so to the proper sizer (the one that calculates the layout of that parent.
squareSizer->Add(red_square, 1, wxEXPAND | wxALIGN_BOTTOM);
But using wxEXPAND
with a wxHORIZONTAL sizer means that the window will take all vertical available space. So, the align-bottom will have no effect. It makes sense when the height (likely fixed, not expandable) of the window is less than the height of the parent where it's layed out.
Perhaps you want some vertical space between the rectangle (at bottom) and its parent panel top border.
If you want this space to be fixed you can use a border
squareSizer->Add(red_square, 1, wxEXPAND | wxALIGN_BOTTOM | wxTOP, 25); //border 25 pixels tall
If you want this space to be expandable then you must use another wxBoxSizer that contains a AddStretchSpacer before adding the window:
wxBoxSizer* verSizer = new wxBoxSizer(wxVERTICAL);
verSizer->AddStretchSpacer(1);
verSizer->Add(red_square, 1, wxEXPAND);
squareSizer->Add(verSizer, 1, wxEXPAND);
And if you want to give 70% to the spacer and 30% to the bottom window use two proportion values:
verSizer->AddStretchSpacer(70);
verSizer->Add(red_square, 30, wxEXPAND);
All of this can be found in the docs:
https://docs.wxwidgets.org/trunk/overview_sizer.html
https://docs.wxwidgets.org/trunk/classwx_box_sizer.html
Finally, consider using wxSizerFlags instead of so many little clear parameters at Add() member.