Long Running Tasks and wxPython

Hi,

After reading various articles and testing demo examples I am trying
to create couple of examples for subject.
The most useful article is here:
http://wiki.wxpython.org/LongRunningTasks

I have divided task into three categories:
1. Recursive (Example :: Listening continuously a port)
2. Non-Recursive (Example :: sending email using SMTP)
3. External Process (Example :: Launch external process and capture
in,error and out)

The idea is to produce three working example as mentioned above. In
all of the three categories there are few things remain constant.
1. User will start the process on demand.
2. User can interrupt/close the process.
3. Result (stdin,out/error) should be accessible.

I have created first example (2. Non-Recursive) of sending email using
SMTP. The file is attached here. Make sure you change MAIL_SERVER,
USER and PASSWORD
global.

Here are the details:
1. Click "Send Email" button"
2. The process can be interrupted by user in two ways: Press "Abort"
or close the application itself.
3. If user is closing the app (by close button or "Cancel" button) no
error or warning is thrown but I am bit concerned about the thread
that I started. I am not stopping it at the time of destroying of
frame as I have no access to it. Is it ok?
4. If user is pressing "Abort", immediately after pressing "Send
Email" button, the process is not stopped and after couple of seconds
you can see a message box saying "Message has been sent".

Q:1 How do you correctly interrupt the process? (at destroy or at abort)
Q:2 Is there any better solution for the giving scenario?

I am requesting to all experienced user to provide their suggestions
to finish the task. I have access to three platforms(win, linux and
mac) to test.

Cheers

Prashant

ex_2.py (4.19 KB)

3. If user is closing the app (by close button or "Cancel" button) no
error or warning is thrown but I am bit concerned about the thread
that I started. I am not stopping it at the time of destroying of
frame as I have no access to it. Is it ok?

You should maintain a handle to the thread so that you can signal it
to quit and then monitor or join() it.

4. If user is pressing "Abort", immediately after pressing "Send
Email" button, the process is not stopped and after couple of seconds
you can see a message box saying "Message has been sent".

You can remedy this by using a boolean to signal the email sending to stop.

class MailMan(threading.Thread)
    def __init__(self):
        self.aborted = False
        self.start()

    def run(self, message_text, window):
        try:
            if not self.aborted:
                self.smtp.connect(...)
            if not self.aborted:
                 self.smtp.login(...)
        ...

    def abort(self):
        self.aborted = True
        ...

Then the user can actually abort sending the email.

Q:1 How do you correctly interrupt the process? (at destroy or at abort)
Q:2 Is there any better solution for the giving scenario?

Notice above I derived MailMan from threading.Thread. This will allow
you to control the thread. You can for instance signal the email
sending to abort and then wait for the thread to actually stop.

class MainFrame(wx.Frame):
    def __init__(self, parent):
        this.mailman = None

    def onSendMail(self, evt):
        ...
        this.mailman = MailMan('This is my message.', self)

    def onAbortMail(self, evt):
        if self.mailman:
            self.label.SetLabel('Aborting...')
            self.mailman.abort()
            while self.mailman.is_alive():
                # Allow the mainloop to process pending events
                # so the GUI stays responsive.
                wx.Yield()
                time.sleep(0.1)
        self.label.SetLabel('Aborted')
        ...

    def onClose(self, evt):
        if self.mailman:
            self.label.SetLabel('Aborting...')
            self.mailman.abort()
            self.mailman.join()
        self.Destroy()

I am requesting to all experienced user to provide their suggestions
to finish the task. I have access to three platforms(win, linux and
mac) to test.

It just seems to me that you want to keep a handle to the thread
around to give you control of it. You also want to use some sort of
signal to let the thread know when to give up the ghost. If the thread
is in a loop of some type, you will want to do something like:

while not self.aborted:
    ... do some work ...

If you read and actually test the applications below, there is a lot
to be learned. The wx.Yield() bit is mentioned there, as well as many
other techniques.

