wxPython in a thread, OS X "Couldn't contact Spell Checker"

Hello all,

I'm new to wxPython and using it to launch a GUI from a Twisted Python
process. It's a slightly backwards arrangement where the twisted
process runs as a daemon but pops up a dialog box every now and again.

Because twisted is asynchronous, we are forced to run the wxPython app
in a thread to avoid the event loop stalling while the GUI is open.
Initially this approach seems to work, but I've discovered a problem
that is related to running in a thread is this manner:

The GUI we create has a wx.TextCtrl with style=wx.TE_MULTILINE. On my
Mac, a side-effect of using the multiline widget is that the spell
checker is invoked on the contents, by default as characters are
added. When running in a thread, this step locks up the GUI before
eventually producing the error "Alert: Couldn't contact Spell
Checker".

Confoundingly, it only seems to have the problem if a value is set
programmatically for the TextCtrl -- i.e. via the value kwarg during
contruction or via a call to SetValue. If you don't set an initial
value and just type in the box, the spell checker is invoked
successfully.

I've included a testcase that demonstrates these problems, but I also
want to ask a couple of questions. First and foremost, is it
reasonable to be running a wxPython app inside a thread like this?
Secondly, if this is just a special case, is there a way to
programatically disable spellchecking on a multiline TextCtrl?

I'm running the default Leopard installation of wxPython (2.8.4.0) on
Python 2.5. The problem seems specific to OS X. I've run the attached
testcase with 2.8.x on Windows and Ubuntu, both Python2.5, without
issue.

Many thanks,
Matt.

···

-------------
testcase.py

#!/usr/bin/python

from threading import Thread
import wx

class GUI(wx.Frame):

    def __init__(self, id, title, size=None):

        #create frame
        wx.Frame.__init__(self, None, id, title, size=size)

        #parent panel & layout
        panel = wx.Panel(self, -1)
        vbox = wx.BoxSizer(wx.VERTICAL)

        #data
        label = "What is the Answer to Life, the Universe &
Everything?"
        initial_value = "Hint: it's between 41 and 43"

        #generate components
        label = wx.StaticText(panel, -1, label)

        #this errors in threaded case:
        textarea = wx.TextCtrl(panel, -1, value=initial_value,
style=wx.TE_MULTILINE)

        #this also errors in threaded case:
        #textarea = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE)
        #textarea.SetValue(initial_value)

        #this works in threaded case:
        #textarea = wx.TextCtrl(panel, -1, style=wx.TE_MULTILINE)

        #build layout
        box = wx.BoxSizer(wx.VERTICAL)
        box.Add(label, 0, wx.BOTTOM, 3)
        box.Add(textarea, 1, wx.EXPAND)

        #add to parent layout
        vbox.Add(box, 1, wx.EXPAND | wx.ALL, 10)

        #end spacer
        vbox.Add((-1, 15))

        #apply parent layout; center'n'show
        panel.SetSizer(vbox)
        self.Centre()
        self.Show(True)

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

   def run(self):
        app = wx.App()
        GUI(-1, 'Spell Check Test - Threaded', size=(500, 600))
        app.MainLoop()

if __name__ == '__main__':

    NORMAL = 100
    INTHREAD = 101

    CASE = INTHREAD

    if CASE is NORMAL:
        app = wx.App()
        GUI(-1, 'Spell Check Test', size=(500, 600))
        app.MainLoop()

    elif CASE is INTHREAD:
        threaded = ThreadedGUI()
        threaded.start()

I suggest using twisted's wxreactor for this. This avoid having two threads. So far I haven't run into any problems when using it, the wxapp behaves just as if there was no twisted.

-Matthias

···

Am 02.10.2009, 15:55 Uhr, schrieb Matt Bennett <bennett.matthew@gmail.com>:

Hello all,

I'm new to wxPython and using it to launch a GUI from a Twisted Python
process. It's a slightly backwards arrangement where the twisted
process runs as a daemon but pops up a dialog box every now and again.

Because twisted is asynchronous, we are forced to run the wxPython app
in a thread to avoid the event loop stalling while the GUI is open.
Initially this approach seems to work, but I've discovered a problem
that is related to running in a thread is this manner:

The GUI we create has a wx.TextCtrl with style=wx.TE_MULTILINE. On my
Mac, a side-effect of using the multiline widget is that the spell
checker is invoked on the contents, by default as characters are
added. When running in a thread, this step locks up the GUI before
eventually producing the error "Alert: Couldn't contact Spell
Checker".

Confoundingly, it only seems to have the problem if a value is set
programmatically for the TextCtrl -- i.e. via the value kwarg during
contruction or via a call to SetValue. If you don't set an initial
value and just type in the box, the spell checker is invoked
successfully.

I've included a testcase that demonstrates these problems, but I also
want to ask a couple of questions. First and foremost, is it
reasonable to be running a wxPython app inside a thread like this?
Secondly, if this is just a special case, is there a way to
programatically disable spellchecking on a multiline TextCtrl?

I'm running the default Leopard installation of wxPython (2.8.4.0) on
Python 2.5. The problem seems specific to OS X. I've run the attached
testcase with 2.8.x on Windows and Ubuntu, both Python2.5, without
issue.

Matthias,

> I'm new to wxPython and using it to launch a GUI from a Twisted Python
> process. It's a slightly backwards arrangement where the twisted
> process runs as a daemon but pops up a dialog box every now and again.

