wxTextCtrl SelectAll() when clicking on it Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 449
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

wxTextCtrl SelectAll() when clicking on it

Post by mael15 » Tue Apr 14, 2020 6:27 pm

hello everyone,
I cannot get a wxTextCtrl to select its content when clicking on it. It works only once. I use wxMSW 3.1.3.

Code: Select all

class MyTextCtrl : public wxTextCtrl {
public:
	MyTextCtrl(wxWindow* par, wxString val) : wxTextCtrl(par, wxID_ANY, val, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER) {
		Connect(wxEVT_LEFT_UP, wxMouseEventHandler(MyTextCtrl::onLeftUp));
		Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent&) { Navigate(); });
	}
protected:
private:
	void onLeftUp(wxMouseEvent& evt) {
		SelectAll();
	}
};

class MyPanel : public wxPanel {
public:
	MyPanel(wxWindow* par) : wxPanel(par) {
		SetSizer(new wxBoxSizer(wxHORIZONTAL));
		for (int i = 0; i < 3; i++)
			GetSizer()->Add(new MyTextCtrl(this, wxString::Format(wxT("%i"), i)));
	}
};

class MyFrame1 : public wxFrame 
{
public:
	MyFrame1( wxWindow* parent = NULL, 
		wxWindowID id = wxID_ANY, 
		const wxString& title = wxEmptyString, 
		const wxPoint& pos = wxDefaultPosition, 
		const wxSize& size = wxSize( 500,300 ), 
		long style = wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) :
		wxFrame(parent, id, title, pos, size, style)
	{
		SetSizer(new wxBoxSizer(wxHORIZONTAL));
		GetSizer()->Add(new MyPanel(this));
	}
	~MyFrame1(){}
};

class MyApp : public wxApp {
	virtual bool OnInit() {
		MyFrame1* mainFrame = new MyFrame1();
		mainFrame->Show();
		SetTopWindow(mainFrame);

		return TRUE;
	}
};
What is wrong here?
Thank you!

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2673
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxTextCtrl SelectAll() when clicking on it

Post by PB » Tue Apr 14, 2020 6:58 pm

Skip the event in the handler, this seems to work

Code: Select all

#include <wx/wx.h>

class MyDialog : public wxDialog
{
public:
    MyDialog(): wxDialog(nullptr, wxID_ANY, "Test")
    {
        wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);

        mainSizer->Add(new wxButton(this, wxID_ANY, "Test"), wxSizerFlags().Expand().Border());        

        m_textCtrl = new wxTextCtrl(this, wxID_ANY, "aaa\nbbb", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
        mainSizer->Add(m_textCtrl, wxSizerFlags().Proportion(1).Expand().Border());        
        m_textCtrl->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& event) 
            { 
                m_textCtrl->SelectAll(); 
                event.Skip(); 
            });

        SetSizer(mainSizer);
    }	
private:
    wxTextCtrl* m_textCtrl;
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {        
        MyDialog().ShowModal();
        return false;
    }
}; wxIMPLEMENT_APP(MyApp);
However, doing what you want makes little sense to me, as it basically means the user cannot use the mouse with the control.

mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 449
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxTextCtrl SelectAll() when clicking on it

Post by mael15 » Tue Apr 14, 2020 7:16 pm

that is a little embarrasing, thank you.
this was only a more simple test for doing the same thing with wxSpinCtrl, seems to be different there? onLeftUp is not called and I do not know how to reach the wxTextCtrl component?

Code: Select all

class MySpinCtrl : public wxSpinCtrl {
public:
	MySpinCtrl(wxWindow* par) : wxSpinCtrl(par, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER) {
		Connect(wxEVT_LEFT_UP, wxMouseEventHandler(MySpinCtrl::onLeftUp));
		Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent&) { Navigate(); });
	}
protected:
private:
	void onLeftUp(wxMouseEvent& evt) {
		SetSelection(-1, -1);
		evt.Skip();
	}
};

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2673
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxTextCtrl SelectAll() when clicking on it

Post by PB » Tue Apr 14, 2020 7:34 pm

mael15 wrote:
Tue Apr 14, 2020 7:16 pm
wxSpinCtrl, seems to be different there? onLeftUp is not called and I do not know how to reach the wxTextCtrl component?
Yes, it seems the event is handled only for the wxSpinButton part of the control and not for the wxTextCtrl one (i.e., the buddy).
wxWidgets source code comment wrote:Under Win32, wxSpinCtrl is a wxSpinButton with a buddy
I have no idea whether this should be considered a bug. Are mouse events guaranteed for the native controls - I don't think so. Does it work on other platforms?.

I also have no idea about a (simple) workaround.

User avatar
doublemax
Moderator
Moderator
Posts: 15282
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxTextCtrl SelectAll() when clicking on it

Post by doublemax » Tue Apr 14, 2020 7:48 pm

How about using wxFocusEvent instead of the mouse event?
Use the source, Luke!

mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 449
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxTextCtrl SelectAll() when clicking on it

Post by mael15 » Tue Apr 14, 2020 8:12 pm

