Mega Search
23.2 Million


Sign Up

Make a donation  
Problems with losing focus on wxTextCtrl in wxGTK  
News Group: comp.soft-sys.wxwindows

I have an application where I have multiple wxTextCtrls on a panel. I
would like to validate the contents to be sure they are valid (i.e,
positive floating point number). On an invalid entry, I would like to
display a wxMessageBox with the error. When the user dismisses the
message box I would like to set focus to the text field in question
and select the text in it.

It was no problem to validate when the user hits the enter key.

I also wanted to validate when the focus is lost on the (possibly bad)
text field, for example the user might enter text in one field and
then click on another text field.

I was having problems changing focus within a focus event handler;
that is, when focus is lost on a text field with bad data, I was
having problems setting the focus back to the text field with bad
data. However, I got things working reasonably well by just flagging
the error in the "Kill Focus" event handler and then changing the
focus in an "Idle" event handler that checked for the flagged error.

The problem is as follows:
1) I enter bad data in  text field #1
2) I click on text field #2
3) I get a wxMessageBox with an error msg; I click OK
4) The focus is now on text field #1 with its text selected (as I
wanted), but the text appears and disappears on text field #2 as I
swipe the cursor back and forth on text field #2. This keeps happening
until I click on text field #2. It seems as though the system thinks
there is still some sort of "psuedo focus" on text field #2? Note that
this problem does not occur if I do not pop up the wxMessageBox.

I tried to recreate the problem in this test program. In this sample,
the text in text field #2 does not appear and disappears, it gets
highlighted/unhighlighted as I swipe the cursor over it; I assume this
is a symptom of the same problem.

Is this a bug? Am I doing something wrong? Is there a better way to
accomplish what I am trying to do?

The sample is as follows... it just have two text fields that take a
valid floating point number:

__________________________________


#include 
using namespace std;
#include "wx/wx.h"

#define TC_ID_1   wxID_HIGHEST      + 1
#define TC_ID_2   TC_ID_1           + 1

class MyApp : public wxApp
{
public:
   virtual bool OnInit();
};

class MyFrame : public wxFrame
{
public:
   MyFrame(const wxString& title);

   bool ValidateMe(int id);
   void OnTextEntered(wxCommandEvent& e);
   void OnIdle(wxIdleEvent& e);
   void OnLostFocus(wxFocusEvent& e);

private:
   wxTextCtrl    *m_tc1;
   wxTextCtrl    *m_tc2;
   wxTextCtrl    *m_err_tc;
   bool           m_err_ack;
   DECLARE_EVENT_TABLE()
};

DECLARE_APP(MyApp)
IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
   MyFrame *frame = new MyFrame(wxT("Minimal App"));
   frame->Show(true);
   return true;
}

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
   EVT_TEXT_ENTER(TC_ID_1,   MyFrame::OnTextEntered)
   EVT_TEXT_ENTER(TC_ID_2,   MyFrame::OnTextEntered)
   EVT_IDLE(                 MyFrame::OnIdle)
END_EVENT_TABLE()


MyFrame::MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY,
title)
{
    m_err_tc = 0;
    m_err_ack = false;

    m_tc1 = new wxTextCtrl(this, TC_ID_1, "0",
       wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
    m_tc2 = new wxTextCtrl(this, TC_ID_2, "0",
       wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);

    m_tc1->Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(
       MyFrame::OnLostFocus), NULL, this);
    m_tc2->Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(
       MyFrame::OnLostFocus), NULL, this);

    wxBoxSizer *s = new wxBoxSizer(wxVERTICAL);
    s->Add(m_tc1, 0, wxEXPAND|wxALL, 5);
    s->Add(m_tc2, 0, wxEXPAND|wxALL, 5);
    SetSizerAndFit(s);
}

void MyFrame::OnTextEntered(wxCommandEvent& e)
{
   ValidateMe(e.GetId());
}

void MyFrame::OnLostFocus(wxFocusEvent& e)
{
   ValidateMe(e.GetId());
   e.Skip();
}

void MyFrame::OnIdle(wxIdleEvent& e)
{
   if (m_err_ack) {
      wxTextCtrl *tc = m_err_tc;
      m_err_tc = 0;
      m_err_ack = false;
      tc->SetFocus();
      tc->SetSelection(-1, -1);
   }
   e.Skip();
}