http://wiki.wxpython.org/LongRunningTasks

More information about threading.Thread and the interface it provides
for controlling your threads.

Hope that Helps.

···

On Sat, Feb 26, 2011 at 11:41 AM, Prashant Saxena <animator333@gmail.com> wrote:

Thanks Ben,

I made some changes as per you suggestions and you can a check the new version here:
http://pastebin.com/4s3q8WDU

This one is working fine on windows(xp) and mac 10.5.5 (leopard). On linux (python 2.6.5, wxpython 2.8.10.1 gtk-unicode, ubuntu hardy 8.04 GNOME) it’s getting crashed badly. Special case is when you are not connected to internet and press “Send” button and “Abort” immediately.

The error is:
python: …/…/src/xcb_lock.c:77: _XGetXCBBuffer: Assertion `((int) ((xcb_req) - (dpy->request)) >= 0)’ failed.

After googling I have found that this is a thread related issue. Again I am looking for some help here.

Prashant

Hello list!..

Am designing a piping software, right now it works on 2D. I

implemented a very simple canvas with wx.paintDC() it basically goes
like this:

    <small>def OnDrawing(self, evt):</small>
<small>        dc = wx.PaintDC(self.leftWindow)</small>
<small>        self.leftWindow.PrepareDC(dc)</small>
<small>        dc.Clear()</small>
<small>        for image in self.images[1:]:</small>
<small>            x = image[1][0]</small>
<small>            y = image[1][1]</small>
<small>            img = wx.Image(image[0], wx.BITMAP_TYPE_ANY)</small>
<small>            bmp = wx.BitmapFromImage(img)</small>
<small>            dc.DrawBitmap(bmp, x, y, True)</small>

<small></small>    The result is this [1]. The buttons on the right are

used to add sections (pipes, valves, etc) to the canvas. when you
click on a button the program calculate the position and draw it, so
the canvas its non interactive, you cant clic on the segments of
pipe or valves, cant resize it, etc.

This its very easy and simple, but as a new programmer it cost me

some time (and am fairly proud of it). now I want to improve that,
what I want to do now is to create a 3D-like interactive canvas,
where the user could create “by mouse” the pipe diagram, click on
them to change properties etc.

what am aiming for its something like these [2] [3]. with a

isometric background like this [4]

I guess thats not going to be easy (but neither was for me at the

beginning what I did), but am decided to keep trying and studying to
make it. What I want from you guys is directions…

Now I dont know where to start, am wondering "is this possible on

wx?", “should I use openGL?”. I need you to point to the right
direction.

is this possible to implement with only wx? or I need pyopengl

(witch I dont know anything about), or something like that?

thanks!!!...

[1] [2]

[3] [4]

···

http://dl.dropbox.com/u/391810/py13.PNG
http://www.visguy.com/wp-content/uploads/2008/06/sampleisometricpipingdrawing-thumb.png
http://img13.imageshack.us/i/pipemht.jpg/sr=1
http://mrmaths.org/Shapes/IsometricTriangles.jpg

Your window.onResult is being called from the worker thread's context, and it is doing operations on UI elements. While this can sometimes work if all the stars are in proper alignment, most of the time it can only cause problems. Especially on GTK as the X libs are especially susceptible to multi-thread issues.

···

On 2/27/11 5:16 AM, King wrote:

Thanks Ben,

I made some changes as per you suggestions and you can a check the new
version here:
wxpython : send email using thread - Pastebin.com

This one is working fine on windows(xp) and mac 10.5.5 (leopard). On
linux (python 2.6.5, wxpython 2.8.10.1 gtk-unicode, ubuntu hardy 8.04
GNOME) it's getting crashed badly. Special case is when you are not
connected to internet and press "Send" button and "Abort" immediately.

The error is:
python: ../../src/xcb_lock.c:77: _XGetXCBBuffer: Assertion `((int)
((xcb_req) - (dpy->request)) >= 0)' failed.

