2012-01-13 22 views
6

के साथ पाइथन टिंकर टेक्स्ट विजेट मैंने एक साधारण टिंकर आधारित पायथन एप्लिकेशन लिखा जो सीरियल कनेक्शन से टेक्स्ट पढ़ता है और इसे विंडो में जोड़ता है, विशेष रूप से एक टेक्स्ट चौड़ा होता है।ऑटो और कस्टम स्क्रॉल

बहुत सारे बदलाव और कुछ बहुत ही अजीब अपवादों के बाद, यह काम करता है। फिर मैंने इसे करके ऑटोस्कोलिंग जोड़ा:

self.text.insert(END, str(parsed_line)) 
self.text.yview(END) 

ये पंक्तियां थ्रेड में चलती हैं। सीरियल कनेक्शन से पढ़ने पर थ्रेड ब्लॉक, लाइनों को विभाजित करता है और फिर विजेट को सभी लाइनों को जोड़ता है।

यह भी काम करता है। फिर मैं उपयोगकर्ता को स्क्रॉल करने की इजाजत देना चाहता था जिसे उपयोगकर्ता को तब तक स्क्रॉल करना चाहिए जब तक कि उपयोगकर्ता नीचे तक स्क्रॉल न करे।

मुझे यह Stop Text widget from scrolling when content is changed संबंधित लगता है।

if self.myWidgetScrollbar.get() == 1.0: 
    self.myWidget.yview(END) 

मैं भी .get()[1] की कोशिश की जो वास्तव में तत्व मैं चाहता हूँ (नीचे की स्थिति) है: विशेष रूप से, मैं DuckAssasin की टिप्पणी से कोड की कोशिश की। बहरहाल, यह निम्न अपवादों के साथ दुर्घटनाओं:

Traceback (most recent call last): 
    File "transformer-gui.py", line 119, in run 
    pos = self.scrollbar.get()[1] 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 2809, in get 
    return self._getdoubles(self.tk.call(self._w, 'get')) 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 1028, in _getdoubles 
    return tuple(map(getdouble, self.tk.splitlist(string))) 
ValueError: invalid literal for float(): None 

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

उम्मीद है कि कोई भी इस समस्या से मेरी मदद कर सकता है!

[संपादित करें]

ठीक है, मैं एक डेमो स्क्रिप्ट है कि मेरी विन XP मशीन पर इस मुद्दे को पुन: पेश कर सकते हैं एकत्र कर लें:

import re,sys,time 
from Tkinter import * 
import Tkinter 
import threading 
import traceback 


class ReaderThread(threading.Thread): 
    def __init__(self, text, scrollbar): 
     print "Thread init" 
     threading.Thread.__init__(self) 
     self.text = text 
     self.scrollbar = scrollbar 
     self.running = True 

    def stop(self): 
     print "Stopping thread" 
     running = False 

    def run(self): 
     print "Thread started" 
     time.sleep(5) 
     i = 1 
     try: 
      while(self.running): 
       # emulating delay when reading from serial interface 
       time.sleep(0.05) 
       line = "the quick brown fox jumps over the lazy dog\n" 

       curIndex = "1.0" 
       lowerEdge = 1.0 
       pos = 1.0 

       # get cur position 
       pos = self.scrollbar.get()[1] 

       # Disable scrollbar 
       self.text.configure(yscrollcommand=None, state=NORMAL) 

       # Add to text window 
       self.text.insert(END, str(line)) 
       startIndex = repr(i) + ".0" 
       curIndex = repr(i) + ".end" 

       # Perform colorization 
       if i % 6 == 0: 
        self.text.tag_add("warn", startIndex, curIndex) 
       elif i % 6 == 1: 
        self.text.tag_add("debug", startIndex, curIndex)        
       elif i % 6 == 2: 
        self.text.tag_add("info", startIndex, curIndex)       
       elif i % 6 == 3: 
        self.text.tag_add("error", startIndex, curIndex)        
       elif i % 6 == 4: 
        self.text.tag_add("fatal", startIndex, curIndex)        
       i = i + 1 

       # Enable scrollbar 
       self.text.configure(yscrollcommand=self.scrollbar.set, state=DISABLED) 

       # Auto scroll down to the end if scroll bar was at the bottom before 
       # Otherwise allow customer scrolling       

       if pos == 1.0: 
        self.text.yview(END) 

       #if(lowerEdge == 1.0): 
       # print "is lower edge!" 
       #self.text.see(curIndex) 
       #else: 
       # print "Customer scrolling", lowerEdge 

       # Get current scrollbar position before inserting 
       #(upperEdge, lowerEdge) = self.scrollbar.get() 
       #print upperEdge, lowerEdge 

       #self.text.update_idletasks() 
     except Exception as e: 
      traceback.print_exc(file=sys.stdout) 
      print "Exception in receiver thread, stopping..." 
      pass 
     print "Thread stopped" 


