Refresh wxDialog created from main thread event loop app

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.
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Refresh wxDialog created from main thread event loop app

Post by Sridhar@Work »

Hi

I have an event main loop application which internally calls showModal() to show the wxDialog. The wxDialog() constructor creates a thread which runs in the background listing for some events. On these external events, we have to refresh our dialog.

Can you please let us know how this can be done?

Sample code:

Main Dll Application:
MyDllApp()


Dialog class:
class MyDialog : public wxDialog
{
MyDialog()
~MyDialog ()
}

MyDialog::MyDialog()
{
/* This creates a thread and waits for some third party events */
CreateThread(...,mythread(),..);

/* Show controls in the dialog */
}

mythread ()
{
/* wait for events */
/* On some specific event, we need to refresh the MyDialog() to show new controls */
}

Can you please help how to trigger some event to refresh the MyDialog() after showModel() is called from MainEventLoop?

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

Re: Refresh wxDialog created from main thread event loop app

Post by doublemax »

Sridhar@Work wrote: Fri Jan 21, 2022 2:28 pm I have an event main loop application which internally calls showModal() to show the wxDialog. The wxDialog() constructor creates a thread which runs in the background listing for some events. On these external events, we have to refresh our dialog.
Send a custom event to the dialog. https://docs.wxwidgets.org/trunk/overvi ... nts_custom

Alternaively, you can use CallAfter() to call some code asynchronously from the main thread. https://docs.wxwidgets.org/trunk/classw ... 50b3719519
Use the source, Luke!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: Refresh wxDialog created from main thread event loop app

Post by Sridhar@Work »

Thank you.

Do you have any sample code for reference?

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

Re: Refresh wxDialog created from main thread event loop app

Post by doublemax »

In its simplest form: Pass a MyDialog pointer to the thread constructor and store it in a member variable m_dialog;

Then, inside the thread you can call a method from the dialog.

Code: Select all

wxTheApp->CallAfter( [this] {
  m_dialog->SomeMethod();
});
The code inside will be executed asynchronously from the context of the main thread.
Use the source, Luke!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: Refresh wxDialog created from main thread event loop app

Post by Sridhar@Work »

Thank you.

I'm actually launching a dialog from dll and then creating thread from dialog. So I don't think the below code would work.
However, I created a worker thread in dialog and then sending an OnThreadEvent() event to refresh the dialog.

The problem is the repaint is not clearing the old controls properly and creating the new controls. I can see that some old controls still appear in the new dialog created. Can you please let me know what is the correct way to call repaint on thread event in dialog code?

I tried Refresh() but it is not working as I show the dialog using ShowModel().

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

Re: Refresh wxDialog created from main thread event loop app

Post by doublemax »

Are you sure this is a refresh/redraw issue? Does the dialog "fix" itself when you resize it, or force a refresh by dragging another window across?
Use the source, Luke!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: Refresh wxDialog created from main thread event loop app

Post by Sridhar@Work »

Hi

Yes,

When I call ShowModel(), it calls the dialog constructor which internally draws the controls and the layout of the dialog.
When I get the thread events occur1, I show a different layout with different controls and dialog increases in size or decreases in size.
However, the new dialog layout is not clean. It shows some borders/colors of previous dialog/layout.

I'm redrawing the controls and then running the below functions.

Update();
Refresh();

Let me know if I have to do anything extra?

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

Re: Refresh wxDialog created from main thread event loop app

Post by doublemax »

You didn't answer my question:
Does the dialog "fix" itself when you resize it, or force a refresh by dragging another window across?
Sridhar@Work wrote: Tue Feb 01, 2022 7:11 am Update();
Refresh();
The order of these two is wrong, but i don't think it will make a difference in this case.
Use the source, Luke!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: Refresh wxDialog created from main thread event loop app

Post by Sridhar@Work »

>>Does the dialog "fix" itself when you resize it, or force a refresh by dragging another window across?
No. It doesn't.

Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Refresh wxDialog created from main thread event loop app

Post by doublemax »

Ok, then it's not a layout/redraw issue, but something more serious.

How are you deleting the previous content? Can you show some code?
Use the source, Luke!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: Refresh wxDialog created from main thread event loop app

Post by Sridhar@Work »

Sample code:

Code: Select all

class MyThread : public wxThread
{
 MyThread(wxEvtHandler* sink) : wxThread(wxTHREAD_JOINABLE), m_sink(sink)
 {}
 ExitCode Entry() override;
}