After googling I have found that this is a thread related issue. Again I
am looking for some help here.

--
Robin Dunn
Software Craftsman

Hello list!..

Am designing a piping software, right now it works on 2D. I implemented
a very simple canvas with wx.paintDC() it basically goes like this:

def OnDrawing(self, evt):
dc = wx.PaintDC(self.leftWindow)
self.leftWindow.PrepareDC(dc)
dc.Clear()
for image in self.images[1:]:
x = image[1][0]
y = image[1][1]
img = wx.Image(image[0], wx.BITMAP_TYPE_ANY)
bmp = wx.BitmapFromImage(img)
dc.DrawBitmap(bmp, x, y, True)

What is image[0]? If it's the filename of the tile to be painted then you'll save a lot of time and resources by preloading those bitmaps and reusing them. Also, you don't need to load into a wx.Image if all you're going to do with it is convert it to a bitmap. wx.Bitmap can load the file itself.

Finally, I expect that you're seeing a lot of flicker on Windows as the paint event method is working. You should learn about doing double-buffered drawing to see what alternate approaches you could take to minimize the flicker. There are some examples in the wiki.

The result is this [1]. The buttons on the right are used to add
sections (pipes, valves, etc) to the canvas. when you click on a button
the program calculate the position and draw it, so the canvas its non
interactive, you cant clic on the segments of pipe or valves, cant
resize it, etc.

This its very easy and simple, but as a new programmer it cost me some
time (and am fairly proud of it). now I want to improve that, what I
want to do now is to create a 3D-like interactive canvas, where the user
could create "by mouse" the pipe diagram, click on them to change
properties etc.

what am aiming for its something like these [2] [3]. with a isometric
background like this [4]

I guess thats not going to be easy (but neither was for me at the
beginning what I did), but am decided to keep trying and studying to
make it. What I want from you guys is directions..

Now I dont know where to start, am wondering "is this possible on wx?",
"should I use openGL?". I need you to point to the right direction.

is this possible to implement with only wx? or I need pyopengl (witch I
dont know anything about), or something like that?

It can all be done in plain wx, but I expect that something done with OpenGL would look lots better, and if you want to do things like rotate the drawing in 3D space then something like OpenGL is probably the only approach you should take. I don't know a whole lot about it myself however so I can't give you any idea about relative complexities.

···

On 2/27/11 12:43 PM, PythonJourney wrote:

--
Robin Dunn
Software Craftsman

Nice catch Robin, I was stumped.

So, that means instead of directly calling onResult from the worker
thread, use something to defer the call back to the main thread.
wx.CallAfter can do that.

http://wiki.wxpython.org/CallAfter

···

On Mon, Feb 28, 2011 at 12:34 PM, Robin Dunn <robin@alldunn.com> wrote:

Your window.onResult is being called from the worker thread's context, and
it is doing operations on UI elements. While this can sometimes work if all
the stars are in proper alignment, most of the time it can only cause
problems. Especially on GTK as the X libs are especially susceptible to
multi-thread issues.

El 28/02/2011 01:05 p.m., Robin Dunn escribi�:

Hello list!..

Am designing a piping software, right now it works on 2D. I implemented
a very simple canvas with wx.paintDC() it basically goes like this:

def OnDrawing(self, evt):
dc = wx.PaintDC(self.leftWindow)
self.leftWindow.PrepareDC(dc)
dc.Clear()
for image in self.images[1:]:
x = image[1][0]
y = image[1][1]
img = wx.Image(image[0], wx.BITMAP_TYPE_ANY)
bmp = wx.BitmapFromImage(img)
dc.DrawBitmap(bmp, x, y, True)

What is image[0]? If it's the filename of the tile to be painted then you'll save a lot of time and resources by preloading those bitmaps and reusing them. Also, you don't need to load into a wx.Image if all you're going to do with it is convert it to a bitmap. wx.Bitmap can load the file itself.