bool MyFrame::ValidateMe(int id)
{
   bool ok = true;
   wxTextCtrl *tc = 0;

   if (id == TC_ID_1) {
      tc = m_tc1;
   } else if (id == TC_ID_2) {
      tc = m_tc2;
   }

   if (tc) {
      wxString s = tc->GetValue();
      double d;
      if (!s.ToDouble(&d)) {
         ok = false;
         tc->ChangeValue("0");
         m_err_tc = tc;

         // Comment out the next showing of the dialog box and the
         // error does not occur
         wxMessageDialog d(tc, "Not a valid float!", "Error",
            wxOK|wxICON_ERROR);
         d.ShowModal();

         m_err_ack = true;
      }
   }

   return ok;
}





Vote for best question.
Score: 0  # Vote:  0
Date Posted: 21-Aug-2011, at 1:31 PM EST
From: Marco DeFreitas
 
Re: Problems with losing focus on wxTextCtrl in wxGTK  
News Group: comp.soft-sys.wxwindows
Op zaterdag 27 augustus 2011 00:39:19 UTC+2 schreef Marco DeFreitas het volgende:
> Has anyone been able to reproduce the error with the sample i
> provided?
> 
> Thanks...

Hello,
I can't reproduce the error on WinXP with wxWidgets-2.8.12 and MinGW GCC 4.6.1.
I found this disccussion when searching for an example of "Delayed Action Mechanism". I have updated your example to check the double value in the OnIdle handler after a kill focus event, hopefully it helps other people.
I don't known if the "dynamically connected" mode can be improved by passing the ID or object directly to the OnIdle handler (SetEventObject or SetId??)
Notice the difference in the counter behaviour in the status bar for the static and dynamically connected OnIdle.

#include "wx/wx.h"

#define EV_DYN   // undef for static connected OnIdle

class MyApp : public wxApp
{
public:
  virtual bool OnInit();
};

class MyFrame : public wxFrame
{
public:
	MyFrame(const wxString& title);

private:
  void ValidateMe(int id);
  void OnTextEntered(wxCommandEvent& event);
  void OnIdle(wxIdleEvent& event);
  void OnLostFocus(wxFocusEvent& event);

  wxTextCtrl    *m_tc1;
  wxTextCtrl    *m_tc2;
  int           m_check_id;
  long          m_IdleCnt;
  DECLARE_EVENT_TABLE()
};

enum
{
  ID_TC_1 = 1,
  ID_TC_2,
};

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
  EVT_TEXT_ENTER(ID_TC_1,   MyFrame::OnTextEntered)
  EVT_TEXT_ENTER(ID_TC_2,   MyFrame::OnTextEntered)
#ifndef EV_DYN
  EVT_IDLE(                 MyFrame::OnIdle)
#endif
END_EVENT_TABLE()

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
  MyFrame *frame = new MyFrame(wxT("Minimal App"));
  frame->Show(true);
  return true;
}

MyFrame::MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title)
{
  m_check_id = 0;
  m_IdleCnt = 0;

  wxPanel * panel = new wxPanel(this, wxID_ANY); // Handy for using TAB
  m_tc1 = new wxTextCtrl(panel, ID_TC_1, "0",
      wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
  m_tc2 = new wxTextCtrl(panel, ID_TC_2, "0",
      wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);

  m_tc1->Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(
      MyFrame::OnLostFocus), NULL, this);
  m_tc2->Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(
      MyFrame::OnLostFocus), NULL, this);

  wxBoxSizer *s = new wxBoxSizer(wxVERTICAL);
  s->Add(m_tc1, 0, wxEXPAND|wxALL, 5);
  s->Add(m_tc2, 0, wxEXPAND|wxALL, 5);
  panel->SetSizer(s);

  // Create and enable status bar.
  CreateStatusBar();
  SetStatusText( wxString("Welcome to ") << title );

  SetMinSize( ClientToWindowSize( s->CalcMin()));
}

void MyFrame::OnTextEntered(wxCommandEvent& event)
{
  ValidateMe(event.GetId());
}

void MyFrame::OnLostFocus(wxFocusEvent& event)
{
  // Ask OnIdle to check the value
  // If ValidateMe is done here: unpredictable results can occur
  // because this function calls SetFocus.
  m_check_id = event.GetId();
  // Calling ValidateMe in wxMSW 2.8.12 seems to work.
  // ValidateMe(event.GetId());
#ifdef EV_DYN
  Connect( wxEVT_IDLE, wxIdleEventHandler( MyFrame::OnIdle ) );
#endif
}

void MyFrame::OnIdle(wxIdleEvent& event)
{
  m_IdleCnt++;
  SetStatusText( wxString::Format(wxT("IdleCnt: %ld"), m_IdleCnt) );

  if( m_check_id == ID_TC_1 || m_check_id == ID_TC_2)
  {
    ValidateMe( m_check_id);
  }
  m_check_id = 0;
#ifdef EV_DYN
  if( ! Disconnect( wxEVT_IDLE, wxIdleEventHandler( MyFrame::OnIdle ) ) )
  {
    SetStatusText( wxT("Disconnect failed") );
  }
#endif
  event.Skip();
}

