顯示具有 wxpython 標籤的文章。 顯示所有文章
顯示具有 wxpython 標籤的文章。 顯示所有文章

2014年10月24日 星期五

wxpython thread

最近寫python需要程式一直在迴圈裡面跑
如果用while true的話會當機,沒有辦法按下停止鍵
看了下面兩個非常好的reference來練習一下怎麼寫wxpython thread

Reference :


wxpython下有三個最安全的方式來寫thread
wx.PostEvent
wx.CallAfter
wx.CallLater

wx.PostEvent是最低階的方式,那那那那就先用它來寫寫看吧!!!!!

這個練習是使用者按下start,表示開始執行另一個thread,然後右邊會反覆出現紅色與綠色的按鍵還有說明,最下面顯示這個迴圈已經被跑了幾次,每次跑的時候先從txt中讀出上次已經跑的次數,然後再繼續累加(所以要先在同一個資料夾下面準備一個test_cnt.txt的檔案),順便練習讀寫file還有把file放在textctrl中顯示,按下stop則停止這個thread

wxglade建立好視窗之後要加入 from threading import Thread


這邊寫thread最主要的關鍵就是EVT_RESULT_ID


wx.frame中再用ResultEvent來跟thread溝通



wx.Frame中如果使用者按下start,則會連到thread class來執行run function


run function,先把txt中的值讀出來,int()string轉成int來累加,利用wx.PostEvent(self._notify_window,ResultEvent("Green")) 來告訴wx.Frame classGUI上要做甚麼變化,如果使用者按下STOP則會傳到abort,然後傳到run中停止執行緒




test.py
import wx

# begin wxGlade: dependencies
import gettext
# end wxGlade

# begin wxGlade: extracode
# end wxGlade

############### Definitions ###############
from threading import Thread
import time
import os
###########################################

############### Threads #######################

# Define notification event for thread completion
EVT_RESULT_ID = wx.NewId()

def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)

class ResultEvent(wx.PyEvent):
    """Simple event to carry arbitrary result data."""
    def __init__(self, data):
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESULT_ID)
        self.data = data

class WorkerThread(Thread):
    def __init__(self,notify_window):
        Thread.__init__(self)
        self._notify_window = notify_window
        self._want_abort = 0
        self.start()

    def run(self):
        
        print("Read test_cnt.txt ")
        fread = file('test_cnt.txt','r')
        while True:           
            text = fread.readline()
            if len(text) == 0:
                break;
            print text
            cnt = int(text)
        fread.close()

        while True:
            time.sleep(1)
            if self._want_abort:
                wx.PostEvent(self._notify_window,ResultEvent(None))
                return

            wx.PostEvent(self._notify_window,ResultEvent("Green"))
            time.sleep(1)
            wx.PostEvent(self._notify_window,ResultEvent("Red"))
            time.sleep(1)
            fwrite = file('test_cnt.txt','w')
            cnt += 1                    
            fwrite.write("%s"%cnt)
            fwrite.close()
            time.sleep(1)
            wx.PostEvent(self._notify_window,ResultEvent("cnt"))

            
    def abort(self):
        self._want_abort = 1
        
