How to resize frame after hiding a component in wxwidgets - c++

I have a frame which has 4 textboxes and one link(change no of textboxes). when user clicks on link I am hiding 4th textbox. but what happens is after hiding 4th textbox, it's space remains blank. I don't want to keep its space blank. That space should disappear and frame should get resized. Is there any way that I can achieve this? when user again clicks on the link(change no of textboxes I am again displaying 4th textbox.
code:
m_ComputerNameText1 = new wxTextCtrl(m_panel, wxID_ANY, "computerName", wxDefaultPosition, wxSize(250, wxDefaultSize.GetHeight()));
m_ComputerNameText2 = new wxTextCtrl(m_panel, wxID_ANY, "computerName1", wxDefaultPosition, wxSize(250, wxDefaultSize.GetHeight()));
m_ComputerNameText3 = new wxTextCtrl(m_panel, wxID_ANY, "computerName3", wxDefaultPosition, wxSize(250, wxDefaultSize.GetHeight()));
m_ComputerNameText4 = new wxTextCtrl(m_panel, wxID_ANY, "computerName4", wxDefaultPosition, wxSize(250, wxDefaultSize.GetHeight()));
m_hyperLinkOption = new wxHyperlinkCtrl(m_panel, wxID_ANY, "Change no of textboxes", wxT(""), wxDefaultPosition, wxSize(135, wxDefaultSize.GetHeight()));
m_userPassSizer->Add(m_ComputerNameText1, 0, wxALIGN_LEFT | wxALL, 0);
m_userPassSizer->Add(m_ComputerNameText2, 0, wxALIGN_LEFT | wxALL, 0);
m_userPassSizer->Add(m_ComputerNameText3, 0, wxALIGN_LEFT | wxALL, 0);
m_userPassSizer->Add(m_ComputerNameText4, 0, wxALIGN_LEFT | wxALL, 0);
m_userPassSizer->Add(m_hyperLinkOption , 0, wxALIGN_LEFT | wxALL, 0);
Following function executes when hyperlink is clicked.
void OnAuthCodeOptionLinkClicked(wxHyperlinkEvent& event)
{
if (!m_hyperlinkOptionSelected)
{
m_hyperlinkOptionSelected= true;
m_ComputerNameText4->Hide();
m_hyperLinkOption->SetLabel("Go back");
}
else
{
m_hyperlinkOptionSelected= false;
m_ComputerNameText4->Show();
m_hyperLinkOption->SetLabel("change no of textboxes");
}
}
in this way I have to hide and show 4th textbox. After hiding some blank space remains. How can I avaoid that blank space and take link in the place of 4th textbox ?

Whenever I need to dynamically update the size of a control, I always call Layout() and Refresh().
You can find more info about Layout here:
http://docs.wxwidgets.org/3.1/classwx_window.html#a1b143c3e72bd0af533b76db4830a6113
As well as some good info on window sizing in general here:
http://docs.wxwidgets.org/3.1/overview_windowsizing.html
Calling Layout assumes that your class where you construct and manage your textboxes, etc. is a wxWindow derived control itself (like a panel, frame, whatever). If not, like you are making the changes on a view-model, you will need to call Layout and Refresh on the owning window:
void UpdateView()
{
view->Layout();
view->Refresh();
}
You may need to play around with your sizers, minimum size of windows, etc. to get the exact behavior you want.

Related

Why does the second wxSizer fail to center the button?

I created a global panel and called a method that creates a sizer and a button. The button clears the sizer (i.e., also the panel), and then deletes is. Then, another method is called, using the same logic, it creates another sizer and another button. This time they don't work.
my code(windows, vs studio):
#include "MainFrame.h"
#include <wx/wx.h>s
MainFrame::MainFrame(const wxString& title) : wxFrame(nullptr, wxID_ANY, title)
{
panel = new wxPanel(this);
StartParty(panel);
}
void MainFrame::ClearButtonClicked(wxCommandEvent& evt)
{
panel->GetSizer()->Clear(true);
panel->SetSizerAndFit(nullptr);
ChooseMode(panel);
}
void MainFrame::StartParty(wxPanel* parent)
{
wxButton* start_button = new wxButton(parent, wxID_ANY, "Start the Party!", wxDefaultPosition, wxSize(200, 70));
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->AddStretchSpacer(1);
sizer->Add(
start_button,
0,
wxALL | wxALIGN_CENTER,
0);
sizer->AddStretchSpacer(1);
parent->SetSizerAndFit(sizer);
start_button->Bind(wxEVT_BUTTON, &MainFrame::ClearButtonClicked, this);
}
void MainFrame::ChooseMode(wxPanel* parent)
{
wxButton* select_button = new wxButton(parent, wxID_ANY, "Choose", wxDefaultPosition, wxSize(200, 70));
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->AddStretchSpacer(1);
sizer->Add(
select_button,
0,
wxALL | wxALIGN_CENTER,
0);
sizer->AddStretchSpacer(1);
parent->SetSizer(sizer);
}
You do need Layout(), as mentioned in the comments, as this is what actually repositions the windows -- SetSizer() just specifies the sizer to use for doing it, but doesn't do anything on its own immediately (it will when the window is resized the next time, as this results in a call to Layout()).
However, even if it's somewhat unrelated to the question itself, I think you shouldn't be doing this at all and use wxSimplebook instead. This simple (sic) class allows you to add a few pages to it and then easily switch between them.

Interaction between wxPanel and wxFrame

I am trying to understand how wxFrame and wxPanel work together. I am having a hard time explaining the following code behavior:
I am trying to set up the GUI for my application. I have a function that creates a form for data entry:
void MyFrame::Initialize_Project_Info() {
//Info_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(600, 1000), wxTAB_TRAVERSAL, _T(""));
//Info_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T(""));
Info_Box = new wxBoxSizer(wxHORIZONTAL);
Info_Staticbox = new wxStaticBoxSizer(wxHORIZONTAL, Info_Panel, _T("Project Information"));
Info_Grid = new wxFlexGridSizer(4, 2, 0, 0);
//Note wsSize(width,height).
Project_Name = new wxStaticText(Info_Panel, wxID_ANY, _T("Project:"));
Engineer_Name = new wxStaticText(Info_Panel, wxID_ANY, _T("Engineer:"));
CrossSection_Name = new wxStaticText(Info_Panel, wxID_ANY, _T("Cross Section ID:"));
Additional_Notes = new wxStaticText(Info_Panel, wxID_ANY, _T("Additional Notes:"));
Enter_PN = new wxTextCtrl(Info_Panel, ENTER_PN, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB, wxDefaultValidator, _T(""));
Enter_EN = new wxTextCtrl(Info_Panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB, wxDefaultValidator, _T(""));
Enter_CSN = new wxTextCtrl(Info_Panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB, wxDefaultValidator, _T(""));
Enter_AN = new wxTextCtrl(Info_Panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(250, 100), wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxTE_MULTILINE, wxDefaultValidator, _T(""));
Info_Grid->Add(Project_Name,
wxSizerFlags().Align(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL)
.Border(wxTOP | wxBOTTOM | wxLEFT));
Info_Grid->Add(Enter_PN, wxSizerFlags().Expand().Border(wxALL));
Info_Grid->Add(Engineer_Name,
wxSizerFlags().Align(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL)
.Border(wxBOTTOM | wxLEFT));
Info_Grid->Add(Enter_EN, wxSizerFlags().Expand().Border(wxBOTTOM | wxLEFT | wxRIGHT));
Info_Grid->Add(CrossSection_Name,
wxSizerFlags().Align(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL)
.Border(wxBOTTOM | wxLEFT));
Info_Grid->Add(Enter_CSN,
wxSizerFlags().Expand().Border(wxBOTTOM | wxLEFT | wxRIGHT));
Info_Grid->Add(Additional_Notes,
wxSizerFlags().Align(wxALIGN_LEFT).Border(wxBOTTOM | wxLEFT));
Info_Grid->Add(Enter_AN, wxSizerFlags().Expand().Border(wxBOTTOM | wxLEFT | wxRIGHT));
Info_Staticbox->Add(Info_Grid);
Info_Box->Add(Info_Staticbox, wxSizerFlags().Border(wxALL));
Info_Panel->SetSizer(Info_Box);
}
This code works if I append all the objects to a wxPanel when only defined in the scope of the function. If I define the wxPanel in the scope of the constructor of the wxFrame derived class, it does not work.
For example, doing this does not generate the form as intended:
MyFrame::MyFrame() : wxFrame(NULL,wxID_ANY,"Cross Sectional Beam Properties",wxDefaultPosition,wxSize(1200,600),wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)) {
Info_Panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T(""));
Initialize_Project_Info();
}
So, my question is how does wxPanel interface with wxFrame. Why would one moving one line of code (i.e. wxPanel initialization) change the outcome?
From the wx docs:
A frame is a window whose size and position can (usually) be changed
by the user. It usually has thick borders and a title bar, and can
optionally contain a menu bar, toolbar and status bar.
A panel is a window on which controls are placed. It is usually
placed within a frame. Its main feature over its parent class wxWindow
is code for handling child windows and TAB traversal.
wxWindow is a generic class used by any type of window. wxDialog is mainly used as a form where the user enters data.
Usually an application shows a frame as the main window of the app.
==> While you can place controls directly in a wxFrame, because of 'TAB traversal' and a OS's typical background features you better use a wxPanel.
This panel is a child of the main wxFrame and you can buid it at wxFrame's ctor.
Because in wxWidgets if a wxFrame has an unique child then this child is expanded to fit the whole client size of the wxFrame, then you don't use wxsizers for this panel-to-frame fitting.
When you create the controls (e.g. at wxPanel ctor) you set this wxPanel as the parent of the controls. And use sizers to layout them into the panel.
So each control has your panel as parent; an your panel has the frame as parent. Don't forget that 'this' pointers may be used as parents, or pass the parent as a parameter in the function that creates the windows (panel, controls).
Finally, the pointers to any wxWindow-derived class are created with "new", but you don't need to delete them, wxWigets internals takes care of their deletion.

