This wxpython code updates the progressbar window message from a non-main thread but it doesn't create a "only the main thread can process Windows messages" error.
Could you please explain how it updates the progressbar window message from a separate thread without any errors? Because sometimes I cannot update the progressbar from a separate thread, I get "only the main thread can process Windows messages".
But in this example I don't get this error. How???
import wx
import wx.lib.agw.pyprogress as PP
import threading
ID_ADD_BUTTON = 100
ID_ADD_BUTTON2 = 101
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "My Panel", size=(400,300))
self.panel = wx.Panel(self, wx.ID_ANY)
self.mytext = wx.StaticText(self.panel, -1, "Start", size=(20,-1))
self.toolbar = wx.ToolBar(self, -1, style=wx.TB_FLAT|wx.BORDER_RAISED)
self.toolbar.AddLabelTool(ID_ADD_BUTTON, 'Refresh', wx.ArtProvider.GetBitmap(wx.ART_PLUS))
self.toolbar.Bind(wx.EVT_TOOL, self.refreshButton, id=ID_ADD_BUTTON)
self.toolbar.Realize()
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.toolbar, 0, wx.EXPAND)
self.sizer.Add(self.panel, 1, wx.EXPAND)
self.SetSizer(self.sizer)
def refreshButton(self, event):
self.myprogress = ProgressThread()
self.toolbar2 = wx.ToolBar(self, -1, style=wx.TB_FLAT|wx.BORDER_RAISED)
self.toolbar2.AddLabelTool(ID_ADD_BUTTON2, 'Print', wx.ArtProvider.GetBitmap(wx.ART_PLUS))
self.toolbar2.Bind(wx.EVT_TOOL, self.refreshButton, id=ID_ADD_BUTTON2)
update = MyThread(self.mytext)
self.toolbar2.Realize()
self.myprogress.dlg.UpdatePulse("toolbar 2 is added")
for i in xrange(5000):
self.myprogress.dlg.UpdatePulse(str(i))
#print "toolbar 2 is added"
self.sizer.Add(self.toolbar2, 0, wx.EXPAND)
self.Layout()
for i in xrange(8000, 12000):
self.myprogress.dlg.UpdatePulse(str(i))
self.myprogress.keepGoing = False
def refreshButton2(self, event):
print "button 2 is pressed"
class ProgressThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
style = wx. PD_APP_MODAL
self.dlg = PP.PyProgress(None, -1, "Updating Data ",
"Please wait...",
agwStyle=style)
self.start()
def run(self):
self.dlg.SetGaugeProportion(20/100.0)
self.dlg.SetGaugeSteps(50)
self.dlg.SetGaugeBackground(wx.WHITE)
self.dlg.SetFirstGradientColour(wx.WHITE)
self.dlg.SetSecondGradientColour(wx.GREEN)
self.keepGoing = True
while self.keepGoing:
wx.MilliSleep(30)
try:
self.dlg.UpdatePulse()
except:
pass
self.dlg.Destroy()
class MyThread(threading.Thread):
def __init__(self, my_text):
self.my_text= my_text
threading.Thread.__init__(self)
self.start()
def run(self):
for i in xrange(50000):
self.my_text.SetLabel(str(i))
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()
Many of the methods you call do nothing except send a message to the
window. That CAN be done from another thread, because the message
will be HANDLED in the main thread.
···
steve wrote:
This wxpython code updates the progressbar window message from a non-main thread but it doesn't create a "only the main thread can process Windows messages" error. Could you please explain how it updates the progressbar window message from a separate thread without any errors? Because sometimes I cannot update the progressbar from a separate thread, I get "only the main thread can process Windows messages". But in this example I don't get this error. How???
-- Tim Roberts, Providenza & Boekelheide, Inc.
I don’t understand. The separate thread is sending and processing in my example.
···
On Friday, December 18, 2015 at 3:07:53 AM UTC+2, Tim Roberts wrote:
steve wrote:
This wxpython code updates the progressbar window message from a non-main thread but it doesn't create a "only the main thread can process Windows messages" error. Could you please explain how it updates the progressbar window message from a separate thread without any errors? Because sometimes I cannot update the progressbar from a separate thread, I get "only the main thread can process Windows messages". But in this example I don't get this error. How???
Many of the methods you call do nothing except send a message to the
window. That CAN be done from another thread, because the message
will be HANDLED in the main thread.-- Tim Roberts, ti...@probo.com Providenza & Boekelheide, Inc.
Maybe. You’re calling UpdatePulse. i haven’t looked at the code for the PyProgress dialog, but remember that many of the wxPython controls are very thin wrappers around C controls, and those C controls often implement thing like UpdatePulse by just sending a window message to the control window. When a method is implemented that way, you automatically get switched to the main thread to handle the message that is sent. In such a wrapped control, the Python code doesn’t do anything to the underlying data, so it doesn’t matter what thread it’s on.
···
On Dec 19, 2015, at 3:15 PM, steve <oslocourse@gmail.com> wrote:
I don't understand. The separate thread is sending and processing in my example.
—
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.
Please see this example below.
In this example, I have an initial panel on my frame, and a start button on it. When I press the button, a progress bar should be displayed on initial panel, then a new thread is started. This new thread creates a new panel and add a notebook with pages on it to new panel. At the same time the progress bar should be updated. After it is done, the initial panel with progress bar will be hidden, and new panel will be placed on the frame. But I can’t get it work. Could you please help?
import sys
import wx
import wx.lib.agw.aui as agw_aui
import wx.lib.agw.flatnotebook as fnb
import threading
from wx.lib.buttons import ThemedGenBitmapTextButton
import wx.lib.agw.pygauge as PG
szflags = wx.EXPAND | wx.ALL
min_height = 50
height_ratio = 4
pborder = 10
lborder = 5
class NotebookPage(wx.Panel):
def init(self, *args, **kwargs):
wx.Panel.init(self, *args, **kwargs)
class Notebook(fnb.FlatNotebook):
def init(self, *args, **kwargs):
self.gauge = kwargs.pop(‘gauge’, None)
fnb.FlatNotebook.init(self, *args, **kwargs)
self.SetBackgroundColour(wx.Colour(226,226,226))
self.nbPages = {}
pages = [“a”,“b”,“c”]
for page in pages:
self.nbPages[page] = NotebookPage(self, name=‘NotebookPage0’)
self.gauge.SetValue(self.gauge.GetValue()+10)
for page in pages:
self.AddPage(self.nbPages[page], page, True)
class MainPanel(wx.Panel):
def init(self, *args, **kwargs):
self.gauge = kwargs.pop(‘gauge’, None)
wx.Panel.init(self, *args, **kwargs)
bookStyle = agw_aui.AUI_NB_DEFAULT_STYLE
bookStyle &= ~(agw_aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)
self.noteBook = Notebook(self, name=‘Notebook’, agwStyle=fnb.FNB_NO_NAV_BUTTONS | fnb.FNB_NODRAG | fnb.FNB_NO_X_BUTTON |fnb.FNB_VC8|fnb.FNB_BOTTOM, gauge=self.gauge)
self.gauge.SetValue(self.gauge.GetValue()+10)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.noteBook, 1, szflags)
self.SetSizer(sizer)
class InitialPanel(wx.Panel):
def init(self, *args, **kwargs):
wx.Panel.init(self, *args, **kwargs)
self.font_box_title = wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD, underline=False, faceName=“Microsoft Sans Serif”)
self.new_button = ThemedGenBitmapTextButton(self, -1, wx.ArtProvider.GetBitmap(wx.ART_PLUS), label=“Start Gauge and add widgets”, pos=(-1,-1), size=(320,128))
self.new_button.SetFont(self.font_box_title)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add((20,150))
self.sizer.Add(self.new_button, 0, wx.LEFT, 100)
self.SetSizer(self.sizer)
def bindStartButton(self, mypanel):
self.Bind(wx.EVT_BUTTON, lambda event: self.StartButton(event, mypanel), self.new_button)
def StartButton(self, event, panel):
panel.do_it()
def onOpen(self, event):
self.create_pyprogress()
def create_pyprogress(self):
self.gauge = PG.PyGauge(self, -1, size=(400,40),style=wx.GA_HORIZONTAL)
self.gauge.SetRange(100)
self.gauge.SetBackgroundColour(wx.WHITE)
self.gauge.SetBorderColor(wx.BLACK)
self.keepGoing = True
self.gauge.SetValue(self.gauge.GetValue()+10)
self.sizer.Add((20,40))
self.sizer.Add(self.gauge, 0, wx.LEFT, 100)
self.Layout()
class MainFrame(wx.Frame):
def init(self, *args, **kwargs):
wx.Frame.init(self, *args, **kwargs)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.initial_panel = InitialPanel(self)
self.initial_panel.bindStartButton(self)
self.temp_panel = wx.Panel(self)
self.temp_panel.Hide()
self.sizer.Add(self.initial_panel, 1, szflags)
self.SetSizer(self.sizer)
def do_it(self):
self.create_pyprogress()
print "ok"
self.updater = ProgressThread(self)
self.Layout()
def create_pyprogress(self):
self.gauge = PG.PyGauge(self.initial_panel, -1, size=(300,30),style=wx.GA_HORIZONTAL)
self.gauge.SetRange(100)
self.gauge.SetBackgroundColour(wx.WHITE)
self.gauge.SetBorderColor(wx.BLACK)
self.initial_panel.sizer.Add((10,10))
self.initial_panel.sizer.Add(self.gauge, 0, wx.LEFT, 10)
self.initial_panel.Layout()
self.initial_panel.Refresh()
self.initial_panel.Layout()
self.Layout()
def layout_main(self):
self.mainPanel = MainPanel(self.temp_panel, name='MainPanel', gauge= self.gauge)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.sizer.Hide(self.initial_panel)
self.sizer.Remove(self.initial_panel)
self.sizer.Add(self.mainPanel, 1, szflags)
self.mainPanel.Reparent(self)
self.Layout()
def onExit(self, event):
""""""
self.Close()
sys.exit(1)
def OnClose(self, event):
self.Destroy()
sys.exit(1)
class ProgressThread(threading.Thread):
def init(self, panel):
self.main_panel = panel
threading.Thread.init(self)
self.start()
def run(self):
self.main_panel.layout_main()
class App(wx.App):
def OnInit(self):
self.mainFrame = MainFrame(None,
size=wx.Size(1000,700),
title=‘MyFrame’, name=‘MyFrame’)
wx.GetApp().SetTopWindow( self.mainFrame )
self.mainFrame.Show()
self.mainFrame.SetSize((500,400))
return True
def main(*args, **kwargs):
global app
app = App()
app.MainLoop()
if name == “main”:
app = None
main()
···
On Monday, December 21, 2015 at 9:46:51 AM UTC+2, Tim Roberts wrote:
On Dec 19, 2015, at 3:15 PM, steve osloc...@gmail.com wrote:
I don’t understand. The separate thread is sending and processing in my example.
Maybe. You’re calling UpdatePulse. i haven’t looked at the code for the PyProgress dialog, but remember that many of the wxPython controls are very thin wrappers around C controls, and those C controls often implement thing like UpdatePulse by just sending a window message to the control window. When a method is implemented that way, you automatically get switched to the main thread to handle the message that is sent. In such a wrapped control, the Python code doesn’t do anything to the underlying data, so it doesn’t matter what thread it’s on.
—
Tim Roberts, ti...@probo.comProvidenza & Boekelheide, Inc.
steve wrote:
Please see this example below.
In this example, I have an initial panel on my frame, and a start
button on it. When I press the button, a progress bar should be
displayed on initial panel, then a new thread is started. This new
thread creates a new panel and add a notebook with pages on it to new
panel. At the same time the progress bar should be updated. After it
is done, the initial panel with progress bar will be hidden, and new
panel will be placed on the frame. But I can't get it work. Could you
please help?
Your current plan is hopeless. Here is the important point you're
missing. Message queues are associated with threads, NOT with
processes. A window is owned by the thread that created it, and
messages for that window get sent to the owning thread. The reason you
are asked to do all of your I/O in the main thread is because that way,
all of the messages get sent to the main thread's queue, so you only
need one message loop to handle them.
In your case, when you create a new window in a secondary thread, the
messages for that window are sent to the message queue for your
secondary thread, but you don't have a message loop in your secondary
thread, so those messages are going to pile up forever, unhandled.
You need to get in the habit of using something like wx.CallAfter so
that your UI manipulation all happens in the main thread.
···
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.
I still don’t get it.
Main thread is creating the new panel, and adding notebook on it. While, the separate thread is updating the progress bar on main panel at the same time.
You are saying that all GUI updates should be done my main thread, but it is impossible. That way the GUI will become irresponsive and progress bar won’t be updated.
Please see the image below.
1- At first there is a main frame, and initial panel on it. There is a button on the initial panel.
2- When user pushes the button, a progress bar is displayed below the button. Then a thread is created, this new thread creates a new panel. But the new panel is not placed on main frame yet. The new thread also creates a notebook and adds 3 pages on it.
3- As each page is added, progres bar is updated. The user only sees the initial panel and the progress bar. The updates to progress bar is presented to the user. He doesn’t see the new panel and notebook yet.
4- When all 3 pages are added to notebook, the inital panel is hidden, and new panel is added on the main frame.
···
On Monday, December 21, 2015 at 7:57:37 PM UTC+2, Tim Roberts wrote:
steve wrote:
Please see this example below.
In this example, I have an initial panel on my frame, and a start
button on it. When I press the button, a progress bar should be
displayed on initial panel, then a new thread is started. This new
thread creates a new panel and add a notebook with pages on it to new
panel. At the same time the progress bar should be updated. After it
is done, the initial panel with progress bar will be hidden, and new
panel will be placed on the frame. But I can’t get it work. Could you
please help?
Your current plan is hopeless. Here is the important point you’re
missing. Message queues are associated with threads, NOT with
processes. A window is owned by the thread that created it, and
messages for that window get sent to the owning thread. The reason you
are asked to do all of your I/O in the main thread is because that way,
all of the messages get sent to the main thread’s queue, so you only
need one message loop to handle them.
In your case, when you create a new window in a secondary thread, the
messages for that window are sent to the message queue for your
secondary thread, but you don’t have a message loop in your secondary
thread, so those messages are going to pile up forever, unhandled.
You need to get in the habit of using something like wx.CallAfter so
that your UI manipulation all happens in the main thread.
–
Tim Roberts, ti...@probo.comProvidenza & Boekelheide, Inc.
Sorry, if someone has told in before.
First, the general rule is that you can touch any GUI items only from the main thread. (To be more precise: there is a thread, where the wxApp endless loop is running, this loop triggers callback aka events in the same thread, and only these calback can do something with GUI.) Otherwise the magic behind it will be broken. No mater how it will fall, but it will fall.
Second, there is a nice tutorial here: http://wiki.wxpython.org/LongRunningTasks
Third, I use wxCallAfter
With best, Mike
I don’t understand, you are calling wxCallAfter in the separate thread but it uses the main thread to update GUI?
In my example, how will progress bar know that a page is added to new panel? Threads can’t talk to each other.
···
On Tuesday, December 22, 2015 at 6:42:51 PM UTC+2, Michael Salin wrote:
Sorry, if someone has told in before.
First, the general rule is that you can touch any GUI items only from the main thread. (To be more precise: there is a thread, where the wxApp endless loop is running, this loop triggers callback aka events in the same thread, and only these calback can do something with GUI.) Otherwise the magic behind it will be broken. No mater how it will fall, but it will fall.
Second, there is a nice tutorial here: http://wiki.wxpython.org/LongRunningTasks
Third, I use wxCallAfter
With best, Mike
Hello Steve,
i’ve reworked your sample app to to what i think you
would it to do. I’m no expert and i’m sure there are better ways to do it.
Torsten
GaugeThread.py (4.11 KB)
I don't understand, you are calling wxCallAfter in the separate thread but
it uses the main thread to update GUI?
yes, exactly.
In my example, how will progress bar know that a page is added to new
panel? Threads can't talk to each other.
you need to make all the GUI calls in wx from the same thread -- but there
are a few calls you can make from any thread -- notably osting events.
wx.CallAfter is the easiest way to do this.
so you use wxCallAfter in your secondary thread when you want the progress
bar to update.
but I note: " how will progress bar know that a page is added to new panel"
-- this implies that the new page is added ina a secondsary thred -- you
can't do that (reliabley). all teh page addingl etc need to take place in
the main thread. but you can call a function from a separete thread to tell
the main thread to add a panel -- using, you guessed it, wx.CallAfter().
-CHB
···
On Tue, Dec 22, 2015 at 9:07 AM, steve <oslocourse@gmail.com> wrote:
On Tuesday, December 22, 2015 at 6:42:51 PM UTC+2, Michael Salin wrote:
Sorry, if someone has told in before.
First, the general rule is that you can touch any GUI items only from the
main thread. (To be more precise: there is a thread, where the wxApp
endless loop is running, this loop triggers callback aka events in the same
thread, and only these calback can do something with GUI.) Otherwise the
magic behind it will be broken. No mater how it will fall, but it will fall.Second, there is a nice tutorial here:
LongRunningTasks - wxPyWikiThird, I use wxCallAfter
With best, Mike
--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
Christopher Barker, Ph.D.
Oceanographer
Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception
Chris.Barker@noaa.gov
steve wrote:
I don't understand, you are calling wxCallAfter in the separate thread
but it uses the main thread to update GUI?
Yes, that's exactly what CallAfter is for. wx.CallAfter simply sends a
window message to the main window for the application and then returns.
The message loop (app.MainLoop), which is running in your main thread,
pulls the window message from the message queue, and calls the function
that you specified in the wx.CallAfter.
···
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.
wx.CallAfter is a “non-blocking” call that tells the main thread to call the function specified next time it wakes up. the call to CallAfter itself returns immediately, often before the function specified is called (but do not rely on this fact). So, code following the call to callafter should NOT expect the results of the function that is the argument to callafter to be completed.
There is another important point that I don’t think has been made yet. Windows, OS X and Linux all work slightly differently. It is possible on some of these platforms to interact with the GUI message queues from other threads than the main thread, even sometimes from other threads than the one creating the GUI objects. Even if you get this to work, DO NOT do it as it will surely fail on some platform even if it is not failing on your own. The reason that people religiously only interact with the GUI from the main thread is that it creates the most portable and failproof code. If you get in the habit of it now, your life will be better.
···
On Tue, Dec 22, 2015 at 2:53 PM, Tim Roberts timr@probo.com wrote:
steve wrote:
I don’t understand, you are calling wxCallAfter in the separate thread
but it uses the main thread to update GUI?
Yes, that’s exactly what CallAfter is for. wx.CallAfter simply sends a
window message to the main window for the application and then returns.
The message loop (app.MainLoop), which is running in your main thread,
pulls the window message from the message queue, and calls the function
that you specified in the wx.CallAfter.
–
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.
–
You received this message because you are subscribed to the Google Groups “wxPython-users” group.
To unsubscribe from this group and stop receiving emails from it, send an email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi, Steve,
wx.CallAfter is a "non-blocking" call that tells the main thread to call the
function specified next time it wakes up. the call to CallAfter itself
returns immediately, often before the function specified is called (but do
not rely on this fact). So, code following the call to callafter should NOT
expect the results of the function that is the argument to callafter to be
completed.There is another important point that I don't think has been made yet.
Windows, OS X and Linux all work slightly differently. It is possible on
some of these platforms to interact with the GUI message queues from other
threads than the main thread, even sometimes from other threads than the one
creating the GUI objects. Even if you get this to work, DO NOT do it as it
will surely fail on some platform even if it is not failing on your own. The
reason that people religiously only interact with the GUI from the main
thread is that it creates the most portable and failproof code. If you get
in the habit of it now, your life will be better.
Exactly.
Workiing with the GUI from anything other than the main thread is not
supported and
should be avoided.
You can post the message to the main thread to notify the GUI to
update itself and do
everything GUI-related on the main thread (create GUI controls, update
GUI controls).
There are some controversy about wxTimer and whether it should work
from the secondary
thread, but thats should not be the issue as if every single wx class
is made from the main
thread than everything will work just fine.
Thank you.
···
On Tue, Dec 22, 2015 at 3:21 PM, Michael Haimes <michael.haimes@gmail.com> wrote:
On Tue, Dec 22, 2015 at 2:53 PM, Tim Roberts <timr@probo.com> wrote:
steve wrote:
> I don't understand, you are calling wxCallAfter in the separate thread
> but it uses the main thread to update GUI?Yes, that's exactly what CallAfter is for. wx.CallAfter simply sends a
window message to the main window for the application and then returns.
The message loop (app.MainLoop), which is running in your main thread,
pulls the window message from the message queue, and calls the function
that you specified in the wx.CallAfter.--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Dear sirs,
There is still one point not explained yet:
The script is trying to update the GUI simultaneously:
1- A new panel with a notebook is created, then pages are added to this notebook
2- For each page added, the progress bar is updated
3- Finally, when all pages are added, notebook panel is placed on main frame, whereas the initial panel with progress bar is hidden.
So, the notebook panel is created in main thread. And separate thread is sending messages to main thread to update to progress bar each time a page is added to notebook.
But it is impossible, because main thread is busy with creating the notebook panel and its pages. It will not get the “progress bar update messages” sent from the separate thread. Thus, the user will not see the progression of progress bar. He will only see that he pressed the button, then the notebook panel is placed on mainframe.
···
On Tuesday, December 22, 2015 at 11:10:55 PM UTC+2, Igor Korot wrote:
Hi, Steve,
On Tue, Dec 22, 2015 at 3:21 PM, Michael Haimes > > michael...@gmail.com wrote:
wx.CallAfter is a “non-blocking” call that tells the main thread to call the
function specified next time it wakes up. the call to CallAfter itself
returns immediately, often before the function specified is called (but do
not rely on this fact). So, code following the call to callafter should NOT
expect the results of the function that is the argument to callafter to be
completed.
There is another important point that I don’t think has been made yet.
Windows, OS X and Linux all work slightly differently. It is possible on
some of these platforms to interact with the GUI message queues from other
threads than the main thread, even sometimes from other threads than the one
creating the GUI objects. Even if you get this to work, DO NOT do it as it
will surely fail on some platform even if it is not failing on your own. The
reason that people religiously only interact with the GUI from the main
thread is that it creates the most portable and failproof code. If you get
in the habit of it now, your life will be better.
Exactly.
Workiing with the GUI from anything other than the main thread is not
supported and
should be avoided.
You can post the message to the main thread to notify the GUI to
update itself and do
everything GUI-related on the main thread (create GUI controls, update
GUI controls).
There are some controversy about wxTimer and whether it should work
from the secondary
thread, but thats should not be the issue as if every single wx class
is made from the main
thread than everything will work just fine.
Thank you.
On Tue, Dec 22, 2015 at 2:53 PM, Tim Roberts ti...@probo.com wrote:
steve wrote:
I don’t understand, you are calling wxCallAfter in the separate thread
but it uses the main thread to update GUI?
Yes, that’s exactly what CallAfter is for. wx.CallAfter simply sends a
window message to the main window for the application and then returns.
The message loop (app.MainLoop), which is running in your main thread,
pulls the window message from the message queue, and calls the function
that you specified in the wx.CallAfter.
–
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.
–
You received this message because you are subscribed to the Google Groups
“wxPython-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
–
You received this message because you are subscribed to the Google Groups
“wxPython-users” group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi, Steve,
Dear sirs,
There is still one point not explained yet:
The script is trying to update the GUI simultaneously:
1- A new panel with a notebook is created, then pages are added to this
notebook
IIUC, this step is performed on the secondary thread.
Why did you do a design like this?
Once again - no GUI should operate on the secondary thread.
Also, the creation of the controls should be very fast - couple of
miliseconds. You will not
be able to see anything on the progress bar.
Thank you.
···
On Tue, Dec 22, 2015 at 4:33 PM, steve <oslocourse@gmail.com> wrote:
2- For each page added, the progress bar is updated
3- Finally, when all pages are added, notebook panel is placed on main
frame, whereas the initial panel with progress bar is hidden.So, the notebook panel is created in main thread. And separate thread is
sending messages to main thread to update to progress bar each time a page
is added to notebook.But it is impossible, because main thread is busy with creating the notebook
panel and its pages. It will not get the "progress bar update messages" sent
from the separate thread. Thus, the user will not see the progression of
progress bar. He will only see that he pressed the button, then the notebook
panel is placed on mainframe.On Tuesday, December 22, 2015 at 11:10:55 PM UTC+2, Igor Korot wrote:
Hi, Steve,
On Tue, Dec 22, 2015 at 3:21 PM, Michael Haimes >> <michael...@gmail.com> wrote:
> wx.CallAfter is a "non-blocking" call that tells the main thread to call
> the
> function specified next time it wakes up. the call to CallAfter itself
> returns immediately, often before the function specified is called (but
> do
> not rely on this fact). So, code following the call to callafter should
> NOT
> expect the results of the function that is the argument to callafter to
> be
> completed.
>
> There is another important point that I don't think has been made yet.
> Windows, OS X and Linux all work slightly differently. It is possible on
> some of these platforms to interact with the GUI message queues from
> other
> threads than the main thread, even sometimes from other threads than the
> one
> creating the GUI objects. Even if you get this to work, DO NOT do it as
> it
> will surely fail on some platform even if it is not failing on your own.
> The
> reason that people religiously only interact with the GUI from the main
> thread is that it creates the most portable and failproof code. If you
> get
> in the habit of it now, your life will be better.Exactly.
Workiing with the GUI from anything other than the main thread is not
supported and
should be avoided.You can post the message to the main thread to notify the GUI to
update itself and do
everything GUI-related on the main thread (create GUI controls, update
GUI controls).
There are some controversy about wxTimer and whether it should work
from the secondary
thread, but thats should not be the issue as if every single wx class
is made from the main
thread than everything will work just fine.Thank you.
>
> On Tue, Dec 22, 2015 at 2:53 PM, Tim Roberts <ti...@probo.com> wrote:
>>
>> steve wrote:
>> > I don't understand, you are calling wxCallAfter in the separate
>> > thread
>> > but it uses the main thread to update GUI?
>>
>> Yes, that's exactly what CallAfter is for. wx.CallAfter simply sends a
>> window message to the main window for the application and then returns.
>> The message loop (app.MainLoop), which is running in your main thread,
>> pulls the window message from the message queue, and calls the function
>> that you specified in the wx.CallAfter.
>>
>> --
>> Tim Roberts, ti...@probo.com
>> Providenza & Boekelheide, Inc.
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups
>> "wxPython-users" group.
>> To unsubscribe from this group and stop receiving emails from it, send
>> an
>> email to wxpython-user...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> You received this message because you are subscribed to the Google
> Groups
> "wxPython-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an
> email to wxpython-user...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
steve wrote:
There is still one point not explained yet:
The script is trying to update the GUI simultaneously:
1- A new panel with a notebook is created, then pages are added to
this notebook
2- For each page added, the progress bar is updated
3- Finally, when all pages are added, notebook panel is placed on main
frame, whereas the initial panel with progress bar is hidden.So, the notebook panel is created in main thread. And separate thread
is sending messages to main thread to update to progress bar each time
a page is added to notebook.But it is impossible, because main thread is busy with creating the
notebook panel and its pages. It will not get the "progress bar update
messages" sent from the separate thread. Thus, the user will not see
the progression of progress bar. He will only see that he pressed the
button, then the notebook panel is placed on mainframe.
Your original code tried to create the additional notebook pages from a
different thread. That is NEVER going to work. All windows have to be
created in the main thread.
Given that, you're going to have to use a different approach. If all
you're trying to do is show a progress bar while you open the notebook
pages, then you'll have to do the progres bar update inline in the main
thread and call wx.Yield to allow messages to get processed.
···
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.
> But it is impossible, because main thread is busy with creating the
> notebook panel and its pages.
here is a good thing to keep in mind. IF you want your GUI to be
responsive, then everything that happens as the result of an event should
return quickly.
At Tim points out, creating a showing a few GUI elements should be plenty
quick. Usually, the only things that take a long time are complex
calculations, or pulling data from a remote service to database, or...
in which case, you want o do THOSE operations in another thread to keep the
GUI alive. That thread can then post events to update the GUI if you want
(like a progress bar, etc.), using wx.CallAfter, or lower level event
posting.
The OP seems to want a progress bar fro when notebook pages are being
created, but that should be too fast an operation to require a progress
bar. So I suspect that there is some other process that is going on in
order to crate the pages -- THAT should be done in a separate thread.
THis sounds like classic mixing of GUI and business logic to me -- clean
that up and you won't struggle with keeping the GUI in one thread.
-CHB
···
It will not get the "progress bar update
> messages" sent from the separate thread. Thus, the user will not see
> the progression of progress bar. He will only see that he pressed the
> button, then the notebook panel is placed on mainframe.Your original code tried to create the additional notebook pages from a
different thread. That is NEVER going to work. All windows have to be
created in the main thread.Given that, you're going to have to use a different approach. If all
you're trying to do is show a progress bar while you open the notebook
pages, then you'll have to do the progres bar update inline in the main
thread and call wx.Yield to allow messages to get processed.--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--
Christopher Barker, Ph.D.
Oceanographer
Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception
Chris.Barker@noaa.gov