################################################

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.window_1 = wx.SplitterWindow(self, wx.ID_ANY, style=wx.SP_3D | wx.SP_BORDER)
        self.window_1_pane_1 = wx.Panel(self.window_1, wx.ID_ANY)
        self.start = wx.Button(self.window_1_pane_1, wx.ID_ANY, _("Start"))
        self.stop = wx.Button(self.window_1_pane_1, wx.ID_ANY, _("Stop"))
        self.window_1_pane_2 = wx.Panel(self.window_1, wx.ID_ANY)
        self.light = wx.Button(self.window_1_pane_2, wx.ID_ANY, _(""))
        self.status = wx.StaticText(self.window_1_pane_2, wx.ID_ANY, _("Status\n"))
        self.cnt = wx.TextCtrl(self.window_1_pane_2, wx.ID_ANY, "")

        self.__set_properties()
        self.__do_layout()
        # end wxGlade

        ################# init function ##################
        rd_log = open(os.path.join('', 'test_cnt.txt'), 'r')
        self.cnt.SetValue(rd_log.read())
        rd_log.close()

        ################# function binding ###############
        self.Bind(wx.EVT_BUTTON,self.EVTSTART,self.start)
        self.Bind(wx.EVT_BUTTON,self.EVTSTOP,self.stop)
        EVT_RESULT(self,self.updateDisplay)
        self.worker = None
        ###################################################


        ################# function binding ###############
    def EVTSTART(self,event):
        print("Start testing")
        self.worker = WorkerThread(self)
        

    def EVTSTOP(self,event):
        print("End testing")
        self.worker.abort()

    def updateDisplay(self,event):
        if event.data is "Green":
            self.light.SetBackgroundColour(wx.Colour(0, 255, 127))
            self.status.SetLabel('Green')

        if event.data is "Red":
            self.light.SetBackgroundColour(wx.Colour(255, 0, 61))
            self.status.SetLabel('Red')

        if event.data is "cnt":
            rd_log = open(os.path.join('', 'test_cnt.txt'), 'r')
            self.cnt.SetValue(rd_log.read())
            rd_log.close()
        ###################################################

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle(_("Test"))
        self.start.SetMinSize((100, 80))
        self.stop.SetMinSize((100, 80))
        self.window_1_pane_1.SetMinSize((192, 257))
        self.light.SetMinSize((100, 40))
        self.window_1_pane_2.SetMinSize((188, 257))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_5 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.BoxSizer(wx.VERTICAL)
        sizer_4.Add(self.start, 0, wx.LEFT | wx.TOP | wx.BOTTOM, 20)
        sizer_4.Add(self.stop, 0, wx.LEFT | wx.TOP, 20)
        sizer_3.Add(sizer_4, 1, wx.EXPAND, 0)
        self.window_1_pane_1.SetSizer(sizer_3)
        sizer_5.Add(self.light, 0, wx.LEFT | wx.TOP, 40)
        sizer_5.Add(self.status, 0, wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 40)
        sizer_5.Add(self.cnt, 0, wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 30)
        self.window_1_pane_2.SetSizer(sizer_5)
        self.window_1.SplitVertically(self.window_1_pane_1, self.window_1_pane_2)
        sizer_2.Add(self.window_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_2)
        sizer_2.Fit(self)
        self.Layout()
        # end wxGlade

# end of class MyFrame
if __name__ == "__main__":
    gettext.install("app") # replace with the appropriate catalog name

    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    Test = MyFrame(None, wx.ID_ANY, "")
    app.SetTopWindow(Test)
    Test.Show()
    app.MainLoop()



如果用callafter則如下
import wx

# begin wxGlade: dependencies
import gettext
# end wxGlade

# begin wxGlade: extracode
# end wxGlade

############### Definitions ###############
from threading import Thread
from wx.lib.pubsub import Publisher
import time
import os
###########################################

############### Threads #######################

class WorkerThread(Thread):
    def __init__(self,notify_window):      
        Thread.__init__(self)
        self._notify_window = notify_window
        self._want_abort = 0
        self.start()

    def run(self):
        
        print("Read test_cnt.txt ")
        fread = file('test_cnt.txt','r')
        while True:           
            text = fread.readline()
            if len(text) == 0:
                break;
            print text
            cnt = int(text)
        fread.close()

        while True:
            time.sleep(1)
            if self._want_abort:
                wx.CallAfter(Publisher().sendMessage, "update", None)
                return
            wx.CallAfter(Publisher().sendMessage, "update", "Green")
            time.sleep(1)
            wx.CallAfter(Publisher().sendMessage, "update", "Red")
            time.sleep(1)
            fwrite = file('test_cnt.txt','w')
            cnt += 1                    
            fwrite.write("%s"%cnt)
            fwrite.close()
            time.sleep(1)
            wx.CallAfter(Publisher().sendMessage, "update", "cnt")
    
    def abort(self):
        self._want_abort = 1

