Reputation: 805
I'm using horizontal and vertical boxsizers to build my GUI, and so far I've had success just adding everything to sizers using expand on each sizer, then adjusting a min or max width/height of diff elements to get what I want. I've run into a strange problem though.
There are 2 gaps in the contents of my GUI i don't understand. Here is an image:
Gap #1
I don't understand gap #1 because it seems unnecessary. The entire GUI starts out with a vertical boxsizer with 2 elements. All the contents above the red StaticText go into the top part, and the red StaticText is contained in the second element.
Among the sub-sizers in the top strip, the most height that should be required is for the "Castables" and "Lands" columns of TextCtrls. This leads me to strange gap #2...
Gap #2
This gap was not here until i set a max height for the 4 buttons above it. I've drawn purple outlines in paint so you can see how the sizers fit together (or how they SHOULD fit together unless I've made a mistake). The gap is at the start of a vertical sizer that then contains some other sizers... Before i set the max heights for those 4 buttons, the height of those 4 buttons filled this gap area exactly. When i set the max height for them, I want all of the contents below to slide up, not down.
Here is all of my code in the constructor that builds the entire GUI
// mainPanel
wxPanel *mainPanel = new wxPanel(this, wxID_ANY);
// mainPanelSizer (vertical)
wxBoxSizer *mainPanelSizer = new wxBoxSizer(wxVERTICAL);
// progSizer (horizontal)
// contains program along top, and log window is along the bottom
// program contains 3 "columns"
wxBoxSizer *progSizer = new wxBoxSizer(wxHORIZONTAL);
mainPanelSizer->Add(progSizer, wxSizerFlags(1).Expand());
// 1. DECK
// deckSizer (horizontal)
wxBoxSizer *deckSizer = new wxBoxSizer(wxHORIZONTAL);
progSizer->Add(deckSizer, wxSizerFlags(1).Expand());
// castables column
wxBoxSizer *deckSizerCasts = new wxBoxSizer(wxVERTICAL);
deckSizer->Add(deckSizerCasts, wxSizerFlags(1).Expand());
// castables title
wxStaticText *deckCastsTitle = new wxStaticText(mainPanel, wxID_ANY, "Castables", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
deckCastsTitle->SetBackgroundColour(*wxYELLOW);
deckCastsTitle->SetMaxSize(wxSize(-1, 25));
deckSizerCasts->Add(deckCastsTitle, wxSizerFlags(1).Expand());
// castables content
for ( int i = 0; i < 25; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString);
textCtrl->SetMinSize(wxSize(200, -1));
textCtrl->SetMaxSize(wxSize(-1, 25));
deckInputCastables.push_back(textCtrl);
deckSizerCasts->Add(textCtrl, wxSizerFlags(1).Expand());
}
// lands column
wxBoxSizer *deckSizerLands = new wxBoxSizer(wxVERTICAL);
deckSizer->Add(deckSizerLands, wxSizerFlags(1).Expand());
// lands title
wxStaticText *deckLandsTitle = new wxStaticText(mainPanel, wxID_ANY, "Lands", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
deckLandsTitle->SetBackgroundColour(*wxGREEN);
deckLandsTitle->SetMaxSize(wxSize(-1, 25));
deckSizerLands->Add(deckLandsTitle, wxSizerFlags(1).Expand());
// lands content
for ( int i = 0; i < 25; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString);
textCtrl->SetMinSize(wxSize(200, -1));
textCtrl->SetMaxSize(wxSize(-1, 25));
deckInputLands.push_back(textCtrl);
deckSizerLands->Add(textCtrl, wxSizerFlags(1).Expand());
}
// 2. HAND
// handSizer (vertical)
wxBoxSizer *handSizer = new wxBoxSizer(wxVERTICAL);
progSizer->Add(handSizer, wxSizerFlags(1).Expand());
// hand title
wxStaticText *deckHandTitle = new wxStaticText(mainPanel, wxID_ANY, "Hand", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
deckHandTitle->SetBackgroundColour(*wxCYAN);
deckHandTitle->SetMaxSize(wxSize(-1, 25));
handSizer->Add(deckHandTitle, wxSizerFlags(1).Expand());
// hand content
for ( int i = 0; i < 7; i++ )
{
wxTextCtrl *textCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString);
textCtrl->SetMinSize(wxSize(200, -1));
textCtrl->SetMaxSize(wxSize(-1, 25));
handInputs.push_back(textCtrl);
handSizer->Add(textCtrl, wxSizerFlags(1).Expand());
}
// 3. OPTS
wxBoxSizer *optsSizer = new wxBoxSizer(wxVERTICAL);
progSizer->Add(optsSizer, wxSizerFlags(1).Expand());
// a. OPTS INSTRUCTIONS (horizontal)
// contains buttons for things can do,
// add or remove needs, reset all, or calculate
wxBoxSizer *optsInstructSizer = new wxBoxSizer(wxHORIZONTAL);
optsSizer->Add(optsInstructSizer, wxSizerFlags(1).Expand());
wxButton *addNeedButton = new wxButton(mainPanel, wxID_ANY, "+ Need");
//addNeedButton->SetMaxSize(wxSize(-1, 50));
optsInstructSizer->Add(addNeedButton, wxSizerFlags(1).Expand());
wxButton *removeNeedButton = new wxButton(mainPanel, wxID_ANY, "- Need");
//removeNeedButton->SetMaxSize(wxSize(-1, 50));
optsInstructSizer->Add(removeNeedButton, wxSizerFlags(1).Expand());
wxButton *resetAllButton = new wxButton(mainPanel, wxID_ANY, "Reset All");
//resetAllButton->SetMaxSize(wxSize(-1, 50));
optsInstructSizer->Add(resetAllButton, wxSizerFlags(1).Expand());
wxButton *calculateButton = new wxButton(mainPanel, wxID_ANY, "Calculate");
//calculateButton->SetMaxSize(wxSize(-1, 50));
optsInstructSizer->Add(calculateButton, wxSizerFlags(1).Expand());
// b. NEEDS WRAP SIZER
// contains all the needs
wxBoxSizer *needsWrapSizer = new wxBoxSizer(wxVERTICAL);
optsSizer->Add(needsWrapSizer, wxSizerFlags(1).Expand());
// b1. a single need we can copy to make more needs
wxBoxSizer *needsItemSizer = new wxBoxSizer(wxVERTICAL);
needsWrapSizer->Add(needsItemSizer, wxSizerFlags(1).Expand());
// each need has 3 horrizontal components
// i. filters check area
// we'll do 3 columns of filters so 12 possible.
// this is
wxBoxSizer *needsItemFiltersSizer = new wxBoxSizer(wxHORIZONTAL);
needsItemSizer->Add(needsItemFiltersSizer, wxSizerFlags(1).Expand());
// 4 filters per column: col 1
wxBoxSizer *needsItemFiltersCol1Sizer = new wxBoxSizer(wxVERTICAL);
needsItemFiltersSizer->Add(needsItemFiltersCol1Sizer, wxSizerFlags(1).Expand());
for ( int i = 0; i < 4; i++ )
{
wxCheckBox *filterCheck = new wxCheckBox(mainPanel, wxID_ANY, "filter " + wxString::Format(wxT("%d"), (int)(i + 1)));
filterCheck->SetBackgroundColour(*wxGREEN);
needsItemFiltersCol1Sizer->Add(filterCheck, wxSizerFlags(1).Expand());
}
// 4 filters per column: col 2
wxBoxSizer *needsItemFiltersCol2Sizer = new wxBoxSizer(wxVERTICAL);
needsItemFiltersSizer->Add(needsItemFiltersCol2Sizer, wxSizerFlags(1).Expand());
for ( int i = 4; i < 8; i++ )
{
wxCheckBox *filterCheck = new wxCheckBox(mainPanel, wxID_ANY, "filter " + wxString::Format(wxT("%d"), (int)(i + 1)));
needsItemFiltersCol2Sizer->Add(filterCheck, wxSizerFlags(1).Expand());
}
// 4 filters per column: col 3
wxBoxSizer *needsItemFiltersCol3Sizer = new wxBoxSizer(wxVERTICAL);
needsItemFiltersSizer->Add(needsItemFiltersCol3Sizer, wxSizerFlags(1).Expand());
for ( int i = 8; i < 12; i++ )
{
wxCheckBox *filterCheck = new wxCheckBox(mainPanel, wxID_ANY, "filter " + wxString::Format(wxT("%d"), (int)(i + 1)));
needsItemFiltersCol3Sizer->Add(filterCheck, wxSizerFlags(1).Expand());
}
// ii. build line (3 variations: land/land+fixing, specific card, and other
// should put in a ramp, but for now just do "land"
wxBoxSizer *needsItemBuildLineSizer = new wxBoxSizer(wxHORIZONTAL);
needsItemSizer->Add(needsItemBuildLineSizer, wxSizerFlags(1).Expand());
// line item -> "("
wxButton *needsItemOpenBrackButton = new wxButton(mainPanel, wxID_ANY, "(");
needsItemBuildLineSizer->Add(needsItemOpenBrackButton, wxSizerFlags(1).Expand());
// line item -> cards to draw combo box
wxComboBox *cardsToDrawCombo = new wxComboBox(mainPanel, wxID_ANY);
cardsToDrawCombo->Append("1 to Draw");
cardsToDrawCombo->Append("2 to Draw");
cardsToDrawCombo->Append("3 to Draw");
cardsToDrawCombo->Append("4 to Draw");
cardsToDrawCombo->Append("5 to Draw");
cardsToDrawCombo->Append("6 to Draw");
cardsToDrawCombo->Append("7 to Draw");
cardsToDrawCombo->Append("8 to Draw");
cardsToDrawCombo->Append("9 to Draw");
cardsToDrawCombo->Append("10 to Draw");
needsItemBuildLineSizer->Add(cardsToDrawCombo, wxSizerFlags(1).Expand());
// line item -> filters to apply (any/all)
wxComboBox *filtersApplyTypeCombo = new wxComboBox(mainPanel, wxID_ANY);
filtersApplyTypeCombo->Append("Any");
filtersApplyTypeCombo->Append("All");
needsItemBuildLineSizer->Add(filtersApplyTypeCombo, wxSizerFlags(1).Expand());
// line item -> cost colors combo
wxComboBox *filtersCostColorsCombo = new wxComboBox(mainPanel, wxID_ANY);
filtersCostColorsCombo->Append("Any");
filtersCostColorsCombo->Append("Black");
filtersCostColorsCombo->Append("Blue");
filtersCostColorsCombo->Append("Green");
filtersCostColorsCombo->Append("Red");
filtersCostColorsCombo->Append("White");
needsItemBuildLineSizer->Add(filtersCostColorsCombo, wxSizerFlags(1).Expand());
// line item -> cost amount combo
wxComboBox *filtersCostAmountCombo = new wxComboBox(mainPanel, wxID_ANY);
filtersCostAmountCombo->Append("<= 1");
filtersCostAmountCombo->Append("<= 2");
filtersCostAmountCombo->Append("<= 3");
filtersCostAmountCombo->Append("<= 4");
filtersCostAmountCombo->Append("<= 5");
filtersCostAmountCombo->Append("<= 6");
needsItemBuildLineSizer->Add(filtersCostAmountCombo, wxSizerFlags(1).Expand());
// line item -> ")"
wxButton *needsItemCloseBrackButton = new wxButton(mainPanel, wxID_ANY, ")");
needsItemBuildLineSizer->Add(needsItemCloseBrackButton , wxSizerFlags(1).Expand());
// line item -> "AND"
wxButton *needsItemAndButton = new wxButton(mainPanel, wxID_ANY, "AND");
needsItemBuildLineSizer->Add(needsItemAndButton, wxSizerFlags(1).Expand());
// line item -> "OR"
wxButton *needsItemOrButton = new wxButton(mainPanel, wxID_ANY, "OR");
needsItemBuildLineSizer->Add(needsItemOrButton, wxSizerFlags(1).Expand());
// iii. line buttons (reset, + row below, - this row
wxBoxSizer *needsItemButtonSizer = new wxBoxSizer(wxHORIZONTAL);
needsItemSizer->Add(needsItemButtonSizer, wxSizerFlags(1).Expand());
// buttons
wxButton *needsItemInlineAddButton = new wxButton(mainPanel, wxID_ANY, "+");
needsItemButtonSizer->Add(needsItemInlineAddButton, wxSizerFlags(1).Expand());
wxButton *needsItemInlineRemoveButton = new wxButton(mainPanel, wxID_ANY, "-");
needsItemButtonSizer->Add(needsItemInlineRemoveButton, wxSizerFlags(1).Expand());
wxButton *needsItemInlineResetButton = new wxButton(mainPanel, wxID_ANY, "R");
needsItemButtonSizer->Add(needsItemInlineResetButton, wxSizerFlags(1).Expand());
// b2. At the bottom of all needs is a
// test control that has the build string
wxBoxSizer *needsBuildDisplaySizer = new wxBoxSizer(wxVERTICAL);
needsWrapSizer->Add(needsBuildDisplaySizer, wxSizerFlags(1).Expand());
// outputSizer (horizontal)
wxStaticText *buildDisplay = new wxStaticText(mainPanel, wxID_ANY, "Build Display");
buildDisplay->SetBackgroundColour(*wxBLUE);
needsBuildDisplaySizer->Add(buildDisplay, wxSizerFlags(1).Expand());
// at the bottom of the main panel stretches the log output
wxBoxSizer *outputSizer = new wxBoxSizer(wxHORIZONTAL);
mainPanelSizer ->Add(outputSizer, wxSizerFlags(1).Expand());
// logOutput StaticText
logOutput = new wxStaticText(mainPanel, wxID_ANY, "Output Terminal");
logOutput->SetBackgroundColour(*wxRED);
outputSizer ->Add(logOutput, wxSizerFlags(1).Expand());
mainPanel->SetSizerAndFit(mainPanelSizer);
this->Fit();
Thanks for your help.
Upvotes: 0
Views: 272
Reputation: 3554
With the code you posted, I'm not seeing gap2. Instead, I'm seeing the buttons enlarged to fill the entire space. I guess you changed the code slightly after the image was created. But both the enlargement of the buttons and gap2 will have the same cause.
You have optsSizer
which contains 2 other sizers optsInstructSizer
and needsWrapSizer
. Both of those sizers are added to optsSizer
with proportion 1. That means that both optsInstructSizer
and needsWrapSizer
will be sized to have the same size. Since the contents of needsWrapSizer
are much larger, that means that will have gap2 in the code that generated the image.
To solve this, simply add optsInstructSizer
to optsSizer
with proportion 0 like so:
optsSizer->Add(optsInstructSizer, wxSizerFlags(0).Expand());
or since 0 is the default value for the proportion argument, you can just use
optsSizer->Add(optsInstructSizer, wxSizerFlags().Expand());
(I always always use 0 even though it's not necessary to explicitly remind me that the item being added has proportion 0.) When an item is added to a sizer with proportion 0, it means that should be sized (verically in a vertical sizer or horizontally in a horizontal sizer) to its minimum size.
When you get rid of gap2, gap1 is removed for similar reasons. You have progSizer
which contains handSizer
and optsSizer
. Both are added with proportion 1 which means they will have the same size. When gap2 is removed, the vertical size optsSizer
shrinks which removes gap1 as well since handSizer
has the same vertical size.
Upvotes: 1