> Because twisted is asynchronous, we are forced to run the wxPython app
> in a thread to avoid the event loop stalling while the GUI is open.

I suggest using twisted's wxreactor for this. This avoid having two
threads. So far I haven't run into any problems when using it, the wxapp
behaves just as if there was no twisted.

Ours is not a windowed application that does some work using twisted
occasionally. Instead, it's the (admittedly less common) reverse case:
we have a twisted daemon that occcasionally needs to show a GUI. As I
understand it, wxreactor only gives you a way to run a twisted event
loop inside a wxApp, not the other way around.

···

On Oct 2, 6:06 pm, Nitro <nitrogen...@googlemail.com> wrote:

Am 02.10.2009, 15:55 Uhr, schrieb Matt Bennett <bennett.matt...@gmail.com>:

-Matthias

Matt Bennett wrote:

Ours is not a windowed application that does some work using twisted
occasionally. Instead, it's the (admittedly less common) reverse case:
we have a twisted daemon that occcasionally needs to show a GUI.

The other option would be to run the GUI as a separate process. Communicating with it should be easy if you're using twisted already...

That being said, there are folks running wx in a separate (not the main one) thread. You might look at how ipython does it, for example. But this sounds like a weird, mac-specific bug -- I wonder if you can turn off the spell-checking somehow?

You also might get around it by running wx in the Main thread, and twisted in a secondary thread.

-Chris

···

--
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

You are right. I thought it was the other around (twisted mainloop calling wxApp.Pending/Dispatch). It might have been that way many years ago, but I am not sure.

Regarding your problem, I guess you could always split these 2 apps (network, gui popup) and then use some kind of IPC. E.g. the wxPython app could connect to the network app with twisted's pb and your network app sends events to the gui app whenever it needs to. You could even run the gui monitoring in a different location or have multiple clients monitoring your network app that way. Of course this is a bit more involved than your original solution and depending on your needs and the scale of your application it might very well be overkill. Using a more lightweight kind of IPC (e.g. using python's multiprocessing module) might make this easier though.

Also be sure, you always call wx-related functionality only from the thread you created wx.App in. Never call something in the gui thread directly from the network thread. Use wx.CallAfter for this.

On the other hand, maybe it's possible to run the wxapp in a second thread like you suggested and the behaviour you are seeing is just a bug in wxMac's text ctrl when there's more than one thread.

So you better wait for a more qualified answer than mine :slight_smile:

-Matthias

···

Am 02.10.2009, 19:36 Uhr, schrieb Matt Bennett <bennett.matthew@gmail.com>:

Matthias,

On Oct 2, 6:06 pm, Nitro <nitrogen...@googlemail.com> wrote:

Am 02.10.2009, 15:55 Uhr, schrieb Matt Bennett >> <bennett.matt...@gmail.com>:

> I'm new to wxPython and using it to launch a GUI from a Twisted Python
> process. It's a slightly backwards arrangement where the twisted
> process runs as a daemon but pops up a dialog box every now and again.

> Because twisted is asynchronous, we are forced to run the wxPython app
> in a thread to avoid the event loop stalling while the GUI is open.

I suggest using twisted's wxreactor for this. This avoid having two threads. So far I haven't run into any problems when using it, the wxapp behaves just as if there was no twisted.

Ours is not a windowed application that does some work using twisted
occasionally. Instead, it's the (admittedly less common) reverse case:
we have a twisted daemon that occcasionally needs to show a GUI. As I
understand it, wxreactor only gives you a way to run a twisted event
loop inside a wxApp, not the other way around.

I'm not able to duplicate this with a newer wxPython. I don't know if this is related to the wx version or some other difference on my machine, but you should try upgrading. Also, I don't recall when it was added but wx.TextCtrl now has a MacCheckSpelling method to turn spell check on or off.

···

On 10/2/09 6:55 AM, Matt Bennett wrote:

Hello all,

I'm new to wxPython and using it to launch a GUI from a Twisted Python
process. It's a slightly backwards arrangement where the twisted
process runs as a daemon but pops up a dialog box every now and again.

Because twisted is asynchronous, we are forced to run the wxPython app
in a thread to avoid the event loop stalling while the GUI is open.
Initially this approach seems to work, but I've discovered a problem
that is related to running in a thread is this manner:

The GUI we create has a wx.TextCtrl with style=wx.TE_MULTILINE. On my
Mac, a side-effect of using the multiline widget is that the spell
checker is invoked on the contents, by default as characters are
added. When running in a thread, this step locks up the GUI before
eventually producing the error "Alert: Couldn't contact Spell
Checker".

Confoundingly, it only seems to have the problem if a value is set
programmatically for the TextCtrl -- i.e. via the value kwarg during
contruction or via a call to SetValue. If you don't set an initial
value and just type in the box, the spell checker is invoked
successfully.

I've included a testcase that demonstrates these problems, but I also
want to ask a couple of questions. First and foremost, is it
reasonable to be running a wxPython app inside a thread like this?
Secondly, if this is just a special case, is there a way to
programatically disable spellchecking on a multiline TextCtrl?

I'm running the default Leopard installation of wxPython (2.8.4.0) on
Python 2.5. The problem seems specific to OS X. I've run the attached
testcase with 2.8.x on Windows and Ubuntu, both Python2.5, without
issue.

--
Robin Dunn
Software Craftsman