我有一个简单的项目,可从电位计和Arduino读取串行数据。获得转换后的读数后,该读数应该会更改空白窗口的颜色。

由于某些原因,我无法更新窗口,而且我真的不熟悉Tkinter。感谢您的任何投入。

import Tkinter
import serial

ser = serial.Serial("/dev/ttyACM0", 9600, timeout = 2)
def update():
    while 1:
        line = ser.readline()
        color = "#%02x%02x%02x" %(000, 000, int(line))
        return color

root = Tkinter.Tk()
root.geometry("500x500")
root.configure(background = update())
root.mainloop()

最佳答案

我最近只是这样做来监视来自串行设备的输入。准备就绪后,您需要能够接收串行数据,并保持Tk事件循环运行。您可以使用辅助线程读取串行数据并将输入发布到UI线程以进行显示,也可以使用Twisted框架。在我的情况下,我使用twisted来避免从串行端口进行任何阻塞读取,并仅使用画布线将值绘制为简单的线图。

#!/usr/bin/python
import sys
from Tkinter import *
from ttk import *
from twisted.internet import tksupport, reactor
from twisted.internet.serialport import SerialPort
from twisted.protocols import basic

class DeviceProtocol(basic.LineReceiver):
    #delimiter = "\r\n" # default delimiter is crlf
    def __init__(self, callback):
        self.callback = callback
    def lineReceived(self, data):
        self.callback.OnDataReceived(data)

class MainWindow(Frame):
    def __init__(self, parent, title):
        self.data = [(n,1) for n in range(100)]
        self.sample = len(self.data)
        Frame.__init__(self, parent)
        parent.wm_withdraw()
        parent.wm_title(title)
        self.CreateUI()
        self.grid(sticky = (N,S,W,E))
        parent.wm_protocol("WM_DELETE_WINDOW", self.onDestroy)
        parent.grid_rowconfigure(0, weight = 1)
        parent.grid_columnconfigure(0, weight = 1)
        parent.wm_deiconify()

    def CreateUI(self):
        canvas = Canvas(self, background="white")
        canvas.create_line((0, 0, 1, 1), tag='Plot', fill='red', smooth=True)
        canvas.grid(sticky = (N,S,W,E))
        self.canvas = canvas
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

    def onDestroy(self):
        reactor.stop() # required to cleanly shutdown twisted event loop

    def Monitor(self, port, baudrate = 9600):
        self.serial = SerialPort(DeviceProtocol(self),
                                 port, reactor, baudrate=baudrate)

    def OnDataReceived(self, data):
        print data
        for v in data.split():
            self.data.append((self.sample, int(v)))
        self.sample += 1
        if len(self.data) > 100:
            self.data = self.data[-100:]
        self.after_idle(self.OnUpdatePlot)

    def OnUpdatePlot(self):
        width = self.canvas.winfo_width()
        height = self.canvas.winfo_height()
        xS,yS = self.data[0]
        xE,yE = self.data[-1]
        coords = []
        fx = width / (xE - xS)
        fy = height / 100 # y values are 0 < y < 100
        for (x,y) in self.data:
            coords.append(fx * (x - xS))
            coords.append(fy * (100 - y))
        self.canvas.coords('Plot', *coords)

def main(argv = None):
    if argv is None:
        argv = sys.argv
    if len(argv) != 2:
        print "usage: plot_serial <serialport>"
        return 1
    root = Tk()
    tksupport.install(root) # register the Tk event loop with twisted
    main = MainWindow(root, "Plot serial data")
    main.Monitor(argv[1])
    reactor.run() # use twisted instead of root.mainloop()
    return 0

if __name__ == '__main__':
    sys.exit(main())

09-27 08:17