python - Tkinter 窗口与线程不能很好地配合

标签 python multithreading python-3.x tkinter python-3.3

我有一个程序,最终将通过串行方式从外部源接收数据,但我正在尝试首先开发显示端。

我有这个“主”模块,它具有模拟数据发送和接收的功能。它更新 Matplotlib 带状图使用的全局变量。所有这些都有效。

#-------------------------------------------------------------------------------
# Name:        BBQData
# Purpose:  Gets the data from the Arduino, and runs the threads.
#-------------------------------------------------------------------------------
import time
import math
import random
from threading import Thread
import my_globals as bbq
import sys
import BBQStripChart as sc
import serial
import BBQControl as control


ser = serial.serial_for_url('loop://', timeout=10)

def simData():
    newTime = time.time()
    if not hasattr(simData, "lastUpdate"):
        simData.lastUpdate = newTime  # it doesn't exist yet, so initialize it
        simData.firstTime = newTime  # it doesn't exist yet, so initialize it
    if newTime > simData.lastUpdate:
        simData.lastUpdate = newTime
        return (140 + 0.05*(simData.lastUpdate - simData.firstTime), \
            145 + 0.022*(simData.lastUpdate - simData.firstTime), \
            210 + random.randrange(-10, 10))
    else:
        return None

def serialDataPump():
    testCtr = 0;
    while not bbq.closing and testCtr<100:
        newData = simData()
        if  newData != None:
            reportStr = "D " + "".join(['{:3.0f} ' for x in newData]) + '\n'
            reportStr = reportStr.format(*newData)
            ser.write(bytes(reportStr, 'ascii'))
            testCtr+=1
            time.sleep(1)
    bbq.closing = True

def serialDataRcv():
    while not bbq.closing:
        line = ser.readline()
        rcvdTime = time.time()
        temps = str(line, 'ascii').split(" ")
        temps = temps[1:-1]
        for j, x in enumerate(temps):
            bbq.temps[j].append(float(x))
            bbq.plotTimes.append(rcvdTime)

def main():
    sendThread = Thread(target = serialDataPump)
    receiveThread = Thread(target = serialDataRcv)
    sendThread.start()
    receiveThread.start()
#    sc.runUI() 
    control.runControl() #blocks until user closes window
    bbq.closing = True
    time.sleep(2)
    exit()


if __name__ == '__main__':
    main()
##    testSerMain()

但是,我想添加一个单独的 tkinter 窗口,其中仅包含最新数据、关闭按钮等。我可以让该窗口出现,并最初显示数据,但没有其他窗口线程运行。 (当我尝试同时运行窗口和绘图时,没有任何效果。)

#-------------------------------------------------------------------------------
# Name:        BBQ Display/Control
# Purpose:      displays current temp data, and control options
#-------------------------------------------------------------------------------

import tkinter as tk
import tkinter.font
import my_globals as bbq
import threading

fontSize = 78

class BBQControl(tk.Tk):
    def __init__(self,parent):
        tk.Tk.__init__(self,parent)
        self.parent = parent
        self.labelFont = tkinter.font.Font(family='Helvetica', size=int(fontSize*0.8))
        self.dataFont = tkinter.font.Font(family='Helvetica', size=fontSize, weight = 'bold')
        self.makeWindow()


    def makeWindow(self):
        self.grid()

        btnClose = tk.Button(self,text=u"Close")
        btnClose.grid(column=1,row=5)

        lblFood = tk.Label(self,anchor=tk.CENTER, text="Food Temps", \
            font = self.labelFont)
        lblFood.grid(column=0,row=0)
        lblPit = tk.Label(self,anchor=tk.CENTER, text="Pit Temps", \
            font = self.labelFont)
        lblPit.grid(column=1,row=0)

        self.food1Temp = tk.StringVar()
        lblFoodTemp1 = tk.Label(self,anchor=tk.E, \
            textvariable=self.food1Temp, font = self.dataFont)
        lblFoodTemp1.grid(column=0,row=1)

        #spawn thread to update temps
        updateThread = threading.Thread(target = self.updateLoop)
        updateThread.start()

    def updateLoop(self):
        self.food1Temp.set(str(bbq.temps[1][-1]))

def runControl():
    app = BBQControl(None)
    app.title('BBQ Display')
    app.after(0, app.updateLoop)
    app.mainloop()
    bbq.closing = True

if __name__ == '__main__':
    runControl()

最佳答案

你的标题很好地总结了这个问题:Tkinter 不能很好地处理线程。这不是问题,这就是答案。

您只能从创建小部件的同一线程访问 tkinter 小部件。如果您想使用线程,则需要非 gui 线程将数据放入队列,并让 gui 线程定期轮询队列。

关于python - Tkinter 窗口与线程不能很好地配合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24459886/

相关文章:

python - 为什么我的 virtualenv 的 pip 在我的 lib/python2.7 目录中列出了包?

python - Numpy 源代码中哪里定义了常量?

java - 执行器服务中的依赖线程 - Java

multithreading - 编译器在多线程程序中使用寄存器

java - 中断未知线程

python - 如何从 pdb 控制台进入任意生成器函数调用?

python - Pandas 子字符串搜索过滤器

python-3.x - 从python中列表的元素中查找字符串中的字符

python - 如何在不保存的情况下持久修改查询集切片

Python自定义排序