################################################

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.window_1 = wx.SplitterWindow(self, wx.ID_ANY, style=wx.SP_3D | wx.SP_BORDER)
        self.window_1_pane_1 = wx.Panel(self.window_1, wx.ID_ANY)
        self.start = wx.Button(self.window_1_pane_1, wx.ID_ANY, _("Start"))
        self.stop = wx.Button(self.window_1_pane_1, wx.ID_ANY, _("Stop"))
        self.window_1_pane_2 = wx.Panel(self.window_1, wx.ID_ANY)
        self.light = wx.Button(self.window_1_pane_2, wx.ID_ANY, _(""))
        self.status = wx.StaticText(self.window_1_pane_2, wx.ID_ANY, _("Status\n"))
        self.cnt = wx.TextCtrl(self.window_1_pane_2, wx.ID_ANY, "")

        self.__set_properties()
        self.__do_layout()
        # end wxGlade

        ################# init function ##################
        rd_log = open(os.path.join('', 'test_cnt.txt'), 'r')
        self.cnt.SetValue(rd_log.read())
        rd_log.close()

        ################# function binding ###############
        self.Bind(wx.EVT_BUTTON,self.EVTSTART,self.start)
        self.Bind(wx.EVT_BUTTON,self.EVTSTOP,self.stop)
        Publisher().subscribe(self.updateDisplay, "update")
        self.worker = None
        ###################################################


        ################# function binding ###############
    def EVTSTART(self,event):
        print("Start testing")
        self.worker = WorkerThread(self)
        

    def EVTSTOP(self,event):
        print("End testing")
        self.worker.abort()

    def updateDisplay(self,event):
        if event.data is "Green":
            self.light.SetBackgroundColour(wx.Colour(0, 255, 127))
            self.status.SetLabel('Green')

        if event.data is "Red":
            self.light.SetBackgroundColour(wx.Colour(255, 0, 61))
            self.status.SetLabel('Red')

        if event.data is "cnt":
            rd_log = open(os.path.join('', 'test_cnt.txt'), 'r')
            self.cnt.SetValue(rd_log.read())
            rd_log.close()
        ###################################################

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle(_("Test"))
        self.start.SetMinSize((100, 80))
        self.stop.SetMinSize((100, 80))
        self.window_1_pane_1.SetMinSize((192, 257))
        self.light.SetMinSize((100, 40))
        self.window_1_pane_2.SetMinSize((188, 257))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_5 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.BoxSizer(wx.VERTICAL)
        sizer_4.Add(self.start, 0, wx.LEFT | wx.TOP | wx.BOTTOM, 20)
        sizer_4.Add(self.stop, 0, wx.LEFT | wx.TOP, 20)
        sizer_3.Add(sizer_4, 1, wx.EXPAND, 0)
        self.window_1_pane_1.SetSizer(sizer_3)
        sizer_5.Add(self.light, 0, wx.LEFT | wx.TOP, 40)
        sizer_5.Add(self.status, 0, wx.LEFT | wx.RIGHT | wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 40)
        sizer_5.Add(self.cnt, 0, wx.TOP | wx.ALIGN_CENTER_HORIZONTAL, 30)
        self.window_1_pane_2.SetSizer(sizer_5)
        self.window_1.SplitVertically(self.window_1_pane_1, self.window_1_pane_2)
        sizer_2.Add(self.window_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_2)
        sizer_2.Fit(self)
        self.Layout()
        # end wxGlade

# end of class MyFrame
if __name__ == "__main__":
    gettext.install("app") # replace with the appropriate catalog name

    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    Test = MyFrame(None, wx.ID_ANY, "")
    app.SetTopWindow(Test)
    Test.Show()
    app.MainLoop()



2014年10月17日 星期五

Install wxpython on raspberry pi

Reference:
http://wiki.wxpython.org/InstallingOnUbuntuOrDebian

sudo apt-get update

sudo apt-get install python-wxgtk2.8 python-wxtools wx2.8-i18n libwxgtk2.8-dev libgtk2.0-dev



restart raspberry pi

2014年5月16日 星期五

Pyserial Wxpython with microblaze

target ML605,Python 2.6

在上篇建立好microblaze以address 0x7c600000 來控制LED燈
並在SDK裡面用UART來收集連續的address與data資料
所以可以用pyserial來代替tera term,並用wxGlade來建立一個超簡單的GUI好讓使用者使用

