Lose focus event for wxTextCtrl? Topic is solved
-
- Experienced Solver
- Posts: 62
- Joined: Sun May 06, 2007 5:45 pm
Lose focus event for wxTextCtrl?
How can I find out when my text control loses focus?
I'm trying to avoid making the user hit return before accepting their text input. I just want to grab the text out of the control when the user finishes typing and tabs out or clicks a button.
I'm trying to avoid making the user hit return before accepting their text input. I just want to grab the text out of the control when the user finishes typing and tabs out or clicks a button.
What I would do is, subclass wxTextCtrl, then override wxWindow::SetFocus().
SetFocus is called when focus is set and "killed".
It is virtual so it is "override-ready".
http://docs.wxwidgets.org/stable/wx_wxw ... owsetfocus
Then use wxWindow::FindFocus() within the method to see if your/this control has the keyboard focus.
Regards.
SetFocus is called when focus is set and "killed".
It is virtual so it is "override-ready".
http://docs.wxwidgets.org/stable/wx_wxw ... owsetfocus
Then use wxWindow::FindFocus() within the method to see if your/this control has the keyboard focus.
Regards.
-
- Experienced Solver
- Posts: 62
- Joined: Sun May 06, 2007 5:45 pm
Re:
Is there no other way to get the event when textctrl looses focus? I really want to use wxTextCtrl and not some other custom class.protocol wrote:What I would do is, subclass wxTextCtrl, then override wxWindow::SetFocus().
SetFocus is called when focus is set and "killed".
It is virtual so it is "override-ready".
http://docs.wxwidgets.org/stable/wx_wxw ... owsetfocus
Then use wxWindow::FindFocus() within the method to see if your/this control has the keyboard focus.
Regards.
Re: Re:
I may be missing something but using wxEVT_KILL_FOCUS seems to work just fine?gtafan wrote:Is there no other way to get the event when textctrl looses focus? I really want to use wxTextCtrl and not some other custom class.
Code: Select all
#include <wx/wx.h>
class MyDialog : public wxDialog
{
public:
MyDialog () : wxDialog(NULL, wxID_ANY, "Test")
{
wxPanel* mainPanel = new wxPanel(this);
wxTextCtrl* textCtrl = new wxTextCtrl(mainPanel , wxID_ANY);
textCtrl->Bind(wxEVT_KILL_FOCUS, &MyDialog::OnKillFocus, this);
wxTextCtrl* logCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
mainSizer->Add(textCtrl, wxSizerFlags().Expand().Border());
mainSizer->Add(new wxButton(mainPanel, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());
mainSizer->Add(logCtrl, wxSizerFlags().Expand().Border().Proportion(1));
mainPanel->SetSizer(mainSizer);
}
private:
void OnKillFocus(wxFocusEvent& event)
{
wxLogMessage("textCtrl has just lost focus");
event.Skip();
}
};
class MyApp : public wxApp
{
public:
bool OnInit()
{
MyDialog().ShowModal();
return false;
}
}; wxIMPLEMENT_APP(MyApp);
Re: Re:
Seems not to worck for me, the only diference I am using Connect instead of Bind:PB wrote:I may be missing something but using wxEVT_KILL_FOCUS seems to work just fine?gtafan wrote:Is there no other way to get the event when textctrl looses focus? I really want to use wxTextCtrl and not some other custom class.Code: Select all
#include <wx/wx.h> class MyDialog : public wxDialog { public: MyDialog () : wxDialog(NULL, wxID_ANY, "Test") { wxPanel* mainPanel = new wxPanel(this); wxTextCtrl* textCtrl = new wxTextCtrl(mainPanel , wxID_ANY); textCtrl->Bind(wxEVT_KILL_FOCUS, &MyDialog::OnKillFocus, this); wxTextCtrl* logCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2); wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl)); wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); mainSizer->Add(textCtrl, wxSizerFlags().Expand().Border()); mainSizer->Add(new wxButton(mainPanel, wxID_ANY, "Button"), wxSizerFlags().Expand().Border()); mainSizer->Add(logCtrl, wxSizerFlags().Expand().Border().Proportion(1)); mainPanel->SetSizer(mainSizer); } private: void OnKillFocus(wxFocusEvent& event) { wxLogMessage("textCtrl has just lost focus"); event.Skip(); } }; class MyApp : public wxApp { public: bool OnInit() { MyDialog().ShowModal(); return false; } }; wxIMPLEMENT_APP(MyApp);
Code: Select all
Connect(ID_TEXTCTRL1,wxEVT_KILL_FOCUS,(wxObjectEventFunction)&MyFrame::OnKillFocus);
Re: Lose focus event for wxTextCtrl?
Yes. You don't show the context of your Connect(), but I would guess you're doing it inside the MyFrame class. Focus events don't propagate, so the frame will never see them.Can Connect be the problem? If yes, why?
Try textCtrl->Connect(ID_TEXTCTRL1,wxEVT_KILL_FOCUS,(wxObjectEventFunction)&MyFrame::OnKillFocus);
Re: Re:
Actually, it seems you made another important change, which broke the code. You now call Connect() on MyFrame, not on the wxTextCtrl instance (the call in my code was textCtrl->Bind()). wxEVT_KILL_FOCUS is not a command event, therefore it does not propagate upwards. Change the call accordingly, it should fix it.gtafan wrote:Seems not to worck for me, the only diference I am using Connect instead of Bind:Code: Select all
Connect(ID_TEXTCTRL1,wxEVT_KILL_FOCUS,(wxObjectEventFunction)&MyFrame::OnKillFocus);
BTW, using Connect() in new code is not recommended, unless you have a good reason for it. Bind() is more flexible, less error prone and it does not require the ugly cast.
Re: Re:
So it was really Connect(), that cased the problem?PB wrote:Actually, it seems you made another important change, which broke the code. You now call Connect() on MyFrame, not on the wxTextCtrl instance (the call in my code was textCtrl->Bind()). wxEVT_KILL_FOCUS is not a command event, therefore it does not propagate upwards. Change the call accordingly, it should fix it.gtafan wrote:Seems not to worck for me, the only diference I am using Connect instead of Bind:Code: Select all
Connect(ID_TEXTCTRL1,wxEVT_KILL_FOCUS,(wxObjectEventFunction)&MyFrame::OnKillFocus);
BTW, using Connect() in new code is not recommended, unless you have a good reason for it. Bind() is more flexible, less error prone and it does not require the ugly cast.
The reason I am using Connect() is because I am using wxSmith and there Connect() is always used.
Re: Re:
No, the problem was as both David and me wrote: You changed the control on which the method (Connect) is called, from wxTextCtrl to (probably) its parent. If you did the same to Bind(), it would be wrong as well.gtafan wrote:So it was really Connect(), that cased the problem?
Re: Re:
OK, now I see, normaly wxSmith does the really complicated stuff for me, so I am not so familiar with the way event handlers are initialized. Thanks for the explanation.PB wrote:No, the problem was as both David and me wrote: You changed the control on which the method (Connect) is called, from wxTextCtrl to (probably) its parent. If you did the same to Bind(), it would be wrong as well.gtafan wrote:So it was really Connect(), that cased the problem?
Re: Lose focus event for wxTextCtrl?
Since I have more then 1 textCtrl, I am geting problems to acces the textCtrl again once it lost focus. After comenting out this line:
everithing worcks fine again.
Code: Select all
textCtrl->Bind(wxEVT_KILL_FOCUS, &MyDialog::OnKillFocus, this);
Re: Lose focus event for wxTextCtrl?
What do you mean by "problems to acces the textCtrl"? Do you mean that the user cannot set focus to the control with keyboard and/or mouse?
Do you call event.Skip() in the wxEVT_KILL_FOCUS handler (see my previous code)?
Can you reproduce the issue with the MyDialog code below?
Do you call event.Skip() in the wxEVT_KILL_FOCUS handler (see my previous code)?
Can you reproduce the issue with the MyDialog code below?
Code: Select all
#include <wx/wx.h>
class MyDialog : public wxDialog
{
public:
MyDialog () : wxDialog(NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(800, 500))
{
wxPanel* mainPanel = new wxPanel(this);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
for ( size_t i = 0; i < 5; ++i )
AddTextCtrl(mainPanel, mainSizer, wxString::Format("wxTextCtrl #%zu", i + 1));
mainSizer->Add(new wxButton(mainPanel, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());
wxTextCtrl* logCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));
mainSizer->Add(logCtrl, wxSizerFlags().Expand().Border().Proportion(1));
mainPanel->SetSizer(mainSizer);
}
private:
void AddTextCtrl(wxWindow* parent, wxSizer* sizer, const wxString& name)
{
sizer->Add(new wxStaticText(parent, wxID_ANY, name),
wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT));
wxTextCtrl* textCtrl = new wxTextCtrl(parent, wxID_ANY);
textCtrl->Bind(wxEVT_KILL_FOCUS, &MyDialog::OnKillFocus, this);
textCtrl->SetName(name);
sizer->Add(textCtrl, wxSizerFlags().Expand().Border(wxLEFT | wxBOTTOM | wxRIGHT));
}
void OnKillFocus(wxFocusEvent& event)
{
wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
wxLogMessage("wxTextCtrl named '%s' has just lost focus", textCtrl->GetName());
event.Skip();
}
};
class MyApp : public wxApp
{
public:
bool OnInit()
{
MyDialog().ShowModal();
return false;
}
}; wxIMPLEMENT_APP(MyApp);
Re: Lose focus event for wxTextCtrl?
Forgot about that event.Skip(), but an other problem seems to be because the textCtrls are inside notebook page and switching between textCtrls using tab not always worcking.PB wrote:What do you mean by "problems to acces the textCtrl"? Do you mean that the user cannot set focus to the control with keyboard and/or mouse?
Do you call event.Skip() in the wxEVT_KILL_FOCUS handler (see my previous code)?
Can you reproduce the issue with the MyDialog code below?Code: Select all
#include <wx/wx.h> class MyDialog : public wxDialog { public: MyDialog () : wxDialog(NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(800, 500)) { wxPanel* mainPanel = new wxPanel(this); wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); for ( size_t i = 0; i < 5; ++i ) AddTextCtrl(mainPanel, mainSizer, wxString::Format("wxTextCtrl #%zu", i + 1)); mainSizer->Add(new wxButton(mainPanel, wxID_ANY, "Button"), wxSizerFlags().Expand().Border()); wxTextCtrl* logCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2); wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl)); mainSizer->Add(logCtrl, wxSizerFlags().Expand().Border().Proportion(1)); mainPanel->SetSizer(mainSizer); } private: void AddTextCtrl(wxWindow* parent, wxSizer* sizer, const wxString& name) { sizer->Add(new wxStaticText(parent, wxID_ANY, name), wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT)); wxTextCtrl* textCtrl = new wxTextCtrl(parent, wxID_ANY); textCtrl->Bind(wxEVT_KILL_FOCUS, &MyDialog::OnKillFocus, this); textCtrl->SetName(name); sizer->Add(textCtrl, wxSizerFlags().Expand().Border(wxLEFT | wxBOTTOM | wxRIGHT)); } void OnKillFocus(wxFocusEvent& event) { wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject()); wxLogMessage("wxTextCtrl named '%s' has just lost focus", textCtrl->GetName()); event.Skip(); } }; class MyApp : public wxApp { public: bool OnInit() { MyDialog().ShowModal(); return false; } }; wxIMPLEMENT_APP(MyApp);
Re: Lose focus event for wxTextCtrl?
Please do not quote whole posts, perhaps no quoting is necessary when responding to the last post.
Are you sure the notebook issue is caused by handling the kill focus event, i.e., it persists even when you do not bind the handler for the event? TBH, I am not sure what the issue is exactly, and what is "not always"? Also make sure you do not do things you are not supposed to do in a handler for such events, remember the trouble you had using a message box in a wxEVT_SPINCTRL handler.
I did not observe any issues during cursory testing the simple code below, can you?
Are you sure the notebook issue is caused by handling the kill focus event, i.e., it persists even when you do not bind the handler for the event? TBH, I am not sure what the issue is exactly, and what is "not always"? Also make sure you do not do things you are not supposed to do in a handler for such events, remember the trouble you had using a message box in a wxEVT_SPINCTRL handler.
I did not observe any issues during cursory testing the simple code below, can you?
Code: Select all
#include <wx/wx.h>
#include <wx/notebook.h>
class MyDialog : public wxDialog
{
public:
MyDialog () : wxDialog(NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(800, 500), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxNotebook* notebook = new wxNotebook(this, wxID_ANY);
AddPage(notebook, "Page 1");
AddPage(notebook, "Page 2");
AddPage(notebook, "Page 3");
mainSizer->Add(notebook, wxSizerFlags().Expand().Border().Proportion(2));
wxTextCtrl* logCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));
mainSizer->Add(logCtrl, wxSizerFlags().Expand().Border().Proportion(1));
SetSizer(mainSizer);
}
private:
void AddPage(wxNotebook* notebook, const wxString& pageName)
{
wxPanel* panel = new wxPanel(notebook);
wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
for ( size_t i = 0; i < 5; ++i )
AddTextCtrl(panel, panelSizer, wxString::Format("%s: wxTextCtrl #%zu", pageName, i + 1));
panelSizer->Add(new wxButton(panel, wxID_ANY, "Button"), wxSizerFlags().Expand().Border());
panel->SetSizer(panelSizer);
notebook->AddPage(panel, pageName);
}
void AddTextCtrl(wxWindow* parent, wxSizer* sizer, const wxString& name)
{
sizer->Add(new wxStaticText(parent, wxID_ANY, name),
wxSizerFlags().Expand().Border(wxLEFT | wxRIGHT));
wxTextCtrl* textCtrl = new wxTextCtrl(parent, wxID_ANY);
textCtrl->Bind(wxEVT_KILL_FOCUS, &MyDialog::OnKillFocus, this);
textCtrl->SetName(name);
sizer->Add(textCtrl, wxSizerFlags().Expand().Border(wxLEFT | wxBOTTOM | wxRIGHT));
}
void OnKillFocus(wxFocusEvent& event)
{
wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());
wxLogMessage("wxTextCtrl lost focus: '%s'.", textCtrl->GetName());
event.Skip();
}
};
class MyApp : public wxApp
{
public:
bool OnInit()
{
MyDialog().ShowModal();
return false;
}
}; wxIMPLEMENT_APP(MyApp);