class MyDialog : public wxDialog
{
 MyDialog( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE );
 ~MyDialog();
 
 void OnThreadEvent(wxThreadEvent& evt)
 {
     ShowLayoutandControls_Type3();
	 Update();
     Refresh();
 }
}

MyDialog::MyDialog( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE )
{

    /* Bind the OnThreadEvent with the dialog */
    Bind(wxEVT_THREAD, &MyDialog::OnThreadEvent, this);
	
	/* Start the thread */
    StartMyThread();
	
    /* Show default layout */	
	ShowLayoutandControls_Type1();
}

MyDialog::ShowLayoutandControls_Type1() 
{
    this->SetSizeHints( wxDefaultSize, wxDefaultSize );
    this->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ) );
    this->SetBackgroundColour( wxColour( 255, 255, 255 ) );
	wxFlexGridSizer* mainLayout;
	....
	/* Add controls and layout with different layout dimensions	*/
	
	this->SetSizer( mainLayout );
    this->Layout();
    mainLayout->Fit( this );
}

MyDialog::ShowLayoutandControls_Type2() 
{
    ...
	wxFlexGridSizer* mainLayout;
	....
	/* Add controls and layout with different layout dimensions	*/
	
	this->SetSizer( mainLayout );
    this->Layout();
    mainLayout->Fit( this );
}

MyDialog::ShowLayoutandControls_Type3() 
{
    ...
	wxFlexGridSizer* mainLayout;
	....
	/* Add controls and layout */
	
	this->SetSizer( mainLayout );
    this->Layout();
    mainLayout->Fit( this );
}
	
wxThread::ExitCode MyThread::Entry()
{
 ...
 /* runs in loop waiting for events */
 if(statuschanged) {
    /* Send event */
    wxThreadEvent evt;
    evt.SetInt(++eventCount);
    wxQueueEvent(m_sink, evt.Clone());
 }
}


Main Dll application:
MyDialog *custom = new MyDialog();
ret = custom->ShowModal();
/* End Dialog */


Hi

Please find the sample code below.
As you can see, the MyDialog application is first created with funtion ShowLayoutandControls_Type1().
Onthreadevent, it is not deleting the layout but calling ShowLayoutandControls_Type2() followed with Update();Refresh().

Let me know if something what needs to be corrected to make it work correct. I want the previous layout to clear and the show the new layout controls on it.

Note: I'm not deleted the previous layout e.g. mainLayout object is not deleted.

Regards
Sridhar
Last edited by doublemax on Tue Feb 01, 2022 10:38 am, edited 1 time in total.
Reason: Added code tags
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Refresh wxDialog created from main thread event loop app

Post by doublemax »

As you're not deleting the old controls, the result is not surprising.

Do you replace all controls or only a subset? If all controls get replaced, call DestroyChildren() before creating a new layout.

If you replace only a subset, put all "dynamic" controls onto a dedicated wxPanel. On layout change, call DestroyChildren() on that panel only.

Another option is to create all 3 layouts at once on separate wxPanels. Then put them into a wxSimpleBook which you can use to switch between them.
Use the source, Luke!
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: Refresh wxDialog created from main thread event loop app

Post by Sridhar@Work »

Thank you.

I tried the following code to clear the old controls and show new controls. It works fine.

This is called before showing the new controls layout.
{{{
GetSizer()->Clear(true);
SetSizer(NULL, true);
}}}


Do you suggest above? or DestroyChildren()?

Regards
Sridhar
Sridhar@Work
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 221
Joined: Fri Jan 08, 2021 8:19 am

Re: Refresh wxDialog created from main thread event loop app

Post by Sridhar@Work »

Hi

What is the best way to gracefully terminate the infinite loop thread?

I'm using

void StopMyThread()
{
if ( m_thread )
{
m_thread->Delete();
wxDELETE(m_thread);
}
}

This is causing the application to crash/hang. This is being called on dialog destructor class.

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

Re: Refresh wxDialog created from main thread event loop app

Post by doublemax »

Code: Select all

GetSizer()->Clear(true);
SetSizer(NULL, true);
This is fine.

Code: Select all

void StopMyThread()
{
  if ( m_thread )
  {
    m_thread->Delete();
    wxDELETE(m_thread);
  }
}
If it's a detached thread, you must not delete the pointer as it deletes itself. If it's a joined thread, use Join() to wait it to terminate.
Use the source, Luke!
Post Reply