class Transformer: 
    def __init__(self): 
     pass 

    def start(self): 
     """starts to read linewise from self.in_stream and parses the read lines""" 
     count = 1 
     root = Tk() 
     root.title("Tkinter Auto-Scrolling Test") 
     topPane = PanedWindow(root, orient=HORIZONTAL) 
     topPane.pack(side=TOP, fill=X) 
     lowerPane = PanedWindow(root, orient=VERTICAL) 

     scrollbar = Scrollbar(root) 
     scrollbar.pack(side=RIGHT, fill=Y) 
     text = Text(wrap=WORD, yscrollcommand=scrollbar.set) 
     scrollbar.config(command=text.yview) 
     # Color definition for log levels 
     text.tag_config("debug",foreground="gray50") 
     text.tag_config("info",foreground="green") 
     text.tag_config("warn",foreground="orange") 
     text.tag_config("error",foreground="red") 
     text.tag_config("fatal",foreground="#8B008B") 
     # set default color 
     text.config(background="black", foreground="gray"); 
     text.pack(expand=YES, fill=BOTH)   

     lowerPane.add(text) 
     lowerPane.pack(expand=YES, fill=BOTH) 

     t = ReaderThread(text, scrollbar) 
     print "Starting thread" 
     t.start() 

     try: 
      root.mainloop() 
     except Exception as e: 
      print "Exception in window manager: ", e 

     t.stop() 
     t.join() 


if __name__ == "__main__": 
    try: 
     trans = Transformer() 
     trans.start() 
    except Exception as e: 
     print "Error: ", e 
     sys.exit(1)  

मैं इस scipt चलने देने और ऊपर स्क्रॉल करने के लिए शुरू करने और नीचे और

.\source\testtools\device-log-transformer>python tkinter-autoscroll.py 
Thread init 
Starting thread 
Thread started 
Traceback (most recent call last): 
    File "tkinter-autoscroll.py", line 59, in run 
    self.text.configure(yscrollcommand=self.scrollbar.set, state=DISABLED) 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 1202, in configure 
Stopping thread 
    return self._configure('configure', cnf, kw) 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 1193, in _configure 
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf)) 
TclError: invalid command name ".14762592" 
Exception in receiver thread, stopping... 
Thread stopped 

.\source\testtools\device-log-transformer>python tkinter-autoscroll.py 
Thread init 
Starting thread 
Thread started 
Stopping thread 
Traceback (most recent call last): 
    File "tkinter-autoscroll.py", line 35, in run 
    pos = self.scrollbar.get()[1] 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 2809, in get 
    return self._getdoubles(self.tk.call(self._w, 'get')) 
TclError: invalid command name ".14762512" 
Exception in receiver thread, stopping... 
Thread stopped 

.\source\testtools\device-log-transformer>python tkinter-autoscroll.py 
Thread init 
Starting thread 
Thread started 
Traceback (most recent call last): 
    File "tkinter-autoscroll.py", line 65, in run 
    self.text.yview(END) 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 3156, in yview 
    self.tk.call((self._w, 'yview') + what) 
Stopping threadTclError: invalid command name ".14762592" 

Exception in receiver thread, stopping... 
Thread stopped 

.\source\testtools\device-log-transformer>python tkinter-autoscroll.py 
Thread init 
Starting thread 
Thread started 
Traceback (most recent call last): 
    File "tkinter-autoscroll.py", line 35, in run 
    pos = self.scrollbar.get()[1] 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 2809, in get 
    return self._getdoubles(self.tk.call(self._w, 'get')) 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 1028, in _getdoubles 
    return tuple(map(getdouble, self.tk.splitlist(string))) 
ValueError: invalid literal for float(): None 
Exception in receiver thread, stopping... 
Thread stopped 
Stopping thread 

