2014-03-19 33 views
1

我有一個簡單的項目,需要從我的電位器和Arduino中讀取串行數據。當我得到轉換的讀數並且應該改變空白窗口的顏色後。Tkinter/Python和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() 
+0

您是否收到錯誤?如果我將系列調用註釋掉並將「顏色」的值設爲「紅色」,它對我來說工作正常。如果我不得不猜測,我會說'顏色'應該給你一個「未知顏色名稱」的錯誤,你需要將你的顏色名稱格式化爲Tkinter可接受的字符串。 – atlasologist

+0

但是,我確實得到了關於顏色的一些錯誤,我認爲這只是由於與串行時間有關。在我發現如何將RGB顏色轉換爲Tkinter接受的HTML顏色後,顏色正常工作。 – mECH

回答

1

我最近剛剛做了這個來監測串口設備的輸入。您需要能夠在準備好時接收串行數據,並保持Tk事件循環運行。您可以使用工作線程讀取串行數據並將輸入發佈到UI線程以供顯示,也可以使用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()) 
+0

感謝@patthoyts的回覆,我會試一試。 我也發現這[網站](http://robotic-controls.com/learn/python-guis/tkinter-serial)我相信這表明它可能是一個問題**阻止**串行正在做。這從更新中停止了Tkinter循環;或者我認爲。 – mECH

+0

正確。你不能在GUI程序中容納事件,所以你應該把事情安排成面向事件的方式,就像你試圖獲得對你的arduino引發中斷的輸入一樣。扭曲的框架允許您註冊各種中斷源(串行數據就緒,Windows事件,套接字事件)並適當地分派它們。所有事件處理程序應該及時返回,如果還有更多工作要做,請使用狀態引擎併發布其他事件。這可以讓工作與其他事件交錯,而不會阻塞太久。 – patthoyts