How to set the size of a toolbar button

I am trying to make a toolbar with some radio buttons. The Problem is that when I add a button in the toolbar, the button is too big,bigger than the height of the toolbar. I have already tried to set the size of the bitmap with not any result. However there is not any function to set the size of the tool itself. Is there any way to make it?
this->m_ToolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL | wxNO_BORDER | wxTB_TEXT | wxTB_NOICONS);
this->m_ToolBar->AddRadioTool(this->LastToolBarId, Name, wxNullBitmap, wxNullBitmap, toolTip, wxT(""), Data);
this->m_ToolBar->ToggleTool (this->LastToolBarId, true);
this->m_ToolBar->Realize();
Ok I found it. I didn't know that there is a white bitmap(16x15) over the text of the tool. So the answer is quite simple. I use SetToolBitmapSize with size (1,1)
this->m_ToolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL | wxNO_BORDER | wxTB_TEXT | wxTB_NOICONS);
this->m_ToolBar->SetToolBitmapSize(wxSize(1,1));
this->m_ToolBar->AddRadioTool(this->LastToolBarId, Name, wxNullBitmap, wxNullBitmap, toolTip, wxT(""), Data);
this->m_ToolBar->ToggleTool (this->LastToolBarId, true);
this->m_ToolBar->Realize();

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