doublemax wrote:
Tue Apr 14, 2020 7:48 pm
How about using wxFocusEvent instead of the mouse event?
Yes! And some weird tip from some other post about the timing of the event and that the selection should occur when idle:

Code: Select all

class MySpinCtrl : public wxSpinCtrl {
public:
	MySpinCtrl(wxWindow* par) : wxSpinCtrl(par, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER) {
		Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(MySpinCtrl::onKillFocus));
		Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(MySpinCtrl::onSetFocus));
		Connect(wxEVT_IDLE, wxIdleEventHandler(MySpinCtrl::onIdle));
		Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent&) { Navigate(); });
	}
protected:
	void ProcessValue(wxString value) {
		OutputDebugString(wxString::Format(wxT("probologTextCtrl::ProcessValue %s\n"), value));
	}
private:
	void onKillFocus(wxFocusEvent& evt) {
		OutputDebugString(wxT("MySpinCtrl::onKillFocus\n"));
		//SetSelection(0, 0);
		m_hasFocus = false;
		evt.Skip();
	}
	void onSetFocus(wxFocusEvent& evt) {
		OutputDebugString(wxT("MySpinCtrl::onSetFocus\n"));
		wxObject* obj = evt.GetEventObject();
		wxSpinCtrl *txt = static_cast<wxSpinCtrl*>(obj);
		//txt->SetSelection(-1, -1);
		m_hasFocus = true;
		evt.Skip();
	}
	void onIdle(wxIdleEvent& evt) {
		if (m_hasFocus)
			SetSelection(-1, -1);
		else
			SetSelection(0, 0);
	}

	bool m_hasFocus = false;
};
It is strange, but it works, thank you :D
Last edited by catalin on Wed Apr 15, 2020 5:29 am, edited 1 time in total.
Reason: Use code tags rather than quote tags.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2673
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxTextCtrl SelectAll() when clicking on it

Post by PB » Tue Apr 14, 2020 8:33 pm

Using CallAfter() for SetSelection() instead when idle seems easier, it did not work?

mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 449
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxTextCtrl SelectAll() when clicking on it

Post by mael15 » Tue Apr 14, 2020 8:45 pm

PB wrote:
Tue Apr 14, 2020 8:33 pm
Using CallAfter() for SetSelection() instead when idle seems easier, it did not work?
WAY better, because onIdle is called over and over and makes it impossible to enter values by keyboard with more than one number, because the selection is refreshed over and over. now it is perfect. :D :D

Code: Select all

class MySpinCtrl : public wxSpinCtrl {
public:
	MySpinCtrl(wxWindow* par) : wxSpinCtrl(par, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER) {
		Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(MySpinCtrl::onKillFocus));
		Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(MySpinCtrl::onSetFocus));
		Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent&) { Navigate(); });
	}
protected:
private:
	void onKillFocus(wxFocusEvent& evt) {
		m_hasFocus = false;
		CallAfter(&MySpinCtrl::makeSelection);
		evt.Skip();
	}
	void onSetFocus(wxFocusEvent& evt) {
		m_hasFocus = true;
		CallAfter(&MySpinCtrl::makeSelection);
		evt.Skip();
	}
	void makeSelection() {
		if (m_hasFocus)
			SetSelection(-1, -1);
		else
			SetSelection(0, 0);
	}

	bool m_hasFocus = false;
};

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2673
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxTextCtrl SelectAll() when clicking on it

Post by PB » Tue Apr 14, 2020 9:33 pm

OK, last nitpick (here). :P

You could probably simplify the code, by getting rid of m_hasFocus, like this

Code: Select all

class MySpinCtrl : public wxSpinCtrl {
public:
	MySpinCtrl(wxWindow* par) : wxSpinCtrl(par, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER) {
		Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(MySpinCtrl::onKillFocus));
		Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(MySpinCtrl::onSetFocus));
		Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent&) { Navigate(); });
	}
protected:
private:
	void onKillFocus(wxFocusEvent& evt) {		
		CallAfter(&MySpinCtrl::SetSelection, 0, 0);
		evt.Skip();
	}
	void onSetFocus(wxFocusEvent& evt) {		
		CallAfter(&MySpinCtrl::SetSelection, -1, -1);		
		evt.Skip();
	}
};
I would also replace those ugly Connect()s with Bind()...

Code: Select all

class MySpinCtrl : public wxSpinCtrl {
public:
    MySpinCtrl(wxWindow* par) : wxSpinCtrl(par, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER) {
        // select all after obtaining focus
        Bind(wxEVT_SET_FOCUS,  [this](wxFocusEvent& e) { CallAfter(&MySpinCtrl::SetSelection, -1, -1); e.Skip(); });
        // unselect all after losing focus
        Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) { CallAfter(&MySpinCtrl::SetSelection, 0, 0); e.Skip(); });

        Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent&) { Navigate(); });
    }
};

mael15
Super wx Problem Solver
Super wx Problem Solver
Posts: 449
Joined: Fri May 22, 2009 8:52 am
Location: Bremen, Germany

Re: wxTextCtrl SelectAll() when clicking on it

Post by mael15 » Thu Apr 16, 2020 9:34 am

much more elegant, thanx again! =D>

Post Reply