void MyFrame::ValidateMe(int id)
{
  wxTextCtrl *tc = 0;

  if (id == ID_TC_1) {
    tc = m_tc1;
  } else if (id == ID_TC_2) {
    tc = m_tc2;
  }

  if (tc) {
    double d;

    if( ! tc->GetValue().ToDouble( &d) )
    {
      wxMessageBox( "Not a valid float!", "Error", wxOK|wxICON_ERROR);
      tc->ChangeValue( "0");
      tc->SetFocus();  // set focus back to wrong input field
      tc->SetSelection(-1, -1);  // select the whole string
    }
  }
}

Eric.

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 12-Jun-2012, at 12:23 PM EST
From: m
 
Re: Problems with losing focus on wxTextCtrl in wxGTK  
News Group: comp.soft-sys.wxwindows
Has anyone been able to reproduce the error with the sample i
provided?

Thanks...

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 26-Aug-2011, at 3:39 PM EST
From: Marco DeFreitas
 
Re: Problems with losing focus on wxTextCtrl in wxGTK  
News Group: comp.soft-sys.wxwindows
On Aug 23, 8:20 am, Vadim Zeitlin  wrote:
>  This is indeed the right thing to do as you can't always (i.e. on all
> platforms) switch focus from focus event handler itself. Moreover, I
> suspect -- although I didn't test this so I could be wrong -- that your
> remaining problem is also due to "doing too much" from this event handler..
> It should basically just set some internal flags and return, in particular
> it shouldn't result in any focus changes itself and showing a message box
> definitely does change focus.
>
>  So I think things should work better if you call wxMessageBox() from your
> EVT_IDLE handler too. Alternatively, you could use wxLogError() (or maybe
> wxLogWarning()) as they're shown during idle time and not immediately as
> well.
>
>  Good luck,
> VZ

I did try to put the wxMessageDialog in the Idle handler, but this did
not help. I tried to use wxLogError, but it was even worse, that is,
the message box was not centered near my text field (it was in the
center of the screen) and the text I wanted to select (in text field
#1) was not selected.

In both cases (wxMessageDialog or wxLogError in the Idle handler) text
field #2 gets highlighted/unhighlighted as I swipe the cursor across
text field #2.


Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 23-Aug-2011, at 11:46 AM EST
From: Marco DeFreitas
 
Re: Problems with losing focus on wxTextCtrl in wxGTK  
News Group: comp.soft-sys.wxwindows
On 2011-08-21, Marco DeFreitas  wrote:
> I also wanted to validate when the focus is lost on the (possibly bad)
> text field, for example the user might enter text in one field and
> then click on another text field.
>
> I was having problems changing focus within a focus event handler;
> that is, when focus is lost on a text field with bad data, I was
> having problems setting the focus back to the text field with bad
> data. However, I got things working reasonably well by just flagging
> the error in the "Kill Focus" event handler and then changing the
> focus in an "Idle" event handler that checked for the flagged error.

 Hello Marco,

 This is indeed the right thing to do as you can't always (i.e. on all
platforms) switch focus from focus event handler itself. Moreover, I
suspect -- although I didn't test this so I could be wrong -- that your
remaining problem is also due to "doing too much" from this event handler.
It should basically just set some internal flags and return, in particular
it shouldn't result in any focus changes itself and showing a message box
definitely does change focus.

 So I think things should work better if you call wxMessageBox() from your
EVT_IDLE handler too. Alternatively, you could use wxLogError() (or maybe
wxLogWarning()) as they're shown during idle time and not immediately as
well.

 Good luck,
VZ

-- 
TT-Solutions: wxWidgets consultancy and technical support
              http://www.tt-solutions.com/

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 23-Aug-2011, at 12:20 PM EST
From: Vadim Zeitlin
 
Re: Problems with losing focus on wxTextCtrl in wxGTK  
News Group: comp.soft-sys.wxwindows
Also, I am using gtk2-2.8.


Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 21-Aug-2011, at 1:52 PM EST
From: Marco DeFreitas
 
Re: Problems with losing focus on wxTextCtrl in wxGTK  
News Group: comp.soft-sys.wxwindows
I forgot to mention I am using wxGTK-2.8.12 on SUSE Linux.


Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 21-Aug-2011, at 1:38 PM EST
From: Marco DeFreitas