When dynamically changing the size of the elements within a wxNotebook (e.g. hiding a button), the size of the whole notebook element is not updated. This can leave white space or prevent some elements from being shown.
Normally, a call to the parent window's Fit() or FitInside() should do the trick, but doesn't for the notebook. How can we resize it?
Minimal example demonstrating the problem:
#include <wx/wx.h>
#include <wx/gbsizer.h>
#include <wx/notebook.h>
const int HIDEME_ID = 512, SHOWME_ID = 513;
class MyApp: public wxApp
{
wxButton* hideme;
wxSizer* panel_sizer, *frame_sizer, *sw_sizer;
wxScrolledWindow* sw;
wxNotebook* nb;
void hide_button( wxCommandEvent& ) {
hideme->Hide();
relayout();
}
void relayout() {
/* Insert layout code here */
}
void show_button( wxCommandEvent& ) {
hideme->Show();
relayout();
}
virtual bool OnInit() {
wxFrame *frame = new wxFrame( NULL, wxID_ANY, _("Hello World"), wxPoint(50, 50), wxSize(450, 340) );
frame_sizer = new wxBoxSizer( wxVERTICAL );
frame->SetSizer( frame_sizer );
sw = new wxScrolledWindow( frame, wxID_ANY );
sw->SetScrollRate( 5, 5 );
frame_sizer->Add( sw, 1, wxEXPAND );
sw_sizer = new wxBoxSizer( wxVERTICAL );
sw->SetSizer( sw_sizer );
nb = new wxNotebook( sw, wxID_ANY );
wxPanel* panel = new wxPanel( nb, wxID_ANY );
nb->AddPage( panel, wxT("Tab1") );
sw_sizer->Add( new wxButton( sw, wxID_ANY, _("Button1"), wxDefaultPosition, wxSize(200,200) ), 0, wxEXPAND );
sw_sizer->Add( nb, 0, wxEXPAND );
sw_sizer->Add( new wxButton( sw, wxID_ANY, _("Button3") ), 1, wxEXPAND );
sw_sizer->Add( new wxButton( sw, wxID_ANY, _("Button4") ), 0, wxEXPAND );
panel_sizer = new wxBoxSizer( wxVERTICAL );
panel_sizer->Add( hideme = new wxButton(panel, HIDEME_ID, wxT("HideMe")), 0, wxEXPAND );
hideme->Hide();
panel_sizer->Add( new wxButton(panel, SHOWME_ID, wxT("ShowMe")), 0, wxEXPAND );
panel->SetSizer( panel_sizer );
frame->Show(true);
SetTopWindow(frame);
return true;
}
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(MyApp, wxApp)
EVT_BUTTON(HIDEME_ID, MyApp::hide_button)
EVT_BUTTON(SHOWME_ID, MyApp::show_button)
END_EVENT_TABLE()
IMPLEMENT_APP( MyApp );
The somewhat surprising pitfall here is that, unlike many other windows, a wxNotebook caches its best size. We have to invalidate the cache before doing any layouting:
nb->InvalidateBestSize();
sw->FitInside();
Related
I have the following GUI created in wxFormBuilder:
gui.h:
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h
#include <wx/xrc/xmlres.h
#include <wx/intl.h
#include <wx/string.h
#include <wx/stattext.h
#include <wx/gdicmn.h
#include <wx/font.h
#include <wx/colour.h
#include <wx/settings.h
#include <wx/textctrl.h
#include <wx/sizer.h
#include <wx/statline.h
#include <wx/bitmap.h
#include <wx/image.h
#include <wx/icon.h
#include <wx/button.h
#include <wx/dialog.h
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class MainDialogBase
///////////////////////////////////////////////////////////////////////////////
class MainDialogBase : public wxDialog
{
private:
protected:
wxStaticText* m_staticText3;
wxStaticText* m_staticText1;
wxTextCtrl* m_textCtrl1;
wxStaticText* m_staticText4;
wxTextCtrl* m_textCtrl2;
wxStaticText* m_staticText6;
wxStaticText* m_staticText5;
wxTextCtrl* m_textCtrl3;
wxStaticText* m_staticText7;
wxTextCtrl* m_textCtrl4;
wxStaticLine* m_staticLine;
wxButton* m_button1;
wxButton* m_button2;
// Virtual event handlers, overide them in your derived class
virtual void OnCloseDialog( wxCloseEvent& event ) { event.Skip(); }
public:
MainDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 400,300 ), long style = wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE );
~MainDialogBase();
};
gui.cpp:
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "gui.h"
///////////////////////////////////////////////////////////////////////////
MainDialogBase::MainDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, >pos, size, style )
{
this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
wxBoxSizer* mainSizer;
mainSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer8;
bSizer8 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );
m_staticText3 = new wxStaticText( this, wxID_ANY, _("Patient's data"), wxDefaultPosition, wxSize( 105,-1 ), 0 );
m_staticText3->Wrap( -1 );
m_staticText3->SetFont( wxFont( 10, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxT("Sans") ) );
bSizer2->Add( m_staticText3, 0, wxALL, 5 );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxHORIZONTAL );
m_staticText1 = new wxStaticText( this, wxID_ANY, _("First Name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1->Wrap( -1 );
bSizer3->Add( m_staticText1, 0, wxALL, 5 );
m_textCtrl1 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
bSizer3->Add( m_textCtrl1, 0, wxALL, 5 );
bSizer2->Add( bSizer3, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer4;
bSizer4 = new wxBoxSizer( wxHORIZONTAL );
m_staticText4 = new wxStaticText( this, wxID_ANY, _("Last Name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText4->Wrap( -1 );
bSizer4->Add( m_staticText4, 0, wxALL, 5 );
m_textCtrl2 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
bSizer4->Add( m_textCtrl2, 0, wxALL, 5 );
bSizer2->Add( bSizer4, 1, wxEXPAND, 5 );
bSizer8->Add( bSizer2, 1, 0, 5 );
wxBoxSizer* bSizer5;
bSizer5 = new wxBoxSizer( wxVERTICAL );
m_staticText6 = new wxStaticText( this, wxID_ANY, _("Doctor's data"), wxDefaultPosition, wxSize( 105,-1 ), 0 );
m_staticText6->Wrap( -1 );
m_staticText6->SetFont( wxFont( 10, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxT("Sans") ) );
bSizer5->Add( m_staticText6, 0, wxALL, 5 );
wxBoxSizer* bSizer6;
bSizer6 = new wxBoxSizer( wxHORIZONTAL );
m_staticText5 = new wxStaticText( this, wxID_ANY, _("First Name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText5->Wrap( -1 );
bSizer6->Add( m_staticText5, 0, wxALL, 5 );
m_textCtrl3 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
bSizer6->Add( m_textCtrl3, 0, wxALL, 5 );
bSizer5->Add( bSizer6, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer7;
bSizer7 = new wxBoxSizer( wxHORIZONTAL );
m_staticText7 = new wxStaticText( this, wxID_ANY, _("Last Name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText7->Wrap( -1 );
bSizer7->Add( m_staticText7, 0, wxALL, 5 );
m_textCtrl4 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
bSizer7->Add( m_textCtrl4, 0, wxALL, 5 );
bSizer5->Add( bSizer7, 1, wxEXPAND, 5 );
bSizer8->Add( bSizer5, 1, 0, 5 );
mainSizer->Add( bSizer8, 1, wxEXPAND, 5 );
mainSizer->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticLine = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
mainSizer->Add( m_staticLine, 0, wxEXPAND | wxALL, 5 );
m_button1 = new wxButton( this, wxID_ANY, _("Record Data"), wxDefaultPosition, wxDefaultSize, 0 );
mainSizer->Add( m_button1, 0, wxALL|wxEXPAND, 5 );
m_button2 = new wxButton( this, wxID_ANY, _("List"), wxDefaultPosition, wxDefaultSize, 0 );
mainSizer->Add( m_button2, 0, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizer9;
bSizer9 = new wxBoxSizer( wxHORIZONTAL );
mainSizer->Add( bSizer9, 1, wxEXPAND, 5 );
this->SetSizer( mainSizer );
this->Layout();
this->Centre( wxBOTH );
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogBase::OnCloseDialog ) );
}
MainDialogBase::~MainDialogBase()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogBase::OnCloseDialog ) );
}
I also have the following inherited class:
inheritedgui.h:
#ifndef __inheritedgui__
#define __inheritedgui__
/**
#file
Subclass of MainDialogBase, which is generated by wxFormBuilder.
*/
#include "gui.h"
//// end generated include
/** Implementing MainDialogBase */
class inheritedgui : public MainDialogBase
{
protected:
// Handlers for MainDialogBase events.
void OnCloseDialog( wxCloseEvent& event );
public:
/** Constructor */
inheritedgui( wxWindow* parent );
//// end generated class members
};
#endif // __inheritedgui__
inheritedgui.cpp:
#include "inheritedgui.h"
inheritedgui::inheritedgui( wxWindow* parent )
:
MainDialogBase( parent )
{
}
void inheritedgui::OnCloseDialog( wxCloseEvent& event )
{
// TODO: Implement OnCloseDialog
}
Could you please tell me how to get text entered in m_textCtrl1 and assign it to a string variable when m_button1 is pressed?
I'm trying to port a simple program from JavaFX to C++, the program mainly takes user input (from wxTextCtrl controls) and assigns the input to string variables, so then I can show the values stored in the variables in a messagebox when m_button2 is pressed.
I've been doing some google searches, but C++ is getting a bit difficult for me.
m_textCtrl1 is a wxTextCtrl, which has a GetValue() method that returns a wxString, which in turn has a ToStdString() for converting to a std::string:
std::string s = m_textCtrl1->GetValue().ToStdString();
#etcCoder,
If you pan to use messagebox function from wxWidgets you dont need to convert the string to std::string - wxMessageBox() accepts wxString.
Thank you.
How to correctly show a MessageBox with the value of "string01"?
gui.h:
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/statline.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/dialog.h>
#include <wx/msgdlg.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class MainDialogBase
///////////////////////////////////////////////////////////////////////////////
class MainDialogBase : public wxDialog
{
private:
protected:
wxStaticText* m_staticText3;
wxStaticText* m_staticText1;
wxTextCtrl* m_textCtrl1;
wxStaticText* m_staticText4;
wxTextCtrl* m_textCtrl2;
wxStaticLine* m_staticLine;
wxButton* m_button1;
wxButton* m_button2;
// Virtual event handlers, overide them in your derived class
virtual void OnCloseDialog( wxCloseEvent& event ) { event.Skip(); }
virtual void m_button1OnButtonClick( wxCommandEvent& event ) { event.Skip(); }
virtual void m_button2OnButtonClick( wxCommandEvent& event ) { event.Skip(); }
public:
MainDialogBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 191,252 ), long style = wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE );
~MainDialogBase();
};
gui.cpp:
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "gui.h"
///////////////////////////////////////////////////////////////////////////
MainDialogBase::MainDialogBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
wxBoxSizer* mainSizer;
mainSizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer8;
bSizer8 = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL );
m_staticText3 = new wxStaticText( this, wxID_ANY, _("Patient's data"), wxDefaultPosition, wxSize( 105,-1 ), 0 );
m_staticText3->Wrap( -1 );
m_staticText3->SetFont( wxFont( 10, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxT("Sans") ) );
bSizer2->Add( m_staticText3, 0, wxALL, 5 );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxHORIZONTAL );
m_staticText1 = new wxStaticText( this, wxID_ANY, _("First Name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1->Wrap( -1 );
bSizer3->Add( m_staticText1, 0, wxALL, 5 );
m_textCtrl1 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
bSizer3->Add( m_textCtrl1, 0, wxALL, 5 );
bSizer2->Add( bSizer3, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer4;
bSizer4 = new wxBoxSizer( wxHORIZONTAL );
m_staticText4 = new wxStaticText( this, wxID_ANY, _("Last Name:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText4->Wrap( -1 );
bSizer4->Add( m_staticText4, 0, wxALL, 5 );
m_textCtrl2 = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
bSizer4->Add( m_textCtrl2, 0, wxALL, 5 );
bSizer2->Add( bSizer4, 1, wxEXPAND, 5 );
bSizer8->Add( bSizer2, 1, 0, 5 );
mainSizer->Add( bSizer8, 1, wxEXPAND, 5 );
m_staticLine = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
mainSizer->Add( m_staticLine, 0, wxEXPAND | wxALL, 5 );
m_button1 = new wxButton( this, wxID_ANY, _("Record Data"), wxDefaultPosition, wxDefaultSize, 0 );
mainSizer->Add( m_button1, 0, wxALL|wxEXPAND, 5 );
m_button2 = new wxButton( this, wxID_ANY, _("List"), wxDefaultPosition, wxDefaultSize, 0 );
mainSizer->Add( m_button2, 0, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizer9;
bSizer9 = new wxBoxSizer( wxHORIZONTAL );
mainSizer->Add( bSizer9, 1, wxEXPAND, 5 );
this->SetSizer( mainSizer );
this->Layout();
this->Centre( wxBOTH );
// Connect Events
this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogBase::OnCloseDialog ) );
m_button1->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogBase::m_button1OnButtonClick ), NULL, this );
m_button2->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogBase::m_button2OnButtonClick ), NULL, this );
}
MainDialogBase::~MainDialogBase()
{
// Disconnect Events
this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogBase::OnCloseDialog ) );
m_button1->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogBase::m_button1OnButtonClick ), NULL, this );
m_button2->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogBase::m_button2OnButtonClick ), NULL, this );
}
inheritedgui.h:
#ifndef __inheritedgui__
#define __inheritedgui__
/**
#file
Subclass of MainDialogBase, which is generated by wxFormBuilder.
*/
#include "gui.h"
//// end generated include
/** Implementing MainDialogBase */
class inheritedgui : public MainDialogBase
{
protected:
// Handlers for MainDialogBase events.
void OnCloseDialog( wxCloseEvent& event );
void m_button1OnButtonClick(wxCommandEvent& event) override;
void m_button2OnButtonClick(wxCommandEvent& event) override;
public:
/** Constructor */
inheritedgui( wxWindow* parent );
//// end generated class members
};
#endif // __inheritedgui__
inheritedgui.cpp:
#include "inheritedgui.h"
inheritedgui::inheritedgui( wxWindow* parent )
:
MainDialogBase( parent )
{
}
wxString string01;
void inheritedgui::m_button1OnButtonClick(wxCommandEvent& event)
{
string01 = m_textCtrl1->GetValue().ToStdString();
}
void inheritedgui::m_button2OnButtonClick(wxCommandEvent& event)
{
wxMessageBox( string01, wxT("This is the title"), wxICON_INFORMATION );
}
void inheritedgui::OnCloseDialog( wxCloseEvent& event )
{
// TODO: Implement OnCloseDialog
}
I'm trying to show the value of "string01" in a wxMessageBox (as seen in "inheritedgui.cpp"), however when I click "m_button2", nothing happens and I don't know why :/
https://i.postimg.cc/jd6WDc6z/Screenshot-20200227-040106.png
What changes do I need to do so the wxMessageBox shows up when I click "m_button2" (is the one which says "List")?
You are declaring std::string string01 in one method (m_button1OnButtonClick) and trying to use it in another one (m_button2OnButtonClick).
To be able to use it in another method like you are trying, make std::string string01 a member variable on class inheritedgui.
Then when you call:
wxMessageBox(wxString(string01.c_str(), wxConvUTF8), wxT("This is the title"), wxICON_INFORMATION);
Also, there is a particular need to use std::string instead of wxString? If not, just stick to wxString.
You don't need to convert the value you receive from the text control to std::string, as I said in the previous question.
You also need to declare this wxString as a member of the class.
And in order to fix the compilation error:
wxMessageBox( string01, wxT("This is the title"), wxICON_INFORMATION );
Also, it is preferred to use Bind() instead of Connect():
Bind( wxEVT_CLOSE_WINDOW, &inheritedGui::OnCloseDialog, this );
Bind( wxEVT_COMMAND_BUTTON_CLICKED, &inheritedGui::m_button1OnButtonClick, this );
In the destructor you don't have to UnBind() the event - it will happen automatically.
And finally - you don't have to declare the function virtual - it should work without. In fact event handlers in wxWidgets very rarely should be virtual.
Thank you.
I need unpack an archive which contains unicode characters for filenames in archives.
My code equivalent this:
#include "wx/wx.h"
#include <wx/archive.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include <wx/fs_arc.h>
#include "wx/fs_zip.h"
#include <memory>
class MyFrame : public wxFrame
{
public:
MyFrame(const wxString& title) :
wxFrame( NULL, -1, title, wxDefaultPosition, wxSize(350,180 ),
wxDEFAULT_FRAME_STYLE & ~ (wxRESIZE_BORDER | wxMAXIMIZE_BOX))
{
wxBoxSizer* Sizer = new wxBoxSizer( wxVERTICAL );
TextBox = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE );
Sizer->Add( TextBox, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 );
auto Button = new wxButton( this, wxID_ANY, wxT("Show entries"), wxDefaultPosition, wxDefaultSize, 0 );
Button->Bind(wxEVT_BUTTON, [this](wxCommandEvent&)
{
auto filename = "test.zip";
auto factory = wxArchiveClassFactory::Find(filename, wxSTREAM_FILEEXT);
if(!factory)
return;
std::unique_ptr<wxArchiveInputStream> inarc(factory->NewStream(new wxFFileInputStream(filename)));
std::unique_ptr<wxArchiveEntry> entry(factory->NewEntry());
while (entry.reset(inarc->GetNextEntry()), entry.get() != NULL)
TextBox->AppendText("Entry : "+entry->GetName()+"\n");
});
Sizer->Add( Button, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );
this->SetSizer( Sizer );
this->Layout();
}
private:
wxTextCtrl* TextBox;
};
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE
{
MyFrame *frame = new MyFrame(wxT("Test"));
frame->Show(true);
return true;
};
};
wxIMPLEMENT_APP(MyApp);
Is it possible to get the correct names for these files using wxWidgets?
Edit: I on Windows7 use wxWidgets 3.1.0, compiler - cl( 17.00.50727.1) VS11.
It seems you suffer this bug: http://trac.wxwidgets.org/ticket/17244 which has been fixed after wx3.1 release.
You need to download the current head code (available with git).
I have a simple wxFrame with 3 buttons. After I press Tab nothing happens. In the forum I found that wxFrame should process Tab button events normally and switch focus between controls. I tried with wxTAB_TRAVERSAL and without it, but look like no result.
Here is my code. wxWidgets 3.0.2. Please, help.
class TabWnd
: public wxFrame
{
public:
TabWnd()
: wxFrame(nullptr,
wxID_ANY,
wxEmptyString,
wxDefaultPosition,
wxDefaultSize,
wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)
{
wxBoxSizer* sz = new wxBoxSizer(wxVERTICAL);
wxButton* b1 = new wxButton(this, wxID_ANY, wxT("First"));
sz->Add(b1, 0, wxALL, 5);
wxButton* b2 = new wxButton(this, wxID_ANY, wxT("Second"));
sz->Add(b2, 0, wxALL, 5);
wxButton* b3 = new wxButton(this, wxID_ANY, wxT("Third"));
sz->Add(b3, 0, wxALL, 5);
SetSizer(sz);
Layout();
Centre(wxBOTH);
}
};
class WxguiApp
: public wxApp
{
public:
bool OnInit() override
{
TabWnd* mainWnd = new TabWnd();
mainWnd->Show();
SetTopWindow(mainWnd);
return true;
}
};
IMPLEMENT_APP(WxguiApp);
Try adding a panel between the frame and the buttons like this:
wxBoxSizer* sz = new wxBoxSizer(wxVERTICAL);
wxPanel* pnl = new wxPanel( this, wxID_ANY );
wxBoxSizer* sz2 = new wxBoxSizer( wxVERTICAL );
wxButton* b1 = new wxButton(pnl, wxID_ANY, wxT("First"));
sz2->Add(b1, 0, wxALL, 5);
wxButton* b2 = new wxButton(pnl, wxID_ANY, wxT("Second"));
sz2->Add(b2, 0, wxALL, 5);
wxButton* b3 = new wxButton(pnl, wxID_ANY, wxT("Third"));
sz2->Add(b3, 0, wxALL, 5);
pnl->SetSizer( sz2 );
sz->Add( pnl, 1, wxEXPAND );
SetSizer(sz);
Layout();
Centre(wxBOTH);
I pretend to "grab" and process the events: EVT_TEXT from wxTextCtrl and EVT_BUTTON from wxID_APPLY.
I try handling the events with Event Tables and I can't? Why?
The source code:
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
class Dialog : public wxDialog
{
public:
Dialog(wxWindow *parent, const wxString &title);
private:
void OnNameChange(wxCommandEvent &event);
void OnApply(wxCommandEvent &event);
wxDECLARE_EVENT_TABLE();
wxTextCtrl *m_name;
};
enum
{
ID_NAME = 1
};
Dialog::Dialog(wxWindow *parent, const wxString &title) :
wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
SetSizer(vbox);
wxFlexGridSizer *flexGrid = new wxFlexGridSizer(2, 2, 5, 5);
wxStaticText *label = new wxStaticText(this, wxID_ANY, "&Name:");
flexGrid->Add(label);
m_name = new wxTextCtrl(this, ID_NAME, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
flexGrid->Add(m_name, 1, wxEXPAND);
label = new wxStaticText(this, wxID_ANY, "&Description:");
flexGrid->Add(label);
m_description = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
flexGrid->Add(m_description, 1, wxEXPAND);
flexGrid->AddGrowableRow(1, 1);
flexGrid->AddGrowableCol(1, 1);
vbox->Add(flexGrid, 1, wxALL | wxEXPAND, 15);
vbox->Add(CreateSeparatedButtonSizer(wxAPPLY | wxCANCEL), 0, wxEXPAND | wxALL, 5);
}
void Dialog::OnNameChange(wxCommandEvent &event)
{
m_description->AppendText("Hello\n");
}
void Dialog::OnApply(wxCommandEvent &event)
{
m_description->AppendText("Apply\n");
}
wxBEGIN_EVENT_TABLE(Dialog, wxDialog)
EVT_TEXT(ID_NAME, Dialog::OnNameChange)
EVT_BUTTON(wxID_APPLY, Dialog::OnApply)
wxEND_EVENT_TABLE()
It's only possible to handle the events dynamically?
Bind(wxEVT_TEXT, &Dialog::OnNameChange, this, m_name->GetId());
The code as shown absolutely should work. It's not self-contained, so I can't test it, but there must be something else not shown here preventing it from working. Please try to make a SSCCE if you still can't isolate the problem yourself.