yes its the files. I have this:

     def workingImages(self):
         return {self.rightButtonsData()[0][1] : ("img/pipesmallH.png", (100, 10)),
                 self.rightButtonsData()[1][1] : ("img/pipesmallV.png", (10, 100)),
                 self.rightButtonsData()[2][1] : ("img/bendsmallSE.png", (17, 17)),
                 self.rightButtonsData()[3][1] : ("img/bendsmallNO.png", (17, 17)),
                 self.rightButtonsData()[4][1] : ("img/bendsmallSO.png", (17, 17)),
                 self.rightButtonsData()[5][1] : ("img/bendsmallNE.png", (17, 17)),
                 self.rightButtonsData()[6][1] : ("img/valvesmallH.png", (14, 12)),
                 self.rightButtonsData()[7][1] : ("img/valvesmallV.png", (14, 12)),
                 self.rightButtonsData()[8][1] : ("img/contrsmallH.png", (15, 10)),
                 self.rightButtonsData()[9][1] : ("img/contrsmallV.png", (10, 15)),
                 self.rightButtonsData()[10][1] : ("img/180bendsmallE.png", (15, 23)),
                 self.rightButtonsData()[11][1] : ("img/180bendsmallN.png", (23, 15)),
                 self.rightButtonsData()[12][1] : ("img/180bendsmallO.png", (15, 23)),
                 self.rightButtonsData()[13][1] : ("img/180bendsmallS.png", (23, 15))
                 }

and I have a function that respond with every buttons click, that depending on the button, it appends entries on a self.image list that is used in the OnDrawing.

Honestly although the program works fine, being my first project in python and wxpython (and programming in general) I expect a lot of "things can be done better" and a bad coding style, am working on improving all that, so thank you for the tips!!..

Finally, I expect that you're seeing a lot of flicker on Windows as the paint event method is working. You should learn about doing double-buffered drawing to see what alternate approaches you could take to minimize the flicker. There are some examples in the wiki.

I haven't notice any (maybe I just haven't gave any attention to that) but thanks for the recommendation..

The result is this [1]. The buttons on the right are used to add
sections (pipes, valves, etc) to the canvas. when you click on a button
the program calculate the position and draw it, so the canvas its non
interactive, you cant clic on the segments of pipe or valves, cant
resize it, etc.

This its very easy and simple, but as a new programmer it cost me some
time (and am fairly proud of it). now I want to improve that, what I
want to do now is to create a 3D-like interactive canvas, where the user
could create "by mouse" the pipe diagram, click on them to change
properties etc.

what am aiming for its something like these [2] [3]. with a isometric
background like this [4]

I guess thats not going to be easy (but neither was for me at the
beginning what I did), but am decided to keep trying and studying to
make it. What I want from you guys is directions..

Now I dont know where to start, am wondering "is this possible on wx?",
"should I use openGL?". I need you to point to the right direction.

is this possible to implement with only wx? or I need pyopengl (witch I
dont know anything about), or something like that?

It can all be done in plain wx, but I expect that something done with OpenGL would look lots better, and if you want to do things like rotate the drawing in 3D space then something like OpenGL is probably the only approach you should take. I don't know a whole lot about it myself however so I can't give you any idea about relative complexities.

I only need things like zoom-in and zoom-out, and that the objects being draw to respond to mouse click..

as the images show, I wont be creating a 3D structure, I just need a 3D-like background, more precisely an isometric one, to draw piping representation, this image [0] show exactly what I want to do (without the yellow, blue and green part I just want the program to be able to make the piping diagram)

Now that you said that it can be done with wx, can you gave me some pointers on how to implement it?. last time I tried I didn't find a way to make the objects being draw to respond to mouse click.

Do you think that pygame could do the trick too? as long as it can be used with wx I could try anything..

