#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2004
    Location
    Atlanta
    Posts
    5
    Rep Power
    0

    py2exe and tkinter not working well together


    Hello everyone, please forgive if this topic already covered. I searched all forums and do not believe this particular variation of the topic has been addressed.

    I have written a Python program that executes under Python. I want to distribute it to coworkers as a stand-alone; all of us using WindowsXP. I have tried py2exe. The program compiles, but when I execute it nothing happens. I am using Python 2.3.3, and py2exe 0.5.3.

    I compile it like this, from the command prompt:

    X:\Gen3\Python>c:\Python23\python.exe setup.py py2exe


    Here is the output:


    running py2exe
    *** searching for required modules ***
    *** parsing results ***
    creating python loader for extension 'datetime'
    creating python loader for extension 'numarray._bytes'
    .
    .
    .
    creating python loader for extension 'numarray._ufuncFloat64'
    *** finding dlls needed ***
    *** create binaries ***
    *** byte compile python files ***
    byte-compiling X:\Gen3\Python\build\bdist.win32\winexe\temp\_sre.py to _sre.pyc
    .
    .
    .
    skipping byte-compilation of c:\Python23\lib\StringIO.py to StringIO.pyc
    .
    .
    .
    *** copy extensions ***
    *** copy dlls ***
    setting sys.winver for 'X:\Gen3\Python\dist\python23.dll' to 'py2exe'
    copying c:\Python23\lib\site-packages\py2exe\run_w.exe -> X:\Gen3\Python\dist\pr
    oblem.exe


    Here is a test program, along with my simple config file. What am I doing wrong?

    Disclaimer: I am electrical engineer, only able to hack my way through code. Not understand OO too good.

    Code:
    from Tkinter import *
    WINDOW = 600
    root = Tk()
    root.title('HELP ME!')
    canvas = Canvas(root, width=WINDOW, height=WINDOW, background='white')
    canvas.create_text(.5*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="text_tag",fill="#00b000")
    canvas.itemconfigure("text_tag",text="Why won't this work?")
    canvas.pack()
    Code:
    from distutils.core import setup
    import py2exe
    setup( windows=["problem.py"])
  2. #2
  3. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    14
    As a general rule don't try packaging python code with py2exe until you are sure it runs the traditional way. (either from the command line "c:\python23\python myprog.py" or with idle with the F5 key)

    Your sample requires the following as it's final line for Tkinter to actaully get started:

    Code:
    root.mainloop()
    when the application runs then look at some of the examples in the forum (keyword "py2exe").

    Also - makes sure you are running py2exe 0.5.

    I too was and an E/E Engineer once, then I found software

    grm
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2004
    Location
    Atlanta
    Posts
    5
    Rep Power
    0

    Excellent!


    Wow, thanks for the quick response and not flaming me for such a lame question! It works! I simply added root.mainloop() at the end.


    I do have one thing that puzzles me: the code I originally posted I had checked out using IDLE and it did display a window. Therefore, I thought the code was okay. Obviously, I am used to writing things in a linear fashion and this is one of those OO things (the mainloop thing). If you guys will humor me for just a second, I'd like to post my original piece of software (that indeed works under IDLE) and ask your help in cleaning it up and making it elegant. It works, but has no mainloop() call. It interfaces through the serial port to a little AVR microcontroller and displays the data it reads. It takes 10 samples, writes the data into a CSV file, and exits.

    Thanks in advance for your help!

    Code:
    #************************************************************************
    # $Author: ehawkins $
    # $Date: 2004/07/09 17:32:39 $
    #
    # $Log: gen3.py,v $
    # Revision 1.1  2004/07/09 17:32:39  ehawkins
    # Initial check-in of Python monitor code
    #
    #************************************************************************
    
    from Tkinter import *
    import pickle
    import time
    import re
    import serial
    import numarray
    import csv
    
    WINDOW = 600
    NSAMPLES = 254
    MAX = 1040
    CHANNELS = 2
    FRAMINGBYTES = 4
    
    
    def OpenSerial():
        global ser
        ser = serial.Serial()
        if ser.isOpen():
            ser.close()
        ser.baudrate = 9600
        ser.port = 'COM1'
        ser.open()
        ser.setDTR()
    
    def CloseSerial():
        try:
            if ser.isOpen():
                ser.close()
        except:
            print "WARNING: Exception raised: ser.close() attempted before ser defined"
        else:
            print "WARNING: ser.close() has issues"
    
    root = Tk()
    root.title('GEN3')
    root.bind('q','exit')
    canvas = Canvas(root, width=WINDOW, height=WINDOW, background='white')
    canvas.create_text(.1*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v00",fill="#00b000")
    canvas.create_text(.1*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v10",fill="#b00000")
    
    canvas.create_text(.30*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0n",fill="#00b000")
    canvas.create_text(.30*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1n",fill="#b00000")
    
    canvas.create_text(.50*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0-",fill="#00b000")
    canvas.create_text(.50*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1-",fill="#b00000")
    
    canvas.create_text(.65*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0c",fill="#00b000")
    canvas.create_text(.65*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1c",fill="#b00000")
    
    OpenSerial()
    
    for test in range(10):
        line2d = []
        path = numarray.zeros((CHANNELS, (NSAMPLES*2 + 2)))
        imp = numarray.zeros((CHANNELS, NSAMPLES))
        diff = numarray.zeros((CHANNELS, NSAMPLES))
        byte = numarray.zeros((FRAMINGBYTES))
        cap = numarray.zeros((CHANNELS))
        print "Finding framing ..."
        while not (((byte[0] == 69) & (byte[1] == 114) & (byte[2] == 105) & (byte[3] == 99))|((byte[0] == 78) & (byte[1] == 101) & (byte[2] == 97) & (byte[3] == 116))):
        #while not ((byte[0] == 69) & (byte[1] == 114) & (byte[2] == 105) & (byte[3] == 99)):
           for i in range(FRAMINGBYTES-1):
               byte[i] = byte[i+1]
           byte[FRAMINGBYTES-1] = ord(ser.read())
        if byte[0] == 69:
           channel = 1
           color = "#b00000"
        else:
           channel = 0
           color = "#00b000"
    
        print byte
    
        print "Getting channel " + str(channel) + " data ..."
        for datacnt in range(NSAMPLES):
           x = datacnt * 2
           y = x + 1
           lo = ord(ser.read())
           hi = ord(ser.read())
           value = (hi << 8) + lo
           imp[channel][datacnt] = (value)
           path[channel][x] = (WINDOW-(value*WINDOW/float(MAX)))
           path[channel][y] = (WINDOW-(datacnt*WINDOW/float(NSAMPLES)))
           if not (datacnt == 0): diff[channel][datacnt] = imp[channel][datacnt - 1] - value
           if diff[channel][datacnt] < 0: diff[channel][datacnt] = 0
    
        print imp[channel]
        print value
    
        for i in range(NSAMPLES*2+2):
            line2d.insert(0,path[channel][i])
    
        canvas.delete("path"+str(channel))
        canvas.create_line(line2d,tag="path"+str(channel),fill=color)
        canvas.itemconfigure("v"+str(channel)+"0",text="CH[%i][0]: %d"% (channel, imp[channel][-1]))
        canvas.itemconfigure("v"+str(channel)+"-",text="dV/dt: %d"%(imp[channel][NSAMPLES-2]-imp[channel][NSAMPLES-1]))
        canvas.itemconfigure("v"+str(channel)+"n",text="CH[%i][-1]: %d"% (channel, imp[channel][0]))
        canvas.itemconfigure("v"+str(channel)+"c",text="C: %d"% (cap[channel]))
        canvas.itemconfigure("v"+str(channel)+"c",text="C: %d"% ((imp[channel][0]-imp[channel][-1])/(imp[channel][NSAMPLES-2]-imp[channel][NSAMPLES-1])))
        canvas.pack()
    
        print "CH: %d, %d, c: %d"% (channel, NSAMPLES-2, imp[channel][NSAMPLES-2])
        print "CH: %d, %d, c: %d"% (channel, NSAMPLES-1, imp[channel][NSAMPLES-1])
        
        print "Writing channel " + str(channel) + " data ..."
    
        grep = re.compile(' |:')
        fNAME = grep.sub("_", str(time.ctime())) + "_CH" + str(channel) + ".csv"
        FILE = open(fNAME, "w")
        FILE.write("Initial Voltage, Final Voltage, dV/dt, Cap\n")
        for i in range(NSAMPLES):
            FILE.write("%u, %u, %u, %u\n" % (line2d[i*2], imp[channel][NSAMPLES-i-1], diff[channel][NSAMPLES-i-1],(imp[channel][0]-imp[channel][-1])/(imp[channel][NSAMPLES-2]-imp[channel][NSAMPLES-1])))
        FILE.close()
    CloseSerial()
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Feb 2004
    Location
    London, England
    Posts
    1,585
    Rep Power
    1373
    The mainloop() call contains the code that receives the windows events and sends them to the correct controls. The reason your program works in Idle is that Idle is also a TkInter application, so mainloop is already running and your application is piggybacking on top of it.

    I don't have the time for in-depth review of your code, but here are some thoughts from aquick scan through...

    1) When I see repeated blocks of code I immediately think "use a loop". Replace

    Code:
    canvas = Canvas(root, width=WINDOW, height=WINDOW, background='white')
    canvas.create_text(.1*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v00",fill="#00b000")
    canvas.create_text(.1*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v10",fill="#b00000")
    
    canvas.create_text(.30*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0n",fill="#00b000")
    canvas.create_text(.30*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1n",fill="#b00000")
    
    canvas.create_text(.50*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0-",fill="#00b000")
    canvas.create_text(.50*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1-",fill="#b00000")
    
    canvas.create_text(.65*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0c",fill="#00b000")
    canvas.create_text(.65*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1c",fill="#b00000")
    with something like this:

    Code:
    canvas = Canvas(root, width=WINDOW, height=WINDOW, background='white')
    for x in (.1, .30, .50, .65):
      for y in (.02, .1):
        canvas.create_text(x*WINDOW,WINDOW-y*WINDOW,text="",font=("Helvetica", 12),tags="v00",fill="#00b000")
    2) Numarray supports comparision of array objects so you could replace

    Code:
        while not (((byte[0] == 69) & (byte[1] == 114) & (byte[2] == 105) & (byte[3] == 99))|((byte[0] == 78) & (byte[1] == 101) & (byte[2] == 97) & (byte[3] == 116))):
    with

    Code:
    end1 = numarray.array([69, 114, 105, 99, ])
    end2 = numarray.array([78,101, 97, 116])
    
        while byte != end1 and byte != end2:
           ...
    
    #or even more pythonically:
    
        while byte not in (end1, end2):
           ...
    This will be more efficient, since the comparisions will be done in a single C function call, rather than several Python bytecodes. IMHO it is also much more readable.

    Dave - The Developers' Coach
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2004
    Location
    Atlanta
    Posts
    5
    Rep Power
    0

    Fantastic! Now, just one more question ...


    I have noticed that my py2exe compiled code is much SLOWER than its py equivalent. Any suggestion as to why? My first guess is something to do with serial IO and Windows XP?? My second guess would simply be my poor coding style.

    By slower I mean the window update via canvas has a slow refresh rate and when I try to grab the window and drag it there is a very perceptible time lag (almost as if the window is frozen).

    At any rate, thanks for all your support. It is now 10PM EST US and I have been at work since 7AM. I never imagined I would get so much excellent support over course of single day.
  10. #6
  11. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    14
    Are there any coding differences between your versions?

    Is there any difference between the ruuning it from Idle and running it using the python command line?

    Py2exe only puts together the byte code with the normal run time.

    All things being equal I can't see why there is a slow down - unless perhaps it is a memory issue. It won't be sharing memory/code with anything else so perhaps the problem is actually a memory paging issue.

    grim
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2004
    Location
    Atlanta
    Posts
    5
    Rep Power
    0
    Is there any difference between the running it from Idle and running it using the python command line?
    As it turns out, there are no differences! I was incorrect to assume py2exe had slowed things down. My recoding to incorporate mainloop() has slowed things down! When I was using a while() loop everything was flowing smoothly. Here is what I have done now, does anyone see any glaring issues? And, can anyone suggest me how to use a CLASS effectively?? I apologize for continuing to post such lengthy code segments, but right now I'm not sharp enough with Python to know how to reduce it to a good testcase.

    Code:
    from Tkinter import *
    import serial
    import numarray
    
    WINDOW = 600
    NSAMPLES = 254
    MAX = 1040
    CHANNELS = 2
    FRAMINGBYTES = 4
    
    
    def OpenSerial():
        global ser
        ser = serial.Serial()
        if ser.isOpen():
            ser.close()
        ser.baudrate = 9600
        ser.port = 'COM1'
        ser.open()
        ser.setDTR()
    
    def CloseSerial():
        try:
            if ser.isOpen():
                ser.close()
        except:
            print "WARNING: Exception raised: ser.close() attempted before ser defined"
        else:
            print "WARNING: ser.close() has issues"
    
    def idle(parent, canvas):
        line2d = []
        path = numarray.zeros((CHANNELS, (NSAMPLES*2 + 2)))
        imp = numarray.zeros((CHANNELS, NSAMPLES))
        diff = numarray.zeros((CHANNELS, NSAMPLES))
        byte = numarray.zeros((FRAMINGBYTES))
        cap = numarray.zeros((CHANNELS))
        print "Finding framing ..."
        while not numarray.sometrue(numarray.equal(byte, frame_ch1)| numarray.equal(byte, frame_ch2)):
           for i in range(FRAMINGBYTES-1):
               byte[i] = byte[i+1]
           byte[FRAMINGBYTES-1] = ord(ser.read())
        if byte[0] == 69:
           channel = 1
           color = "#b00000"
        else:
           channel = 0
           color = "#00b000"
    
        print byte
    
        print "Getting channel " + str(channel) + " data ..."
        for datacnt in range(NSAMPLES):
           x = datacnt * 2
           y = x + 1
           lo = ord(ser.read())
           hi = ord(ser.read())
           value = (hi << 8) + lo
           imp[channel][datacnt] = (value)
           path[channel][x] = (WINDOW-(value*WINDOW/float(MAX)))
           path[channel][y] = (WINDOW-(datacnt*WINDOW/float(NSAMPLES)))
           if not (datacnt == 0): diff[channel][datacnt] = imp[channel][datacnt - 1] - value
           if diff[channel][datacnt] < 0: diff[channel][datacnt] = 0
    
        for i in range(NSAMPLES*2+2):
            line2d.insert(0,path[channel][i])
    
        canvas.delete("path"+str(channel))
        canvas.create_line(line2d,tag="path"+str(channel),fill=color)
        canvas.itemconfigure("v"+str(channel)+"0",text="CH[%i][0]: %d"% (channel, imp[channel][-1]))
        canvas.itemconfigure("v"+str(channel)+"-",text="dV/dt: %d"%(imp[channel][NSAMPLES-2]-imp[channel][NSAMPLES-1]))
        canvas.itemconfigure("v"+str(channel)+"n",text="CH[%i][-1]: %d"% (channel, imp[channel][0]))
        if (imp[channel][NSAMPLES-2] == imp[channel][NSAMPLES-1]):
           canvas.itemconfigure("v"+str(channel)+"c",text="C: INF")
        else:
           canvas.itemconfigure("v"+str(channel)+"c",text="C: %d"% ((imp[channel][0]-imp[channel][-1])/(imp[channel][NSAMPLES-2]-imp[channel][NSAMPLES-1])))
        canvas.pack()
        parent.after_idle(idle, parent, canvas)
    
    
    if (__name__=="__main__"):
    
        frame_ch1 = numarray.array([69, 114, 105, 99])
        frame_ch2 = numarray.array([78, 101, 97, 116])
        print "Opening serial port ..."
        OpenSerial()
        root = Tk()
        root.title('GEN3')
        root.bind('q','exit')
        canvas = Canvas(root, width=WINDOW, height=WINDOW, background='white')
        canvas.create_text(.1*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v00",fill="#00b000")
        canvas.create_text(.1*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v10",fill="#b00000")
        canvas.create_text(.30*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0n",fill="#00b000")
        canvas.create_text(.30*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1n",fill="#b00000")
        canvas.create_text(.50*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0-",fill="#00b000")
        canvas.create_text(.50*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1-",fill="#b00000")
        canvas.create_text(.65*WINDOW,WINDOW-.02*WINDOW,text="",font=("Helvetica", 12),tags="v0c",fill="#00b000")
        canvas.create_text(.65*WINDOW,WINDOW-.1*WINDOW,text="",font=("Helvetica", 12),tags="v1c",fill="#b00000")
        canvas.pack()
        print "Calling main loop ..."
        root.after(100 ,idle, root, canvas)
        root.mainloop()

IMN logo majestic logo threadwatch logo seochat tools logo