[wxPython] Intepreters and wxPython

win98se, Python 2.2.1, wxPython 2.3.2.1 (or 2.3.3pre5)

Hi all,

Writing an interactive interpreter is very instructive.
I programmed a few things that are not working, I do not
understand why, but there are also other thinks that are
working and I do not understand why! Two case studies.

1) Calling a full application from the interpreter (PyCrust or psi)

Assume a full/standalone application in a module called mod.py
having the following skeleton:

···

#-------------------------------------------------------------------
class MyFrame(...)
    def __init__(self, parent, id):
        ...
        EVT_CLOSE(self, self.OnCloseWindow)

    def OnCloseWindow(self, event):
        print 'OnCloseWindow'
        self.Destroy()

class MyApp(wxApp):
    def OnInit(self):
        frame = MyFrame(NULL, -1)
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

def main():
    print 'main is running...'
    app = MyApp(0)
    app.MainLoop()

if __name__ == "__main__" :
    main()
#-------------------------------------------------------------------

Now, in the interpreters (psi or PyCrust) I can

import mod
mod.main()

and the application start correctly.
The problem is raising when I close the application. In PyCrust,
closing the application will close PyCrust too. In psi, where the
interpreter class is a little bit different, the application closes,
but not psi. In that case, the application seems still 'pending' and
I can no more use psi. I looks like if the python interpreter has not
finished its jobs.

Has this to do with a "ThreadedInterpreter"? Two MainLoops running
at the same time? ... Why can I not start the application with

sys.execfile('mod.py')? Should the application returns some

flags? ...

2) Modules using wxPython

PyCrust or psi being interactive interpreters based on wxPython,
it should be (and it is) possible to import modules using wxPython.

For tests, I wrote the following module, job.py

#-------------------------------------------------------------------
#just draw an x,y fuction to do something interesting

from wxPython.wx import *

def MyScaleXY(w1x, w1y, w2x, w2y, ux, uy, u1x, u1y, u2x, u2y):
    wx = (ux - u1x) / (u2x - u1x) * (w2x - w1x) + w1x
    wy = (uy - u1y) / (u2y - u1y) * (w2y - w1y) + w1y
    return (wx, wy)

class MyDialog1(wxDialog):
    def __init__(self, parent, id, xx, yy):
        wxDialog.__init__(self, parent, id, "x, y plot", wxPoint(50,50),
wxSize(300, 200))

        self.size = self.GetClientSize()
        self.plotarea = wxWindow(self, id, wxPoint(0, 0),
self.GetClientSize(), wxNO_BORDER)
        self.plotarea.SetBackgroundColour(wxWHITE)

        EVT_PAINT(self, self.OnPaint)
        EVT_CLOSE(self, self.OnCloseWindow)

        self.xx, self.yy = xx, yy

    def OnPaint(self, event):
        dc = wxPaintDC(self.plotarea)
        dc.BeginDrawing()
        dc.Clear()
        dc.SetPen(wxPen(wxRED))
        xmin, xmax = min(self.xx), max(self.xx)
        ymin, ymax = min(self.yy), max(self.yy)
        if ymin == ymax:
            ymin, ymax = ymin - 1., ymax + 1.
        if xmin == xmax:
            xmin, xmax = xmin - 1., xmax + 1.

        p1x, p2x = 0, self.size[0] - 1
        p1y, p2y = 0, self.size[1] - 1

        #first point
        ax, ay = MyScaleXY(p1x, p1y, p2x, p2y, \
                    self.xx[0], self.yy[0], xmin, ymax, xmax, ymin)
        #other points
        for i in range(1, len(self.xx)):
            bx, by = MyScaleXY(p1x, p1y, p2x, p2y, \
                        self.xx[i], self.yy[i], xmin, ymax, xmax, ymin)
            dc.DrawLine(ax, ay, bx, by)
            ax, ay = bx, by
        #end of last line
        dc.DrawPoint(bx, by)

        dc.EndDrawing()

    def OnCloseWindow(self, event): # X button
        print 'OnCloseWindow'
        #~ self.Destroy()
        self.EndModal(wxID_CANCEL)

def drawxy(xx, yy):
    c = MyDialog1(None, -1, xx, yy)
    c.ShowModal()

#------------------------------------------------------

In the interpreters (PyCrust of psi):

x = [0.0, 1.0, 2.0, 3.0, 4.0]
y = [0.0, 1.0, 5.0, 3.0, 4.0]
import job
job.drawxy(x, y)

    (then close the window with the X-button)

print 'ok'
ok

I am surprised that job.drawxy(...) is working (the curved is correctly
drawn), the 'parent' of MyDialog1 being None ! Nevetheless, if I move
the opened dialog window, psi or PyCrust (or the underlying
wxStlyledTextCtl) is becoming completely grey. After having
closed the window, everything is ok and I may keep on
working with the interpreter.

The same happens, if

x = [0.0, 1.0, 2.0, 3.0, 4.0]
y = [0.0, 1.0, 5.0, 3.0, 4.0]
import job
c = MyDialog1(None, -1, x, y)
c.ShowModal()

I have the feeling, this happens because the dialog window is not
properly 'hooked' to the interpreter window/frame. Is there a way to
'hook' dynamically a window to the intepreter? Should the interpreter
provide something like an handle for the parent frame?

I agree a standalone application for drawing data is much better, but
playing with python is so nice...

A few words of explanation are welcome.

Jean-Michel Fauth, Switzerland