[0] http://img13.imageshack.us/i/pipemht.jpg/sr=1

···

On 2/27/11 12:43 PM, PythonJourney wrote:

PythonJourney wrote:

as the images show, I wont be creating a 3D structure, I just need a
3D-like background, more precisely an isometric one, to draw piping
representation, this image [0] show exactly what I want to do (without
the yellow, blue and green part I just want the program to be able to
make the piping diagram)

Now that you said that it can be done with wx, can you gave me some
pointers on how to implement it?. last time I tried I didn't find a way
to make the objects being draw to respond to mouse click.

Well, the OBJECTS won't respond to mouse clicks. Your WINDOW will get a
mouse-click message. It is up to you to search through your list of
objects, find the one(s) that are closest to the click, and decide
whether the click was close enough to have meant that object or not.
Really, that's only slightly more complicated in the isometric 3D case
than it is in the 2D case, although there will still be math involved.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

def workingImages(self):
return {self.rightButtonsData()[0][1] : ("img/pipesmallH.png", (100, 10)),
self.rightButtonsData()[1][1] : ("img/pipesmallV.png", (10, 100)),

I'm guessing that the (10,100) is the size of the image -- wx.Image knows what size it is, so it should not be necessary to specify that.

It can all be done in plain wx, but I expect that something done with
OpenGL would look lots better, and if you want to do things like
rotate the drawing in 3D space then something like OpenGL is probably
the only approach you should take. I don't know a whole lot about it
myself however so I can't give you any idea about relative complexities.

I only need things like zoom-in and zoom-out, and that the objects being
draw to respond to mouse click..

OK - then you don't need a real 3-d library. But you'll need to do the math yourself to figure out where everything should be drawn.

If you do want to go with OpenGL, it does scale and draw bitmaps very well (they are called "textures" in GL). But is fundamentally a pretty low level library to work with.

Now that you said that it can be done with wx, can you gave me some
pointers on how to implement it?. last time I tried I didn't find a way
to make the objects being draw to respond to mouse click.

right -- you need to write that code yourself.

Alternatively, you may want to give wx.lib.floatcanvas a try. It will give you object clicking and zomming and panning for you.

For additional information and demos, see:

http://trac.paulmcnett.com/floatcanvas

There are a lot of little self contained demos in the SVN source.

What you have now are "raster" objects -- you can use these with FloatCanvas, as a ScaledBitmap object. How3ver, you may want to use vector objects instead -- probably less pretty, but they'll look better as you scale them, etc.

the image here:

http://img13.imageshack.us/i/pipemht.jpg/sr=1

looks like it was done with vector drawing -- i.e. a CAD program.

I've always wanted to build a CAD-like drawing program on FloatCanvas, so send questions to the list, and I'll try to find some time to help you out.

-Chris

···

On 2/28/11 1:26 PM, PythonJourney wrote:

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

El 28/02/2011 06:30 p.m., Christopher Barker escribi�:

···

On 2/28/11 1:26 PM, PythonJourney wrote:

def workingImages(self):
return {self.rightButtonsData()[0][1] : ("img/pipesmallH.png", (100, 10)),
self.rightButtonsData()[1][1] : ("img/pipesmallV.png", (10, 100)),

I'm guessing that the (10,100) is the size of the image -- wx.Image knows what size it is, so it should not be necessary to specify that.

It can all be done in plain wx, but I expect that something done with
OpenGL would look lots better, and if you want to do things like
rotate the drawing in 3D space then something like OpenGL is probably
the only approach you should take. I don't know a whole lot about it
myself however so I can't give you any idea about relative complexities.

I only need things like zoom-in and zoom-out, and that the objects being
draw to respond to mouse click..

OK - then you don't need a real 3-d library. But you'll need to do the math yourself to figure out where everything should be drawn.

If you do want to go with OpenGL, it does scale and draw bitmaps very well (they are called "textures" in GL). But is fundamentally a pretty low level library to work with.

Now that you said that it can be done with wx, can you gave me some
pointers on how to implement it?. last time I tried I didn't find a way
to make the objects being draw to respond to mouse click.

right -- you need to write that code yourself.

Alternatively, you may want to give wx.lib.floatcanvas a try. It will give you object clicking and zomming and panning for you.

For additional information and demos, see:

http://trac.paulmcnett.com/floatcanvas

There are a lot of little self contained demos in the SVN source.

What you have now are "raster" objects -- you can use these with FloatCanvas, as a ScaledBitmap object. How3ver, you may want to use vector objects instead -- probably less pretty, but they'll look better as you scale them, etc.

the image here:

http://img13.imageshack.us/i/pipemht.jpg/sr=1

looks like it was done with vector drawing -- i.e. a CAD program.

I've always wanted to build a CAD-like drawing program on FloatCanvas, so send questions to the list, and I'll try to find some time to help you out.

-Chris

Thanks..

am going to try it first with wx alone.. am reading this [0] tutorial to see if it gives me an idea of what I need to implement and how..

when am done with it i'll try FloatCanvas!!

[0] http://www.zetcode.com/wxpython/gdi/

That could be a good way to learn.

However, wx's drawing methods: DCS and GCs, only give you drawing -- that's it.

The reason I wrote floatcanvas is because I got sick of re-writing code that:

- kept track of Paint Events, etc.
- did the math to scale my data to pixel coordinates, particularly if zooming and scrolling
- Captured mouse events to figure out what was clicked on.
- did all those darn SetBrush(), etc calls

All of that is built into FloatCanvas. And, if do say so myself, it's a pretty easy to extend framework for doing custom drawing stuff.

I've enclosed a little example to give you a taste. It defines a new type of DrawObject (a spline), and then uses it to make a picture that you can zoom and pan around. Note how little code that took.

There are a bunch more little demos here:

http://svn.wxwidgets.org/viewvc/wx/wxPython/3rdParty/FloatCanvas/Demos/

-Chris

TestSpline.py (4.56 KB)

···

On 3/1/11 8:34 AM, PythonJourney wrote:

Thanks..

am going to try it first with wx alone.. am reading this [0] tutorial to
see if it gives me an idea of what I need to implement and how..

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

El 01/03/2011 12:27 p.m., Christopher Barker escribi�:

···

On 3/1/11 8:34 AM, PythonJourney wrote:

Thanks..

am going to try it first with wx alone.. am reading this [0] tutorial to
see if it gives me an idea of what I need to implement and how..

That could be a good way to learn.

However, wx's drawing methods: DCS and GCs, only give you drawing -- that's it.

The reason I wrote floatcanvas is because I got sick of re-writing code that:

- kept track of Paint Events, etc.
- did the math to scale my data to pixel coordinates, particularly if zooming and scrolling
- Captured mouse events to figure out what was clicked on.
- did all those darn SetBrush(), etc calls

All of that is built into FloatCanvas. And, if do say so myself, it's a pretty easy to extend framework for doing custom drawing stuff.

I've enclosed a little example to give you a taste. It defines a new type of DrawObject (a spline), and then uses it to make a picture that you can zoom and pan around. Note how little code that took.

There are a bunch more little demos here:

http://svn.wxwidgets.org/viewvc/wx/wxPython/3rdParty/FloatCanvas/Demos/

-Chris

thank you so much!, that actually do a lot of the thing I want..

Am going to continue with the tutorial, to learn more about what I need. Once I finish I'll start testing the FloatCanvas!

Again thanks a lot!..

Good luck.

If you have detailed questions about FloatCanvas in the future, please join the floatcanvas list and post them there.

-Chris

···

On 3/1/11 2:31 PM, PythonJourney wrote:

Am going to continue with the tutorial, to learn more about what I need.
Once I finish I'll start testing the FloatCanvas!

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