.\source\testtools\device-log-transformer>python tkinter-autoscroll.py 
Thread init 
Starting thread 
Thread started 
Traceback (most recent call last): 
    File "tkinter-autoscroll.py", line 53, in run 
    self.text.tag_add("error", startIndex, curIndex) 
    File "C:\Python26\lib\lib-tk\Tkinter.py", line 3057, in tag_add 
    (self._w, 'tag', 'add', tagName, index1) + args) 
TclError: bad option "261.0": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, pe 
er, replace, scan, search, see, tag, window, xview, or yview 
Exception in receiver thread, stopping... 
Thread stopped 

मुझे आशा है कि यह मदद करता है तुम मुझे :)

012 मदद करने के लिए: कुछ समय के बाद मैं इस तरह के रूप हमेशा अलग अपवाद का एक बहुत मिलता है

धन्यवाद,

/जम्मू

+0

क्या आप बिल्कुल निश्चित हैं कि 'self.scrollbar' वास्तव में स्क्रॉलबार विजेट का संदर्भ है? 'प्राप्त करें' कभी वापस नहीं लौटना चाहिए। सबसे खराब, यह '(0.0, 0.0, 0.0, 0.0) वापस लौटना चाहिए। –

+0

हां, मुझे यकीन है कि 'selfs.scrollbar' सही संदर्भ है। हालांकि, मैंने यह नहीं कहा कि 'प्राप्त करें') वास्तव में 'कोई नहीं' वापस लौटा, मैंने अभी कहा था कि कहीं भी कॉल स्टैक के भीतर, टिंकर ने किया था (जैसा कि आप ट्रेसबैक से देख सकते हैं 'ValueError: फ्लोट के लिए अमान्य शाब्दिक(): कोई नहीं 'मुझे यकीन नहीं है कि अगर टिंकटर आंतरिक रूप से विधि कॉल को कैसे संभालता है, तो इसका कोई संबंध नहीं है। जहां तक ​​मैं इसे समझता हूं, यह एक प्रकार का कार्य बनाता है जो टिंकर मुख्यधारा को भेजता है और फिर संवेदनापूर्वक संसाधित होता है। मैंने भी कोशिश की 'update_idletask' को कॉल करने के लिए, लेकिन यह पूरे सिस्टम को थोड़ी देर बाद लटकने का कारण बनता है। – jaw

उत्तर

2

ठीक है,

मैं Tkinter.generate_event() विधि का उपयोग अतुल्यकालिक घटना और जानकारी पारित करने के लिए एक कतार उत्पन्न करने के लिए उदाहरण स्क्रिप्ट को फिर से लिखने में सक्षम था noob Oddy द्वारा बहुमूल्य सुझावों के आधार पर।

हर बार एक लाइन धारा से पढ़ी जाती है (जो एक स्थिर स्ट्रिंग और देरी द्वारा अनुकरण किया जाता है), मैं लाइन को कतार में जोड़ता हूं (क्योंकि ईवेंट विधि को ऑब्जेक्ट पास करना AFAIK समर्थित नहीं है) और फिर एक बनाएं नयी घटना।

ईवेंट कॉलबैक विधि कतार से संदेश पुनर्प्राप्त करती है और इसे टेक्स्ट को चौड़ा कर देती है। यह काम करता है क्योंकि इस विधि को टिंकर मेनलोप से बुलाया जाता है, इस प्रकार यह अन्य नौकरियों में हस्तक्षेप नहीं कर सकता है।

import re,sys,time 
from Tkinter import * 
import Tkinter 
import threading 
import traceback 
import Queue 


class ReaderThread(threading.Thread): 
    def __init__(self, root, queue): 
     print "Thread init" 
     threading.Thread.__init__(self) 
     self.root = root 
     self.running = True 
     self.q = queue 

    def stop(self): 
     print "Stopping thread" 
     running = False 

    def run(self): 
     print "Thread started" 
     time.sleep(5) 

     try: 
      while(self.running): 
       # emulating delay when reading from serial interface 
       time.sleep(0.05) 
       curline = "the quick brown fox jumps over the lazy dog\n" 

       try: 
        self.q.put(curline) 
        self.root.event_generate('<<AppendLine>>', when='tail') 
       # If it failed, the window has been destoyed: over 
       except TclError as e: 
        print e 
        break 

     except Exception as e: 
      traceback.print_exc(file=sys.stdout) 
      print "Exception in receiver thread, stopping..." 
      pass 
     print "Thread stopped" 


class Transformer: 
    def __init__(self): 
     self.q = Queue.Queue() 
     self.lineIndex = 1 
     pass 

    def appendLine(self, event): 
     line = self.q.get_nowait() 

     if line == None: 
      return 

     i = self.lineIndex 
     curIndex = "1.0" 
     lowerEdge = 1.0 
     pos = 1.0 

     # get cur position 
     pos = self.scrollbar.get()[1] 

     # Disable scrollbar 
     self.text.configure(yscrollcommand=None, state=NORMAL) 

     # Add to text window 
     self.text.insert(END, str(line)) 
     startIndex = repr(i) + ".0" 
     curIndex = repr(i) + ".end" 

     # Perform colorization 
     if i % 6 == 0: 
      self.text.tag_add("warn", startIndex, curIndex) 
     elif i % 6 == 1: 
      self.text.tag_add("debug", startIndex, curIndex)        
     elif i % 6 == 2: 
      self.text.tag_add("info", startIndex, curIndex)       
     elif i % 6 == 3: 
      self.text.tag_add("error", startIndex, curIndex)        
     elif i % 6 == 4: 
      self.text.tag_add("fatal", startIndex, curIndex)        
     i = i + 1 

     # Enable scrollbar 
     self.text.configure(yscrollcommand=self.scrollbar.set, state=DISABLED) 

     # Auto scroll down to the end if scroll bar was at the bottom before 
     # Otherwise allow customer scrolling       

     if pos == 1.0: 
      self.text.yview(END) 

     self.lineIndex = i 

    def start(self): 
     """starts to read linewise from self.in_stream and parses the read lines""" 
     count = 1 
     self.root = Tk() 
     self.root.title("Tkinter Auto-Scrolling Test")# 
     self.root.bind('<<AppendLine>>', self.appendLine) 
     self.topPane = PanedWindow(self.root, orient=HORIZONTAL) 
     self.topPane.pack(side=TOP, fill=X) 
     self.lowerPane = PanedWindow(self.root, orient=VERTICAL) 

     self.scrollbar = Scrollbar(self.root) 
     self.scrollbar.pack(side=RIGHT, fill=Y) 
     self.text = Text(wrap=WORD, yscrollcommand=self.scrollbar.set) 
     self.scrollbar.config(command=self.text.yview) 
     # Color definition for log levels 
     self.text.tag_config("debug",foreground="gray50") 
     self.text.tag_config("info",foreground="green") 
     self.text.tag_config("warn",foreground="orange") 
     self.text.tag_config("error",foreground="red") 
     self.text.tag_config("fatal",foreground="#8B008B") 
     # set default color 
     self.text.config(background="black", foreground="gray"); 
     self.text.pack(expand=YES, fill=BOTH)  

     self.lowerPane.add(self.text) 
     self.lowerPane.pack(expand=YES, fill=BOTH) 

     t = ReaderThread(self.root, self.q) 
     print "Starting thread" 
     t.start() 

     try: 
      self.root.mainloop() 
     except Exception as e: 
      print "Exception in window manager: ", e 

     t.stop() 
     t.join() 


if __name__ == "__main__": 
    try: 
     trans = Transformer() 
     trans.start() 
    except Exception as e: 
     print "Error: ", e 
     sys.exit(1)  

धन्यवाद फिर से सभी को जो आपकी मदद के लिए योगदान:

यहाँ स्क्रिप्ट है!

+0

मैंने 'रीडर थ्रेड 'में डेटा पीढ़ी को छोड़कर उपरोक्त सटीक स्क्रिप्ट का उपयोग किया जो वास्तव में एक धारावाहिक इंटरफ़ेस का इनपुट स्ट्रीम है। दुर्भाग्यवश, यह अभी भी दुर्घटनाग्रस्त है। पहले से कम अक्सर लेकिन फिर भी, यह दुर्घटनाग्रस्त हो जाता है। तो मैंने 'self.root.event_generate' को कॉल करने के बाद देरी (0.02 एस) डाली। यह थोड़ा बेहतर हो गया है लेकिन यह अभी भी क्रैश हो रहा है: 'खराब विंडो नाम/पहचानकर्ता "40034472set" ' – jaw

+0

ओह, बस आपको सूचित करने के लिए, मेरे पास अभी एक नया" त्रुटि संदेश "था। असल में, python.exe, tcl85.dll में होने के कारण, क्रैश हो गया। यह यादृच्छिक रूप से भी होता है। इसे समेटने के लिए: मुझे लगता है (अगर मैं कुछ गलत नहीं कर रहा हूं), 'event_generate' विधि एक अलग थ्रेड से उपयोग करने के लिए पर्याप्त स्थिर नहीं है। – jaw

2

यह बताने के लिए क्या वास्तव में हो रहा है मुश्किल है लेकिन आप एक पंक्ति का उपयोग कर विचार किया है?

from Tkinter import * 
import time, Queue, thread 

def simulate_input(queue): 
    for i in range(100): 
     info = time.time() 
     queue.put(info) 
     time.sleep(0.5) 

class Demo: 
    def __init__(self, root, dataQueue): 
     self.root = root 
     self.dataQueue = dataQueue 

     self.text = Text(self.root, height=10) 
     self.scroller = Scrollbar(self.root, command=self.text.yview) 
     self.text.config(yscrollcommand=self.scroller.set) 
     self.text.tag_config('newline', background='green') 
     self.scroller.pack(side='right', fill='y') 
     self.text.pack(fill='both', expand=1) 

     self.root.after_idle(self.poll) 

    def poll(self): 
     try: 
      data = self.dataQueue.get_nowait() 
     except Queue.Empty: 
      pass 
     else: 
      self.text.tag_remove('newline', '1.0', 'end') 
      position = self.scroller.get() 
      self.text.insert('end', '%s\n' %(data), 'newline')    
      if (position[1] == 1.0): 
       self.text.see('end') 
     self.root.after(1000, self.poll) 

q = Queue.Queue() 
root = Tk() 
app = Demo(root, q) 

worker = thread.start_new_thread(simulate_input, (q,)) 
root.mainloop() 
+0

मुझे लगता है कि कतार समस्या नहीं है क्योंकि मेरे पास एक थ्रेड है जो स्ट्रीम से पढ़ रहा है और फिर इसे डालने और फिर नया डेटा आने तक प्रतीक्षा कर रहा है। एकमात्र चीज जो मदद कर सकती है वह मतदान देरी होगी। लेकिन आवृत्ति अधिक है, आउटपुट कमजोर है। – jaw

+0

आह, ठीक है, मुझे मिल गया! इस उदाहरण में, 'self.after() 'टाइमर में निर्मित पायथन नहीं है लेकिन एक टिंकर समारोह। तो इसका मतलब है, मुझे मतदान का उपयोग करने की ज़रूरत है? यह है आईएमएचओ किसी प्रकार का एंटी-पैटर्न मैं टालना चाहता हूं। – jaw

2

आपकी डेमो स्क्रिप्ट के बारे में।

आप गैर-जीयूआई थ्रेड से जीयूआई सामान कर रहे हैं। इससे समस्याएं पैदा होती हैं।

देखें: http://www.effbot.org/zone/tkinter-threads.htm

+0

संकेत के लिए धन्यवाद लेकिन मैंने इसे पहले ही पढ़ा है। और मुझे अंतर नहीं मिलता है। मेरी लिपि दोनों में "जीयूआई थ्रेड" और यह उदाहरण वास्तव में मुख्य धागा है क्योंकि आप 'root.mainloop()' को कॉल करते हैं जो आंतरिक रूप से जीयूआई कार्य करता है। फिर, आपको टिंकर के साथ बातचीत करने के लिए कम से कम एक अन्य थ्रेड की आवश्यकता है। यह मेरे मामले में धागे द्वारा और उदाहरण के मामले में टाइमर थ्रेड द्वारा किया जा रहा है। लेकिन मुझे थ्रेडिंग पॉइंट व्यू से कोई फर्क नहीं दिखता है। – jaw

+0

क्षमा करें, मैंने गलत पोस्ट पर अपना दूसरा जवाब पोस्ट किया है। यह जवाब और टिप्पणियों के साथ भ्रमित हो जाता है;)। तो, सिर्फ रिकॉर्ड के लिए (उसी) टिप्पणी फिर से करें: – jaw

+0

आह, ठीक है, मुझे मिल गया! इस उदाहरण में, स्वयं। बाद() 'टाइमर में निर्मित पायथन नहीं बल्कि एक टिंकर समारोह है। तो इसका मतलब है, मुझे मतदान का उपयोग करने की ज़रूरत है? यह IMHO किसी प्रकार का एंटी-पैटर्न है जिसे मैं टालना चाहता हूं। – jaw

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