跳到主要內容

[Python] 解決UI更新速度太慢,影響執行速度的快速解法 !!

有用過Python開發UI的人應該都知道,Python的UI更新速度很慢,不是一般的慢,是超級慢。慢到時麼程度呢?大概就是你如果寫一個for迴圈更新比如20個Entry元件的文字顯示,會在UI上清楚的看到20個元件依序被刷新的畫面,20個更新完大概要1到2秒吧。

這樣的速度在有些需要即時反映且更新頻繁的案子上就會被客戶打槍了,因此有一個小方法雖然不能改變Python在UI上的更新速度,但至少可以不讓UI更新速度影響工作的進行 (UI它慢就慢,但我程序還是一樣照跑照跳)。

解法就是:
產生一個thread專門負責UI介面上的更新

我們在程式運作一開始,就先產生兩個thread,一個負責程序的進行,一個負責UI的更新。
來看source code:

class EventHandleThread (threading.Thread):
    def __init__(self, fun, name):
        threading.Thread.__init__(self)
        self.name = name
        self.fun = fun
        self.stopped = [0]
    def run(self):
        self.fun(self.name, self.stopped)
        print ("Exiting " + self.name)
    def stop(self):
        self.stopped[0] = 1

#用來傳遞內容的Queue and Lock
m_queueLock = threading.Lock()
m_workQueue = queue.Queue(30)

#UI thread的運作function
def UiHandleLoop(self, name, stopped):
        global m_queueLock , m_workQueue 
        print ('UiHandleLoop - Start')

        while stopped[0] == 0:
            m_queueLock.acquire()
            if not m_workQueue.empty():
                data = m_workQueue.get()
                m_queueLock.release()
                if data['cmd'] == '001':
                 (更新UI)
                elif data['cmd'] == '002':
                 (更新UI)
                elif data['cmd'] == '003':
                 (更新UI)
                elif data['cmd'] == '004':
                 (更新UI)
            else:
                m_queueLock.release()

#主程序thread的運作function
def ProcessHandleLoop(self, name, stopped):
        global m_queueLock , m_workQueue 
        print ('ProcessHandleLoop - Start')
        while stopped[0] == 0:
            #將要顯示到UI的資料放到Queue中
            m_waferQueueLock.acquire()
            m_waferWorkQueue.put({'cmd':'001','data':'testtestest'})
            m_waferQueueLock.release()


在程序一開始,產生執行這兩個thread:


global m_Threads
thread1 = EventHandleThread(self.ProcessHandleLoop, "Thread-ProcessHandle")
m_Threads.append(thread1)
m_Threads[0].start();

thread2 = EventHandleThread(self.UiHandleLoop, "Thread-UiHandleLoop")
m_Threads.append(thread2)
m_Threads[1].start();

在程序要結束前,關掉兩個thread:


global m_Threads
        for i in range(len(m_Threads)):
            print ('stop main thread...')
            try:
                if m_Threads[i].is_alive():
                    m_Threads[i].stop()
                    m_Threads[i].join()
            except:
                print ('main thread except')
                pass

透過thread和Queue、Lock的運用,就可以將UI的更新和程序的運作分開,不讓UI更新拖累主程序了。

留言

這個網誌中的熱門文章

[Python] 管理多個執行緒(thread)的運作與結束

在開發應用程式中,幾乎所有的專案都會用到thread,不同的程式語言有不同˙的叫用方法,但都大同小異。Thread的使用上最重要的不是在產生一個thread,而是如何結束一個thread,或是如何結束好幾個threads,以下介紹在Python中如何叫用並管理一或多個thread: 一般來說,create thread如下: def job(): while 1: print("Child thread:", i) time.sleep(1) #In main code thread = threading.Thread.__init__(job) thread.start() 這樣可以開始一個thread執行job()中的動作,但若job中的迴圈是如上範例的無限迴圈,必須要加上能讓其退出的機制: stopped = 0 def job(): global stopped while stopped == 0: print("Child thread:", i) time.sleep(1) #In main code thread = threading.Thread.__init__(job) thread.start() 這樣在主程序先將stopped設成1,再調用 thread.join() 就可以將thread完整關閉並釋放記憶體空間。 多執行續的處理: 基於這樣的方式,下面是進化版本,創建一個thread專用的class,並同時處理多個thread的執行與結束: class EventHandleThread (threading.Thread): def __init__(self, fun, name): threading.Thread.__init__(self) self.name = name self.fun = fun self.stopped = [0] def run(self): self.fun(self.name, self.stopped) print ("Exiting " ...

[Python] 將程式設定為全螢幕顯示(full screen)和永遠在最前景、最上層(topmost)

這裡以創建一個tkinter 的 Application物件為例 EX: app = Application() app.master.title("WaferCheckApp") app.master.geometry("1100x720") 將UI顯示在最上層: app.master.attributes('-topmost', True) 將UI以全螢幕顯示: app.master.attributes('-fullscreen', True)

[Python] 自己製作文字設定檔config file,動態調整程式設定

在軟體開發中,通常不會知道實際使用行為有那些與原先預期不一樣的情況,這時如果還要針對特定的不同需求改程式是很吃力不討好的事情。所以我們常常會需要能夠動態調整一些設定,以應付不同的使用情況。 下面以Python提一個簡單的方法來動態調整程式設定: 建立一個function,在程式初始化時呼叫: EX: def initialSetting():         try:             currentDirectory = os.getcwd()             filePath = '%s\\ ToolSet.cfg ' % (currentDirectory)             file = open(filePath, 'r')             for line in file.readlines():                 if line.find("Value1") == 0:                     str1 = int(line[7:-1])                 elif line.find(" Value2 ") == 0:                      str2  = int(line[7:-1])                 elif line.find(" Value3 ")...