wxWidgets ribbonBar taking up entire window

I've spent the past day figuring out how to get a wxRibbon bar. It took some work, but I finally got a ribbon bar working. Except that the ribbon bar takes up the entire window, except for a tiny space on the right side of my application.
The code I'm using to test in my main window is as follow:
Win_app::Win_app(const wxString& title)
: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(640, 480))
{
wxRibbonBar* mainMenu = new wxRibbonBar(this,-1,wxDefaultPosition,wxSize(20,40));
wxRibbonPage* home = new wxRibbonPage(mainMenu, wxID_ANY, wxT("Home"));
wxRibbonPanel *test_panel1 = new wxRibbonPanel(home, wxID_ANY, wxT("Panel 1"),
wxNullBitmap, wxDefaultPosition, wxSize(320,60));
wxRibbonPanel *test_panel2 = new wxRibbonPanel(home, wxID_ANY, wxT("Panel 2"),
wxNullBitmap, wxDefaultPosition, wxSize(320,60));
wxRibbonPage* page = new wxRibbonPage(mainMenu, wxID_ANY, wxT("Another Page"));
wxRibbonPanel *test_panel3 = new wxRibbonPanel(page, wxID_ANY, wxT("Panel 3"),
wxNullBitmap, wxDefaultPosition, wxSize(640,60));
mainMenu->Realize();
Centre();
}
I'm using wxWidgets 2.9.4. Any help would be much appreciated! Thanks for reading.
I would suggest taking a look at the ribbon sample in your wxWidgets install located at wxdir\samples\ribbon. It looks to be doing roughly the same as your code with a key difference in that it adds the wxRibbonBar to a sizer:
wxSizer *s = new wxBoxSizer(wxVERTICAL);
s->Add(m_ribbon, 0, wxEXPAND);
s->Add(m_logwindow, 1, wxEXPAND);
s->Add(m_togglePanels, wxSizerFlags().Border());
SetSizer(s);
You need to do this because if there is a single control on a dialog it automatically fills the dialog, which in your case is unwanted behaviour.