469,271 Members | 934 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,271 developers. It's quick & easy.

wxPython: TextCtrl delayed update when using TE_RICH(2)

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.

Feb 3 '07 #1
5 2701
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
Feb 4 '07 #2
On 2/4/07, jean-michel bain-cornu <py********@nospam.jmbc.frwrote:
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.
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.
Feb 5 '07 #3
>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.
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
Feb 5 '07 #4
On 2/5/07, jean-michel bain-cornu <py********@nospam.jmbc.frwrote:
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.

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.
Feb 5 '07 #5
>
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
Feb 5 '07 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Logan | last post: by
1 post views Thread by sillyemperor | last post: by
reply views Thread by Robin Dunn | last post: by
reply views Thread by Robin Dunn | last post: by
1 post views Thread by PeterG | last post: by
4 posts views Thread by Jimmy | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.