mainloop and threads

Hi,

once more a question about threading and the mainloop. Do I remember right, that the the mainloop has to run in the main thread, i.e. that one which is started with the python interpreter or is the only necessity that no gui functions may be called from outside the mainloop thread?
I am asking because I would like to use wxpython in a COM server. Currently I am instantiating a new wx.App object every time I need to show a dialog, etc. but doing so, the COM server is blocked while the wxpyhton mainloop is running.
The following example (as suspected) does not work.

import wx

from threading import Thread

class Main(Thread):
     def __init__(self):
         Thread.__init__(self)
         self.app = wx.PySimpleApp(0)

         f = wx.Frame(None)
         f.Show()

     def run(self):
         self.app.MainLoop()

t = Main()
t.start()

raw_input()

Any pointers are highly appreciated. I really want to avoid to code the gui using the pywin32 extensions.

Regards, Christian

I believe that you are right, wx can be started in it's own thread as
long as all GUI stuff is done there. I believe the problem with your
example is that you are creating the App object in the main thread and
then running the event loop in another. Try this:
import wx

import time
from threading import Thread

class Main(Thread):
   def __init__(self):
      Thread.__init__(self)

   def run(self):
      self.app = wx.App()

      f = wx.Frame(None)
      f.Show()
      self.app.MainLoop()

t = Main()
t.start()

while True:
   time.sleep(0.001)

···

On Wed, Apr 8, 2009 at 12:30 AM, Christian K. <ckkart@hoc.net> wrote:

Hi,

once more a question about threading and the mainloop. Do I remember right,
that the the mainloop has to run in the main thread, i.e. that one which is
started with the python interpreter or is the only necessity that no gui
functions may be called from outside the mainloop thread?
I am asking because I would like to use wxpython in a COM server. Currently
I am instantiating a new wx.App object every time I need to show a dialog,
etc. but doing so, the COM server is blocked while the wxpyhton mainloop is
running.
The following example (as suspected) does not work.

import wx

from threading import Thread

class Main(Thread):
def __init__(self):
Thread.__init__(self)
self.app = wx.PySimpleApp(0)

   f = wx\.Frame\(None\)
   f\.Show\(\)

def run(self):
self.app.MainLoop()

t = Main()
t.start()

raw_input()

Any pointers are highly appreciated. I really want to avoid to code the gui
using the pywin32 extensions.

Regards, Christian

_______________________________________________
wxpython-users mailing list
wxpython-users@lists.wxwidgets.org
http://lists.wxwidgets.org/mailman/listinfo/wxpython-users

Christian K. wrote:

Hi,

once more a question about threading and the mainloop. Do I remember right, that the the mainloop has to run in the main thread, i.e. that one which is started with the python interpreter or is the only necessity that no gui functions may be called from outside the mainloop thread?

The thread that creates the wx.App object is the main thread as far as wx is concerned.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

This is an old thread but I found it when I was having issues with this exact situation, so thought I would post my discoveries in case it helps anyone else. Using @Mark_Guagenti’s code everything worked correctly, except that on exit I got an pop-up warning from wxWidgets about the wrong thread being used. This happens because there is an atexit handler registered to call wx._core._wxPyCleanup to tear down the wxWidgets resources when the application finishes, and as this is called from the main thread, this causes issues. What I found is that by calling this function myself immediately after returning from self.app.MainLoop(), the atexit call seems to decide that there is nothing left to tear down, and so the error doesn’t appear anymore. I should note for posterity that this is with wxPython 4.1.1 and Python 3.9, a lot of things have changed since this topic was originally opened.

1 Like

Hi, Ben

Thank you for this information. Alternatively, the following command also works.

    self.app.SetAssertMode(wx.APP_ASSERT_SUPPRESS)

But I found that with or without this, two threads make the program crashed silently.

t = Main()
t.start()
t2 = Main()
t2.start()

EDIT I found that a short sleep avoids a crash somehow :roll_eyes:

t = Main()
t.start()
time.sleep(1) # to prevent a crash
t2 = Main()
t2.start()

I don’t know a good reason for running the GUI loop not in __main__, but what about wxasync :face_with_hand_over_mouth:

Hi, da-dada

Thank you for the interesting information. I played with wxasync and felt like very fast wx.Yield. But I think this is essentially a single thread and cannot be an alternative…

How about the following use case for debugging Qt apps :face_with_hand_over_mouth: with wx.py.shell.

import threading
import time
import wx
from wx.py.shell import ShellFrame as Frame
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui

class Main(threading.Thread):
    def run(self):
        app = wx.App()
        frm = Frame(None, title=str(threading.current_thread()))
        frm.Show()
        app.MainLoop()
        wx._core._wxPyCleanup()

t = Main()
t.start()

time.sleep(1)

qApp = QtGui.QApplication()
plt = pg.plot(np.random.normal(size=100), title=str(threading.current_thread()))
plt.centralWidget.vb.setLimits(xMin=-20, xMax=120, minXRange=5, maxXRange=100)
pg.exec()

Clipboard01

Hello komoto48g

since I usually don’t use shells I have the problem where to set a breakpoint ?
but I assume we are both on the cart before horse idea (and it will never stop)
(nevertheless the wxasync is an enthusiastic piece of asynchronous coding) :upside_down_face: