2012-05-13 13 views
5

पर आधारित टिंकर विंडो को गतिशील रूप से अपडेट करना मैं एक प्रोग्राम लिखने की कोशिश कर रहा हूं जो एक सीरियल पोर्ट कनेक्शन से डेटा प्राप्त करता है और उस डेटा के आधार पर वास्तविक समय में टिंकर विंडो को स्वचालित रूप से अद्यतन करता है।सीरियल डेटा

serialdata = [] 
data = True 

class SensorThread(threading.Thread): 
    def run(self): 
     serial = serial.Serial('dev/tty.usbmodem1d11', 9600) 
     try: 
      while True: 
       serialdata.append(serial.readline()) 
     except KeyboardInterrupt: 
      serial.close() 
      exit() 

class GuiThread(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 
     self.root = Tk() 
     self.lbl = Label(self.root, text="") 

    def run(self): 
     self.lbl(pack) 
     self.lbl.after(1000, self.updateGUI) 
     self.root.mainloop() 

    def updateGUI(self): 
     msg = "Data is True" if data else "Data is False" 
     self.lbl["text"] = msg 
     self.root.update() 
     self.lbl.after(1000, self.updateGUI) 

if __name == "__main__": 
    SensorThread().start() 
    GuiThread().start() 

    try: 
     while True: 
      # A bunch of analysis that sets either data = True or data = False based on serialdata 
    except KeyboardInterrupt: 
     exit() 

चल रहा है यह मुझे इस त्रुटि देता है:

Exception in thread Thread-2: Traceback (most recent call last): File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py", line 522, in __bootstrap_inner self.run() File "analysis.py", line 52, in run self.lbl1.pack() File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-tk/Tkinter.py", line 1764, in pack_configure + self._options(cnf, kw)) RuntimeError: main thread is not in main loop

मैं खिड़की है कि समय-समय पर मुख्य थ्रेड से मौजूदा डेटा हो जाता है और खिड़की अपडेट हो जाता है, इस तरह के लिए एक अलग थ्रेड बनाने की कोशिश की

जब मैं इस त्रुटि को Google करता हूं, तो मुझे ज्यादातर पोस्ट मिलती हैं जहां लोग खिड़की से दो अलग-अलग धागे से बातचीत करने की कोशिश कर रहे हैं, लेकिन मुझे नहीं लगता कि मैं ऐसा कर रहा हूं। कोई विचार? बहुत बहुत धन्यवाद!

+1

क्या आपने टीके भाग को थ्रेड में नहीं चलाने का प्रयास किया था? मैं सिर्फ थ्रेड में सीरियल पोर्ट सामान चलाता हूं और टीके सामान मुख्य प्रक्रिया में रह सकता है। मुझे संदेह है कि काम कर सकता है ... –

+0

सीरियल पोर्ट डेटा और डेटा विश्लेषण लूप के लिए एक और थ्रेड प्राप्त करने के लिए एक थ्रेड की तरह? मैं उसे एक शॉट दूंगा। – user1363445

उत्तर

6

टीके गुई को थ्रेड से न चलाएं - इसे मुख्य प्रक्रिया से चलाएं। मैं कुछ है कि सिद्धांत

from time import sleep 
import threading 
from Tkinter import * 

serialdata = [] 
data = True 

class SensorThread(threading.Thread): 
    def run(self): 
     try: 
      i = 0 
      while True: 
       serialdata.append("Hello %d" % i) 
       i += 1 
       sleep(1) 
     except KeyboardInterrupt: 
      exit() 

class Gui(object): 
    def __init__(self): 
     self.root = Tk() 
     self.lbl = Label(self.root, text="") 
     self.updateGUI() 
     self.readSensor() 

    def run(self): 
     self.lbl.pack() 
     self.lbl.after(1000, self.updateGUI) 
     self.root.mainloop() 

    def updateGUI(self): 
     msg = "Data is True" if data else "Data is False" 
     self.lbl["text"] = msg 
     self.root.update() 
     self.lbl.after(1000, self.updateGUI) 

    def readSensor(self): 
     self.lbl["text"] = serialdata[-1] 
     self.root.update() 
     self.root.after(527, self.readSensor) 

if __name__ == "__main__": 
    SensorThread().start() 
    Gui().run() 
+1

आपको एक साधारण सूची चर का उपयोग करने के बजाय धागे के बीच संवाद करने के लिए थ्रेड-सुरक्षित 'कतार' ऑब्जेक्ट का उपयोग करना चाहिए। –

+1

यह बेहतर होगा हाँ, लेकिन मेरा उद्देश्य ओपी को समस्या का समाधान दिखाना था, उन्हें आईपीसी तंत्र को पियान नहीं सिखाया गया ;-) –

1

आप मुख्य थ्रेड में जीयूआई रखा, और सीरियल पोर्ट मतदान पर एक अलग थ्रेड उपयोग करने की आवश्यकता को दर्शाता है में अपने उदाहरण मसला। जब आप सीरियल पोर्ट के डेटा को पढ़ते हैं तो आप उसे कतार ऑब्जेक्ट पर दबा सकते हैं।

मुख्य जीयूआई थ्रेड में आप मतदान को निर्धारित करने के लिए after का उपयोग करके समय-समय पर कतार की जांच के लिए मतदान सेट अप कर सकते हैं। कतार को निकालने वाले फ़ंक्शन को कॉल करें और फिर एक अनंत लूप को प्रभावी ढंग से अनुकरण करने के लिए after के साथ स्वयं को कॉल करें।

यदि सेंसर से आने वाला डेटा काफी धीमी गति से आता है, और आप अवरुद्ध किए बिना सीरियल पोर्ट को मतदान कर सकते हैं, तो आप इसे मुख्य धागे में कर सकते हैं - कतार से धक्का और खींचने के बजाय, आपका मुख्य धागा देख सकता है कि क्या डेटा उपलब्ध है और अगर वहां है तो इसे पढ़ें। आप केवल तभी ऐसा कर सकते हैं जब बिना अवरुद्ध किए पढ़ना संभव हो, अन्यथा आपका जीयूआई डेटा के इंतजार के दौरान फ्रीज हो जाएगा।

उदाहरण के लिए, आप इसे इस तरह से काम कर सकता है:

def poll_serial_port(self): 
    if serial.has_data(): 
     data = serial.readline() 
     self.lbl.configure(text=data) 
    self.after(100, self.poll_serial_port) 

ऊपर सीरियल पोर्ट प्रति सेकंड 10 बार की जाँच करेगा, एक समय में बंद एक आइटम खींच रहा है। आपको निश्चित रूप से अपनी वास्तविक डेटा स्थितियों के लिए इसे समायोजित करना होगा। यह मानता है कि आपके पास has_data जैसी कुछ विधि है जो सही हो सकती है अगर केवल एक पठन ब्लॉक न हो।

संबंधित मुद्दे