wxPython: TextCtrl delayed update when using TE_RICH(2)

C

citronelu

I made a small wxPython app that retrieves web data; for visual
logging I use a TextCtrl widget, and stdout is redirected to it,
something like this:

class RedirectOutput:
def __init__(self, objectTxtCtrl):
self.out = objectTxtCtrl

def write(self, string):
self.out.WriteText(string)

[...]

messages = wx.TextCtrl(panel, -1, "", size = (-1, 200), style =
wx.TE_MULTILINE | wx.TE_RICH, name = "messages")

myout = RedirectOutput(messages)
sys.stdout = myout


The web query is inside a function (def Execute), binded to a button.
To simplify the story, consider the function looks like this:

def Execute(self, evt):
print "Start query"
time.sleep(5)

The "Start query" message should show in the *messages* box when I
press the button. Instead, it shows only after the time.sleep(5)
delay.

If I don't use the wx.TE_RICH / wx.TE_RICH2 style on *messages*, the
text shows before the time.sleep(5)

I want to use wx.TE_RICH / wx.TE_RICH2 because of the 64k limitation
of the standard TextCtrl.

I'm using python 2.4.3 and wxpython 2.8.1.1 unicode, on WinXP SP2.
Windows extensions are also installed.
 
J

jean-michel bain-cornu

Hi,
def Execute(self, evt):
print "Start query"
time.sleep(5)

The "Start query" message should show in the *messages* box when I
press the button. Instead, it shows only after the time.sleep(5)
delay.

If I don't use the wx.TE_RICH / wx.TE_RICH2 style on *messages*, the
text shows before the time.sleep(5)

For this kind of stuff, I'd try to put "self.out.WriteText(string)" in
some 'Idle' event, which avoid to fall in focus loops or other objects
events management problems not easy to solve.

Did you try something like that :

def write(self, string):
self.outBuffer= string
def onIdle(self,event):
if self.outBuffer != None:
self.out.WriteText(self.outBuffer)
self.outBuffer= None
 
C

Chris Mellon

Hi,

For this kind of stuff, I'd try to put "self.out.WriteText(string)" in
some 'Idle' event, which avoid to fall in focus loops or other objects
events management problems not easy to solve.

This doesn't have anything to do with focus loops or otherwise, it's
because the OP isn't familiar with event based programming.

You're performing a long-running task which is preventing the event
loop from processing, so your text isn't updating and your application
is unresponsive. You need to rewrite your task - either do everything
asynchronously, or use a threaded approach. If you use the thread
approach, be sure to not call the updates directly, you can use the
wx.CallAfter mechanism to call gui functions in a threadsafe manner.

There is a lot of information about this on the wxPython wiki and in
the archives of the wxpython-users ML.
 
J

jean-michel bain-cornu

For this kind of stuff, I'd try to put "self.out.WriteText(string)" in
This doesn't have anything to do with focus loops or otherwise, it's
because the OP isn't familiar with event based programming.

You're performing a long-running task which is preventing the event
loop from processing, so your text isn't updating and your application
is unresponsive. You need to rewrite your task - either do everything
asynchronously, or use a threaded approach. If you use the thread
approach, be sure to not call the updates directly, you can use the
wx.CallAfter mechanism to call gui functions in a threadsafe manner.

So it is an event management problem.
The event loop is not yet finished when the program want to display
something, potentially initiating a new event loop.

If you don't want to bother with threads, the idle event approach is not
so bad. Put something to display in a buffer, and display it only one
time the gui have nothing else to do.
I use it every time I can, and it's very safe and easy to do.
Furthermore, you can still step into the program with a debugger, which
can be tricky if the program uses threads (I'd say impossible, but I
didn't try in fact).

Regards
jm
 
C

Chris Mellon

So it is an event management problem.
The event loop is not yet finished when the program want to display
something, potentially initiating a new event loop.

This is almost totally wrong. There is no "new event loop" involved.
The OP is running a long task in the main thread, which is blocking
the event loop. When the event loop is blocked, the application will
not update and cannot be interacted with. It's that simple. The event
loop in a gui application doesn't "finish" until the application
exits.
If you don't want to bother with threads, the idle event approach is not
so bad. Put something to display in a buffer, and display it only one
time the gui have nothing else to do.

The problem is not putting the text into the control - the OP is
mislead by the symptoms. The problem is the task he's perform in
addition to the logging, which is a long running task (and in his
sample code is represented by time.sleep). The logging issue is a red
herring, the real problem is the way he's structured his application,
with work blocking the event loop. Until he changes this, nothing
about the way he writes to his log is going to fix the problem.
I use it every time I can, and it's very safe and easy to do.
Furthermore, you can still step into the program with a debugger, which
can be tricky if the program uses threads (I'd say impossible, but I
didn't try in fact).

Using idle events for continual calculation actually has several
caveats you need to be aware of, and I don't recommend it. A
background thread or a timer is generally a better solution.
 
J

jean-michel bain-cornu

This is almost totally wrong. There is no "new event loop" involved.
The OP is running a long task in the main thread, which is blocking
the event loop. When the event loop is blocked, the application will
not update and cannot be interacted with. It's that simple. The event
loop in a gui application doesn't "finish" until the application
exits.

I appreciate the fact that it is not *completely* wrong...
Try to get out of your point of view, maybe you'll find something
interesting. Maybe the 'true' part of mine.

Regards
jm
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top