有關pyserial的wxpython範例可以在這邊看到
http://pyserial.sourceforge.net/examples.html#wxpython-examples
我會用到wxTerminal.py與wxSerialConfigDialog.py

主程式是wxTerminal, 它其實就是一個python 版的tera term

我先用wxGlade畫一個簡單的GUI,只有一個text與button
text用來寫address的data,button按下時直接送入address 0x7c600000與使用者寫入的資料
在這個例子寫入資料0x00000001 讓LED燈開始閃爍,0x00000000則讓它停止閃爍

打開wxGlade新增一個Frame,選wxFrame



加入一個boxsizer,點了boxsizer之後再點Frame的地方就會出現對話方塊,slots改成2,讓它把畫面分成兩半,使用者就可以輸入不同的功能方塊



在左邊的boxsizer加入一個textctrl 


把名子改成value,之後如果要做比較大的GUI,最好把名子改成跟所需的功能相關,這樣程式寫起來比較省力,知道自己在寫哪一塊,改完後在右邊的boxsizer再加入一個button,同樣把name改成Set


如果要改在gui上顯現的button名子要改widget裡面的label,我將它也設成Set


之後按application 可以看到產生程式的對話視窗,python與選擇輸出位置與檔案名稱,generate code



產生code以後,必須要用bind函式把setvalue定義它們的型態與自身的函式
在寫它們本身的函式,這邊在EvtSet中蒐集由EvtVal中輸入的資料並轉成hex,
EvtVal則是當使用者輸入超過8 個數字則出件警告訊息

在把pyserial整合進來,把需要的函式放進來

import 需要的module
import wxSerialConfigDialog
import serial
import threading
from time import sleep

完整的test.py為

#!/usr/bin/env python
# -*- coding: CP1252 -*-
#
# generated by wxGlade 0.6.8 (standalone edition) on Thu May 15 15:13:20 2014
#

import wx
import wxSerialConfigDialog
import serial
import threading
from time import sleep
# begin wxGlade: dependencies
import gettext
# end wxGlade

# begin wxGlade: extracode
# end wxGlade
#----------------------------------------------------------------------
SERIALRX = wx.NewEventType()
# bind to serial data receive events
EVT_SERIALRX = wx.PyEventBinder(SERIALRX, 0)

class SerialRxEvent(wx.PyCommandEvent):
    eventType = SERIALRX
    def __init__(self, windowID, data):
        wx.PyCommandEvent.__init__(self, self.eventType, windowID)
        self.data = data

    def Clone(self):
        self.__class__(self.GetId(), self.data)
#----------------------------------------------------------------------
LED_ADDR          = '7c600000'        
NEWLINE_CR      = 0
NEWLINE_LF      = 1
NEWLINE_CRLF    = 2        
        
