From: Troels on 14 Nov 2006 11:25 Vadim Zeitlin wrote: >I usually use EVT_IDLE handler if I need to do something "soon after" >window is shown on screen. It's not ideal and I'd welcome any better >ideas but this is what we have for now. Excellent tip. Certainly belongs in the faq http://www.wxwidgets.org/docs/faq.htm if it isn't already there. Below is shown a fancy method to handle the "soon after" situation in a fairly clean way. (http://wxforum.shadonet.com/viewtopic.php?p=49422#49422) // wxIdleOnceEvtHandler by Troels K 2006 extern wxEventType wxEVT_IDLE_ONCE; #define EVT_IDLE_ONCE(func) wx__DECLARE_EVT0(wxEVT_IDLE_ONCE, wxIdleEventHandler(func)) class wxIdleOnceEvtHandler : public wxEvtHandler { public: bool m_fired; wxEvtHandler* m_target; wxIdleOnceEvtHandler(wxEvtHandler* target) : m_target(target), wxEvtHandler(), m_fired(false) { } virtual bool ProcessEvent(wxEvent&); }; .... wxEventType wxEVT_IDLE_ONCE = wxNewEventType(); bool wxIdleOnceEvtHandler::ProcessEvent(wxEvent& event) { if ((event.GetEventType() == wxEVT_IDLE) && !m_fired) { m_fired = true; wxIdleEvent& idle = (wxIdleEvent&)event; wxIdleEvent temp(idle); temp.SetEventType(wxEVT_IDLE_ONCE); wxPostEvent(m_target, temp); } return wxEvtHandler::ProcessEvent(event); } .... MyWindow::MyWindow() { m_idleonce = new wxIdleOnceEvtHandler(this); PushEventHandler(m_idleonce); } MyWindow::~MyWindow() { RemoveEventHandler(m_idleonce); delete m_idleonce; } BEGIN_EVENT_TABLE(MyWindow, wxScrolledWindow) EVT_IDLE_ONCE(MyWindow::OnIdleOnce) END_EVENT_TABLE() void MyWindow::OnIdleOnce(wxIdleEvent&) { OnInitialUpdate(); // or whatever } Vadim Zeitlin wrote: > On Thu, 21 Sep 2006 18:13:24 +0200 Volker Bartheld <dr_versaeg(a)freenet.de> wrote: > > VB> I wonder at what point of time in the life of a wxWindow, > VB> wxScrolledWindow or wxPanel the "default" values for width and height > VB> (in case of wxScrolledWindow also the virtual values) reflect the > VB> reality. > > They always reflect the reality. It's just that initially they're wrong > and the window is only sized correctly after it's laid out correctly. > > VB> What do I have to do to be sure that GetSize()'s return value matches > VB> the actual screen size? > > I usually use EVT_IDLE handler if I need to do something "soon after" > window is shown on screen. It's not ideal and I'd welcome any better ideas > but this is what we have for now. > > VB> I think, this recipe would also hold true for > VB> wxScrolledWindow::GetVirtualSize, right? > > I don't think so, this one should return the "correct" size always. > > Regards, > VZ >
From: Volker Bartheld on 15 Nov 2006 11:25 Hi Troels! > >I usually use EVT_IDLE handler if I need to do something "soon after" > >window is shown on screen. >Below is shown a fancy method to handle the "soon after" situation in a >fairly clean way. >(http://wxforum.shadonet.com/viewtopic.php?p=49422#49422) Actually this is a totally cool thing to do and it casually helped me solve - or at least dramatically reduce - the "stolen focus issue" (check out Message-ID: <4rro90Fse3o8U1(a)mid.individual.net> for more info) I mentioned in the other thread. As it seems, neither overriding wxWindow::AcceptsFocus() nor catching/handling wxActivateEvent and returning wxEvent::Skip(true) or giving back the focus with FindWindow(wxActivateEvent::GetID())->SetFocus() did the trick. On wxMac and wxLin, I couldn't reproduce this behaviour, so a Win32-only solution was acceptable. I decided to remember the HWND of the current foreground window via the native ::GetForegroundWindow() function in the c'tor and then resetting the foreground window to the current state in the OnIdleOnce() handler via ::SetForegroundWindow(). Anyway and whoever is interested, I'm posting the code snippet at the bottom of this reply. But I still have a question: Why do you create a new event type plus handler for it and push this into the wxWindow's list event handlers? Wouldn't it be good enough to DECLARE_EVENT_TYPE(wxEVT_IDLEONCE, -1) DEFINE_EVENT_TYPE(wxEVT_IDLEONCE) , and then just add it in the c'tor wxCommandEvent e(wxEVT_IDLEONCE, GetId()); AddPendingEvent(e); and grab it via EVT_COMMAND(wxID_ANY, wxEVT_IDLEONCE, MyFrame::OnIdleOnce) ? OK, anybody could post this event an make the handler fire false positive - is it that what you wanted to avoid? Thanks a lot for your hints, Volker <nofocus_frame.cpp> #define EVT_IDLE_ONCE(func) wx__DECLARE_EVT0(wxEVT_IDLE_ONCE, wxIdleEventHandler(func)) static wxEventType wxEVT_IDLE_ONCE=wxNewEventType(); class wxIdleOnceEvtHandler : public wxEvtHandler { public: bool m_fired; wxEvtHandler* m_target; wxIdleOnceEvtHandler(wxEvtHandler* target) : m_target(target), wxEvtHandler(), m_fired(false) {} virtual bool wxIdleOnceEvtHandler::ProcessEvent(wxEvent& event) { if((event.GetEventType()==wxEVT_IDLE) && !m_fired) { m_fired=true; wxIdleEvent& idle=(wxIdleEvent&)event; wxIdleEvent temp(idle); temp.SetEventType(wxEVT_IDLE_ONCE); wxPostEvent(m_target, temp); } return wxEvtHandler::ProcessEvent(event); } }; class CMyDialog : public wxFrame { DECLARE_DYNAMIC_CLASS(CMyDialog) public: CMyDialog::CMyDialog(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxSIMPLE_BORDER|wxSTAY_ON_TOP|wxFRAME_NO_TASKBAR|wxSUNKEN_BORDER, const wxString& name=wxT("dialogBox")) : wxFrame(parent, id, title, pos, size, style, name), m_idleonce(NULL), m_hWndFocus(NULL) { m_idleonce=new wxIdleOnceEvtHandler(this); PushEventHandler(m_idleonce); SetSizer(new wxBoxSizer(wxVERTICAL)); wxBoxSizer* pTextSizer=new wxBoxSizer(wxHORIZONTAL); pTextSizer->Add(new wxTextCtrl(this, wxID_ANY, wxT("Text here...")), 0, wxALL, 4); pTextSizer->AddStretchSpacer(); pTextSizer->Add(new wxButton(this, ID_OK, wxT("OK")), 0, wxALL, 4); GetSizer()->Add(pTextSizer, 1, wxEXPAND | wxALL, 4); Fit(); CenterOnScreen(); m_hWndFocus=::GetForegroundWindow(); Show(); } CMyDialog::~CMyDialog() { RemoveEventHandler(m_idleonce); delete m_idleonce; } void CMyDialog::OnOK(wxCommandEvent& event) { wxCommandEvent e(wxEVT_END_DIALOG, GetId()); GetParent()->AddPendingEvent(e); Destroy(); } void CMyDialog::OnIdleOnce(wxIdleEvent&) { ::SetForegroundWindow(m_hWndFocus); } private: DECLARE_EVENT_TABLE() CMyDialog::CMyDialog() {} wxIdleOnceEvtHandler* m_idleonce; HWND m_hWndFocus; }; IMPLEMENT_DYNAMIC_CLASS(CMyDialog, wxFrame) BEGIN_EVENT_TABLE(CMyDialog, wxFrame) EVT_BUTTON(ID_OK, CMyDialog::OnOK) EVT_BUTTON(ID_CANCEL, CMyDialog::OnOK) EVT_IDLE_ONCE(CMyDialog::OnIdleOnce) END_EVENT_TABLE() </nofocus_frame.cpp> __ Mail replies to/an V B A R T H E L D at G M X dot D E
From: Troels on 15 Nov 2006 15:20 Hi Volker > But I still have a question: Why do you create a new event type plus > handler for it and push this into the wxWindow's list event handlers? > Wouldn't it be good enough to It's to stand on the shoulders of EVT_IDLE, piggybacking it, letting the idle mechanism make the decision of when things are stable. I should think it's the safer way to do it, blessed by Vadim n all. I've rearranged the code a little: http://wxforum.shadonet.com/viewtopic.php?p=49422#49422 Now it itself takes care of calling RemoveEventHandler. Greetings Troels Volker Bartheld wrote: > Hi Troels! > >>> I usually use EVT_IDLE handler if I need to do something "soon after" >>> window is shown on screen. >> Below is shown a fancy method to handle the "soon after" situation in a >> fairly clean way. >> (http://wxforum.shadonet.com/viewtopic.php?p=49422#49422) > > Actually this is a totally cool thing to do and it casually helped me > solve - or at least dramatically reduce - the "stolen focus issue" > (check out Message-ID: <4rro90Fse3o8U1(a)mid.individual.net> for more > info) I mentioned in the other thread. > > As it seems, neither overriding wxWindow::AcceptsFocus() nor > catching/handling wxActivateEvent and returning wxEvent::Skip(true) or > giving back the focus with > FindWindow(wxActivateEvent::GetID())->SetFocus() did the trick. > > On wxMac and wxLin, I couldn't reproduce this behaviour, so a Win32-only > solution was acceptable. I decided to remember the HWND of the current > foreground window via the native ::GetForegroundWindow() function in the > c'tor and then resetting the foreground window to the current state in > the OnIdleOnce() handler via ::SetForegroundWindow(). Anyway and whoever > is interested, I'm posting the code snippet at the bottom of this reply. > > But I still have a question: Why do you create a new event type plus > handler for it and push this into the wxWindow's list event handlers? > Wouldn't it be good enough to > > DECLARE_EVENT_TYPE(wxEVT_IDLEONCE, -1) > DEFINE_EVENT_TYPE(wxEVT_IDLEONCE) > > , and then just add it in the c'tor > > wxCommandEvent e(wxEVT_IDLEONCE, GetId()); > AddPendingEvent(e); > > and grab it via > > EVT_COMMAND(wxID_ANY, wxEVT_IDLEONCE, MyFrame::OnIdleOnce) > > ? OK, anybody could post this event an make the handler fire false > positive - is it that what you wanted to avoid? > > Thanks a lot for your hints, > > Volker > > > <nofocus_frame.cpp> > #define EVT_IDLE_ONCE(func) wx__DECLARE_EVT0(wxEVT_IDLE_ONCE, wxIdleEventHandler(func)) > static wxEventType wxEVT_IDLE_ONCE=wxNewEventType(); > class wxIdleOnceEvtHandler : public wxEvtHandler > { > public: > bool m_fired; > wxEvtHandler* m_target; > wxIdleOnceEvtHandler(wxEvtHandler* target) : m_target(target), wxEvtHandler(), m_fired(false) {} > virtual bool wxIdleOnceEvtHandler::ProcessEvent(wxEvent& event) > { > if((event.GetEventType()==wxEVT_IDLE) && !m_fired) > { > m_fired=true; > wxIdleEvent& idle=(wxIdleEvent&)event; > wxIdleEvent temp(idle); > temp.SetEventType(wxEVT_IDLE_ONCE); > wxPostEvent(m_target, temp); > } > return wxEvtHandler::ProcessEvent(event); > } > }; > > class CMyDialog : public wxFrame > { > DECLARE_DYNAMIC_CLASS(CMyDialog) > public: > CMyDialog::CMyDialog(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxSIMPLE_BORDER|wxSTAY_ON_TOP|wxFRAME_NO_TASKBAR|wxSUNKEN_BORDER, const wxString& name=wxT("dialogBox")) > : wxFrame(parent, id, title, pos, size, style, name), m_idleonce(NULL), m_hWndFocus(NULL) > { > m_idleonce=new wxIdleOnceEvtHandler(this); > PushEventHandler(m_idleonce); > > SetSizer(new wxBoxSizer(wxVERTICAL)); > wxBoxSizer* pTextSizer=new wxBoxSizer(wxHORIZONTAL); > pTextSizer->Add(new wxTextCtrl(this, wxID_ANY, wxT("Text here...")), 0, wxALL, 4); > pTextSizer->AddStretchSpacer(); > pTextSizer->Add(new wxButton(this, ID_OK, wxT("OK")), 0, wxALL, 4); > GetSizer()->Add(pTextSizer, 1, wxEXPAND | wxALL, 4); > Fit(); > CenterOnScreen(); > m_hWndFocus=::GetForegroundWindow(); > Show(); > } > CMyDialog::~CMyDialog() > { > RemoveEventHandler(m_idleonce); > delete m_idleonce; > } > void CMyDialog::OnOK(wxCommandEvent& event) > { > wxCommandEvent e(wxEVT_END_DIALOG, GetId()); > GetParent()->AddPendingEvent(e); > Destroy(); > } > void CMyDialog::OnIdleOnce(wxIdleEvent&) { ::SetForegroundWindow(m_hWndFocus); } > private: > DECLARE_EVENT_TABLE() > CMyDialog::CMyDialog() {} > wxIdleOnceEvtHandler* m_idleonce; > HWND m_hWndFocus; > }; > IMPLEMENT_DYNAMIC_CLASS(CMyDialog, wxFrame) > BEGIN_EVENT_TABLE(CMyDialog, wxFrame) > EVT_BUTTON(ID_OK, CMyDialog::OnOK) > EVT_BUTTON(ID_CANCEL, CMyDialog::OnOK) > EVT_IDLE_ONCE(CMyDialog::OnIdleOnce) > END_EVENT_TABLE() > </nofocus_frame.cpp> > > __ > Mail replies to/an V B A R T H E L D at G M X dot D E
From: Volker Bartheld on 16 Nov 2006 07:15 Hi Troels! > > But I still have a question: Why do you create a new event type plus > > handler for it and push this into the wxWindow's list event handlers? > > Wouldn't it be good enough to >It's to stand on the shoulders of EVT_IDLE, piggybacking it, letting the >idle mechanism make the decision of when things are stable. OK, understood. That makes perfect sense. >I've rearranged the code a little: >http://wxforum.shadonet.com/viewtopic.php?p=49422#49422 >Now it itself takes care of calling RemoveEventHandler. You might also want it to take care of automatically inserting itself in the list of the parent's event handlers. Here's the code - it's basically the same approach in the c'tor as you've taken it in the d'tor. So just a m_idleonce=new wxIdleOnceEvtHandler(this); in the parent's c'tor and a delete m_idleonce; in the d'tor should be enough. <idleonce.cpp> #define EVT_IDLE_ONCE(func) wx__DECLARE_EVT0(wxEVT_IDLE_ONCE, wxIdleEventHandler(func)) static wxEventType wxEVT_IDLE_ONCE=wxNewEventType(); /** * define a new handler type that will deal with the wxEVT_IDLE event when it arrives in the queue for the *FIRST* time */ class wxIdleOnceEvtHandler : public wxEvtHandler { public: wxEvtHandler* m_target; wxIdleOnceEvtHandler::wxIdleOnceEvtHandler(wxEvtHandler* target) : m_target(target), wxEvtHandler() { if(wxIS_KIND_OF(m_target, wxWindow) && GetEvtHandlerEnabled()) ((wxWindow*)m_target)->PushEventHandler(this); // push event handler into parent's list } void wxIdleOnceEvtHandler::Stop(void) { if(wxIS_KIND_OF(m_target, wxWindow) && GetEvtHandlerEnabled()) ((wxWindow*)m_target)->RemoveEventHandler(this); // remove handler from parent's list SetEvtHandlerEnabled(false); } // void wxIdleOnceEvtHandler::Stop(void) wxIdleOnceEvtHandler::~wxIdleOnceEvtHandler() { Stop(); } bool wxIdleOnceEvtHandler::ProcessEvent(wxEvent& event) // event handle "hook" { if(wxEVT_IDLE==event.GetEventType() && GetEvtHandlerEnabled()) // is it the wxEVT_IDLE and it arrived for the first time (event handler still enabled)? { Stop(); // stop the handler wxEvent* temp=event.Clone(); // duplicate the event temp->SetEventType(wxEVT_IDLE_ONCE); // set correct event type wxPostEvent(m_target, *temp); // and reinsert it into parent's queue delete temp; } // if(wxEVT_IDLE==event.GetEventType() && GetEvtHandlerEnabled()) return wxEvtHandler::ProcessEvent(event); } // bool wxIdleOnceEvtHandler::ProcessEvent(wxEvent& event) }; </idleonce.cpp> HTH & happy coding, Volker __ Mail replies to/an V B A R T H E L D at G M X dot D E
From: Troels on 16 Nov 2006 10:14 Hi again > You might also want it to take care of automatically inserting itself > in the list of the parent's event handlers. Here's the code Right! I've rearranged the code again http://wxforum.shadonet.com/viewtopic.php?p=49422#49422 Gotten rid of the casts by overloading the constructor, in order to still be able to handle both window and non-window wxEvtHandler's. Cheers! Troels Volker Bartheld wrote: > Hi Troels! > >>> But I still have a question: Why do you create a new event type plus >>> handler for it and push this into the wxWindow's list event handlers? >>> Wouldn't it be good enough to > >> It's to stand on the shoulders of EVT_IDLE, piggybacking it, letting the >> idle mechanism make the decision of when things are stable. > > OK, understood. That makes perfect sense. > >> I've rearranged the code a little: >> http://wxforum.shadonet.com/viewtopic.php?p=49422#49422 >> Now it itself takes care of calling RemoveEventHandler. > > You might also want it to take care of automatically inserting itself in > the list of the parent's event handlers. Here's the code - it's > basically the same approach in the c'tor as you've taken it in the > d'tor. So just a m_idleonce=new wxIdleOnceEvtHandler(this); in the > parent's c'tor and a delete m_idleonce; in the d'tor should be enough. > > <idleonce.cpp> > #define EVT_IDLE_ONCE(func) wx__DECLARE_EVT0(wxEVT_IDLE_ONCE, wxIdleEventHandler(func)) > static wxEventType wxEVT_IDLE_ONCE=wxNewEventType(); > > /** > * define a new handler type that will deal with the wxEVT_IDLE event when it arrives in the queue for the *FIRST* time > */ > class wxIdleOnceEvtHandler : public wxEvtHandler > { > public: > wxEvtHandler* m_target; > wxIdleOnceEvtHandler::wxIdleOnceEvtHandler(wxEvtHandler* target) : m_target(target), wxEvtHandler() > { > if(wxIS_KIND_OF(m_target, wxWindow) && GetEvtHandlerEnabled()) ((wxWindow*)m_target)->PushEventHandler(this); // push event handler into parent's list > } > void wxIdleOnceEvtHandler::Stop(void) > { > if(wxIS_KIND_OF(m_target, wxWindow) && GetEvtHandlerEnabled()) ((wxWindow*)m_target)->RemoveEventHandler(this); // remove handler from parent's list > SetEvtHandlerEnabled(false); > } // void wxIdleOnceEvtHandler::Stop(void) > wxIdleOnceEvtHandler::~wxIdleOnceEvtHandler() { Stop(); } > bool wxIdleOnceEvtHandler::ProcessEvent(wxEvent& event) // event handle "hook" > { > if(wxEVT_IDLE==event.GetEventType() && GetEvtHandlerEnabled()) // is it the wxEVT_IDLE and it arrived for the first time (event handler still enabled)? > { > Stop(); // stop the handler > wxEvent* temp=event.Clone(); // duplicate the event > temp->SetEventType(wxEVT_IDLE_ONCE); // set correct event type > wxPostEvent(m_target, *temp); // and reinsert it into parent's queue > delete temp; > } // if(wxEVT_IDLE==event.GetEventType() && GetEvtHandlerEnabled()) > return wxEvtHandler::ProcessEvent(event); > } // bool wxIdleOnceEvtHandler::ProcessEvent(wxEvent& event) > }; > </idleonce.cpp> > > HTH & happy coding, > Volker > __ > Mail replies to/an V B A R T H E L D at G M X dot D E
|
Pages: 1 Prev: problem with wxThread between wxGTK and wxMSW Next: wxsheet and wxMSW2.8.0 rc incompatible |