LED  = int(0x00000000)
#----------------------------------------------------------------------
class TerminalSetup:
    """Placeholder for various terminal settings. Used to pass the
       options to the TerminalSettingsDialog."""
    def __init__(self):
        self.echo = False
        self.unprintable = False
        self.newline = NEWLINE_CRLF

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        self.serial = serial.Serial()
        self.serial.timeout = 0.5
        self.settings = TerminalSetup()
        self.thread = None
        self.alive = threading.Event()
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.Value = wx.TextCtrl(self, wx.ID_ANY, "")
        self.Set = wx.Button(self, wx.ID_ANY, _("Set"))

        self.__set_properties()
        self.__do_layout()
        # end wxGlade
        
        #-------------------------------------------------
        self.OnPortSettings(None)
        if not self.alive.isSet():
            self.Close()
        self.Bind(wx.EVT_BUTTON, self.EvtSet, self.Set)
        self.Bind(wx.EVT_TEXT,self.EVTVal,self.Value)
        
        # function 
    def Write(self, addr, data):
        writein = str(data)        
        if len(writein) == 3:
            data7 = writein[2]
            data6 = '0'
            data5 = '0'
            data4 = '0'
            data3 = '0'
            data2 = '0'
            data1 = '0'
            data0 = '0'
        elif len(writein) == 4:
            data7 = writein[3]
            data6 = writein[2]
            data5 = '0'
            data4 = '0'
            data3 = '0'
            data2 = '0'
            data1 = '0'
            data0 = '0'
        elif len(writein) == 5:
            data7 = writein[4]
            data6 = writein[3]
            data5 = writein[2]
            data4 = '0'
            data3 = '0'
            data2 = '0'
            data1 = '0'
            data0 = '0'
        elif len(writein) == 6:
            data7 = writein[5]
            data6 = writein[4]
            data5 = writein[3]
            data4 = writein[2]
            data3 = '0'
            data2 = '0'
            data1 = '0'
            data0 = '0'
        elif len(writein) == 7:
            data7 = writein[6]
            data6 = writein[5]
            data5 = writein[4]
            data4 = writein[3]
            data3 = writein[2]
            data2 = '0'
            data1 = '0'
            data0 = '0'
        elif len(writein) == 8:
            data7 = writein[7]
            data6 = writein[6]
            data5 = writein[5]
            data4 = writein[4]
            data3 = writein[3]
            data2 = writein[2]
            data1 = '0'
            data0 = '0'
        elif len(writein) == 9:
            data7 = writein[8]
            data6 = writein[7]
            data5 = writein[6]
            data4 = writein[5]
            data3 = writein[4]
            data2 = writein[3]
            data1 = writein[2]
            data0 = '0'
        elif len(writein) == 10:
            data7 = writein[9]
            data6 = writein[8]
            data5 = writein[7]
            data4 = writein[6]
            data3 = writein[5]
            data2 = writein[4]
            data1 = writein[3]
            data0 = writein[2]
        else:
            data7 = writein[9]
            data6 = writein[8]
            data5 = writein[7]
            data4 = writein[6]
            data3 = writein[5]
            data2 = writein[4]
            data1 = writein[3]
            data0 = writein[2]
        
         
        self.serial.write(addr)
        self.serial.write(data0)
        self.serial.write(data1)
        self.serial.write(data2)
        self.serial.write(data3)
        self.serial.write(data4)
        self.serial.write(data5)
        self.serial.write(data6)
        self.serial.write(data7)

    def EvtSet(self,event):        
        GetValue = hex(int(self.Value.GetValue(),16))        
        self.Write(LED_ADDR,GetValue)
        #self.Write('7c600000','00000000')
        
    def EVTVal(self,event):
        length = len(event.GetString())
        if length > 8:
            alert_dialog = wx.MessageDialog(None,u"Bits Overflow",u"Error",wx.OK             | wx.ICON_ERROR)
            if alert_dialog.ShowModal() == wx.ID_OK:
                alert_dialog.Destroy()
        

    def StartThread(self):
        """Start the receiver thread"""        
        self.thread = threading.Thread(target=self.ComPortThread)
        self.thread.setDaemon(1)
        self.alive.set()
        self.thread.start()

    def StopThread(self):
        """Stop the receiver thread, wait util it's finished."""
        if self.thread is not None:
            self.alive.clear()          #clear alive event for thread
            self.thread.join()          #wait until thread has finished
            self.thread = None

    def OnTermSettings(self, event):
        """Menu point Terminal Settings. Show the settings dialog
           with the current terminal settings"""
        dialog = TerminalSettingsDialog(None, -1, "", settings=self.settings)
        result = dialog.ShowModal()
        dialog.Destroy()
        
    def OnPortSettings(self, event=None):
        """Show the portsettings dialog. The reader thread is stopped for the
           settings change."""
        if event is not None:           #will be none when called on startup
            self.StopThread()
            self.serial.close()
        ok = False
        while not ok:
            dialog_serial_cfg = wxSerialConfigDialog.SerialConfigDialog(None, -1,            "",
            show=wxSerialConfigDialog.SHOW_BAUDRATE|wxSerialConfigDialog.SHOW_FOR             MAT|wxSerialConfigDialog.SHOW_FLOW,
                serial=self.serial
            )
            result = dialog_serial_cfg.ShowModal()
            dialog_serial_cfg.Destroy()
            #open port if not called on startup, open it on startup and OK too
            if result == wx.ID_OK or event is not None:
                try:
                    self.serial.open()
                except serial.SerialException, e:
                    dlg = wx.MessageDialog(None, str(e), "Serial Port Error", wx.                     OK | wx.ICON_ERROR)
                    dlg.ShowModal()
                    dlg.Destroy()
                else:
                    self.StartThread()
                    self.SetTitle("Serial Terminal on %s [%s, %s%s%s%s%s]" % (
                        self.serial.portstr,
                        self.serial.baudrate,
                        self.serial.bytesize,
                        self.serial.parity,
                        self.serial.stopbits,
                        self.serial.rtscts and ' RTS/CTS' or '',
                        self.serial.xonxoff and ' Xon/Xoff' or '',
                        )
                    )
                    ok = True
            else:
                #on startup, dialog aborted
                self.alive.clear()
                ok = True
           
    def OnKey(self, event):
        """Key event handler. if the key is in the ASCII range, write it to the s           erial port.
           Newline handling and local echo is also done here."""
        code = event.GetKeyCode()
        if code < 256:                          #is it printable?
            if code == 13:                      #is it a newline? (check for CR w                                                 hich is the RETURN key)
                if self.settings.echo:          #do echo if needed
                    self.COM_STATUS.AppendText('\n')
                if self.settings.newline == NEWLINE_CR:
                    self.serial.write('\r')     #send CR
                elif self.settings.newline == NEWLINE_LF:
                    self.serial.write('\n')     #send LF
                elif self.settings.newline == NEWLINE_CRLF:
                    self.serial.write('\r\n')   #send CR+LF
            else:
                char = chr(code)
                if self.settings.echo:          #do echo if needed
                    self.COM_STATUS.WriteText(char)
                self.serial.write(char)         #send the charcater
        else:
            print "Extra Key:", code

    def OnSerialRead(self, event):
        """Handle input from the serial port."""
        text = event.data
        if self.settings.unprintable:
            text = ''.join([(c >= ' ') and c or '<%d>' % ord(c)  for c in text])
        self.COM_STATUS.AppendText(text)
        
    def ComPortThread(self):
        """Thread that handles the incomming traffic. Does the basic input
           transformation (newlines) and generates an SerialRxEvent"""
        while self.alive.isSet():               #loop while alive event is true
            text = self.serial.read(1)          #read one, with timout
            if text:                            #check if not timeout
                n = self.serial.inWaiting()     #look if there is more to read
                if n:
                    text = text + self.serial.read(n) #get it
                #newline transformation
                if self.settings.newline == NEWLINE_CR:
                    text = text.replace('\r', '\n')
                elif self.settings.newline == NEWLINE_LF:
                    pass
                elif self.settings.newline == NEWLINE_CRLF:
                    text = text.replace('\r\n', '\n')
                event = SerialRxEvent(self.GetId(), text)
                self.GetEventHandler().AddPendingEvent(event)
                #~ self.OnSerialRead(text)         #output text in window               
 #----------------------------------------------------------------------
    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle(_("Test"))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_2.Add(self.Value, 0, 0, 0)
        sizer_2.Add(self.Set, 0, 0, 0)
        sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()
        # end wxGlade

# end of class MyFrame
if __name__ == "__main__":
    gettext.install("app") # replace with the appropriate catalog name
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    frame_1 = MyFrame(None, -1, "")
    app.SetTopWindow(frame_1)
    frame_1.Show()
    app.MainLoop()
紅色的程式是從wxTerminal.py整合過來,綠色的是自己加上去的
函式write是為了如果使用者沒有完整輸入8位數,則自動補零
所以在測試的時候,即使對話框只輸入1,LED燈也是會閃爍
程式測試成功以後,把它轉成exe
寫一個py2exesetup.py,windows=['test.py'] 裡填入要轉換的py
from distutils.core import setup   
import py2exe  
setup(  
      windows=['test.py'],   
      options = {           
      "py2exe":  
       {"dll_excludes":["MSVCP90.dll"]}  
       }  
) 
把所有會引用到的py檔與py2exesetup.py複製到c下面的python26
然後打開cmd進入python26command
python py2exesetup.py install 
python py2exesetup.py py2exe
就會在同一層的資料夾中產生一個新的disk資料夾
裡面的exe檔就是轉換出來的小寶貝拉XD