2010-05-26 4 views
5

पर मैं एक जीयूआई-आधारित अनुप्रयोग बनाने की प्रक्रिया में हूं जो कि मौजूदा पायथन बीडीबी मॉड्यूल के शीर्ष पर बनाता है जो पाइथन/टिंकर के साथ एक जीयूआई आधारित अनुप्रयोग बनाने की प्रक्रिया में है। इस एप्लिकेशन में, मैं कंसोल से सभी stdout/stderr को चुप करना चाहता हूं और इसे अपने जीयूआई पर रीडायरेक्ट करना चाहता हूं। इस उद्देश्य को पूरा करने के लिए, मैंने एक विशेष Tkinter लिखा है। अगला ऑब्जेक्ट (पोस्ट के अंत में कोड)।सेक्शनमेंट गलती sykinstout को tkinter.ext विजेट

मूल विचार यह है कि जब sys.stdout को कुछ लिखा जाता है, तो यह रंगीन रंग के साथ "टेक्स्ट" में एक पंक्ति के रूप में दिखाई देता है। यदि sys.stderr को कुछ लिखा गया है, तो यह रंग लाल रंग के साथ "पाठ" में एक पंक्ति के रूप में दिखाई देता है। जैसे ही कुछ लिखा जाता है, टेक्स्ट सबसे हालिया रेखा को देखने के लिए हमेशा नीचे स्क्रॉल करता है।

मैं इस समय पाइथन 2.6.1 का उपयोग कर रहा हूं। मैक ओएस एक्स 10.5 पर, यह बहुत अच्छा काम करता प्रतीत होता है। मुझे इसके साथ शून्य समस्याएं हैं। रेडहाट एंटरप्राइज़ लिनक्स 5 पर, हालांकि, मुझे एक स्क्रिप्ट के चलाने के दौरान बहुत से विश्वसनीयता गलती मिलती है। सेगमेंटेशन गलती हमेशा एक ही स्थान पर नहीं होती है, लेकिन यह हमेशा बहुत अधिक होती है। अगर मैं अपने कोड से sys.stdout= और sys.stderr= लाइनों पर टिप्पणी करता हूं, तो सेगमेंटेशन दोष दूर जाने लगते हैं।

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

पीएस - मुझे लगता है कि जीयूआई में sys.stderr को रीडायरेक्ट करना एक अच्छा विचार नहीं हो सकता है, लेकिन मुझे अभी भी सेगमेंटेशन दोष मिलते हैं जब भी मैं sys.stdout को रीडायरेक्ट करता हूं और sys.stderr नहीं। मुझे यह भी एहसास है कि मैं इस समय पाठ को अनिश्चित काल तक बढ़ने की इजाजत दे रहा हूं।

class ConsoleText(tk.Text): 
    '''A Tkinter Text widget that provides a scrolling display of console 
    stderr and stdout.''' 

    class IORedirector(object): 
     '''A general class for redirecting I/O to this Text widget.''' 
     def __init__(self,text_area): 
      self.text_area = text_area 

    class StdoutRedirector(IORedirector): 
     '''A class for redirecting stdout to this Text widget.''' 
     def write(self,str): 
      self.text_area.write(str,False) 

    class StderrRedirector(IORedirector): 
     '''A class for redirecting stderr to this Text widget.''' 
     def write(self,str): 
      self.text_area.write(str,True) 

    def __init__(self, master=None, cnf={}, **kw): 
     '''See the __init__ for Tkinter.Text for most of this stuff.''' 

     tk.Text.__init__(self, master, cnf, **kw) 

     self.started = False 
     self.write_lock = threading.Lock() 

     self.tag_configure('STDOUT',background='white',foreground='black') 
     self.tag_configure('STDERR',background='white',foreground='red') 

     self.config(state=tk.DISABLED) 

    def start(self): 

     if self.started: 
      return 

     self.started = True 

     self.original_stdout = sys.stdout 
     self.original_stderr = sys.stderr 

     stdout_redirector = ConsoleText.StdoutRedirector(self) 
     stderr_redirector = ConsoleText.StderrRedirector(self) 

     sys.stdout = stdout_redirector 
     sys.stderr = stderr_redirector 

    def stop(self): 

     if not self.started: 
      return 

     self.started = False 

     sys.stdout = self.original_stdout 
     sys.stderr = self.original_stderr 

    def write(self,val,is_stderr=False): 

     #Fun Fact: The way Tkinter Text objects work is that if they're disabled, 
     #you can't write into them AT ALL (via the GUI or programatically). Since we want them 
     #disabled for the user, we have to set them to NORMAL (a.k.a. ENABLED), write to them, 
     #then set their state back to DISABLED. 

     self.write_lock.acquire() 
     self.config(state=tk.NORMAL) 

     self.insert('end',val,'STDERR' if is_stderr else 'STDOUT') 
     self.see('end') 

     self.config(state=tk.DISABLED) 
     self.write_lock.release() 
+3

बस एक तरफ के रूप में, मैं सुझाव दूंगा कि * सभी * सभी मामलों में स्वचालित रूप से स्क्रॉल नहीं हो रहा है। यदि किसी उपयोगकर्ता ने कुछ देखने के लिए स्क्रॉल किया है और फिर एक नया आइटम जोड़ा जाता है तो वे एक दुखी उपयोगकर्ता होंगे जब वे दृश्यों को बाहर देख रहे हैं। मैं जिस एल्गोरिदम का उपयोग करता हूं वह है, यदि नया टेक्स्ट दर्ज करने से पहले अंतिम पंक्ति दिखाई दे रही है तो मैं स्वचालित रूप से स्क्रॉल करता हूं। अन्यथा मैं नहीं करता। –

+0

अच्छी कॉल। मुझे यकीन है कि कोई जल्द ही "ठीक करने के लिए" सूची में दिखाया गया होगा। –

उत्तर

3

ठीक है, इसलिए मैंने समस्या को ट्रैक करने में कामयाब रहा है। मैक ओएस एक्स 10.5.8 पर मैं इस समस्या को फिर से बनाने में सक्षम नहीं था, जहां मैंने मूल रूप से कोड विकसित किया था। विभाजन दोष केवल RedHat Enterprise Linux पर होने लगते हैं 5.

ऐसा लगता है कि कोड के इस टुकड़े दोषी है:

def write(self,val,is_stderr=False): 

     #Fun Fact: The way Tkinter Text objects work is that if they're disabled, 
     #you can't write into them AT ALL (via the GUI or programatically). Since we want them 
     #disabled for the user, we have to set them to NORMAL (a.k.a. ENABLED), write to them, 
     #then set their state back to DISABLED. 

     self.write_lock.acquire() 
     self.config(state=tk.NORMAL) 

     self.insert('end',val,'STDERR' if is_stderr else 'STDOUT') 
     self.see('end') 

     self.config(state=tk.DISABLED) 
     self.write_lock.release() 

काश मैं के लिए एक स्पष्टीकरण था क्यों विभाजन दोष हैं घटित हो रहा है, लेकिन मुझे पता चला है कि टेक्स्ट ऑब्जेक्ट को लगातार सक्षम और अक्षम करना अपराधी है। यदि मैं यह करने के लिए कोड के ऊपर टुकड़ा बदलने के लिए:

def write(self,val,is_stderr=False): 

     self.write_lock.acquire() 

     self.insert('end',val,'STDERR' if is_stderr else 'STDOUT') 
     self.see('end') 

     self.write_lock.release() 

मेरे विभाजन दोष दूर जाना जब मैं self.config(state=...) कॉल को हटा दें। self.config(state=...) कॉल का पूरा बिंदु इसे बनाना था ताकि उपयोगकर्ता टेक्स्ट फ़ील्ड को संपादित नहीं कर सके। जब टेक्स्ट फ़ील्ड tk.DISABLED स्थिति में है, तो self.insert(...) पर कॉल या तो काम नहीं करते हैं।

मैं जिस वर्कअराउंड समाधान के साथ आया हूं वह टेक्स्ट फ़ील्ड सक्षम है, लेकिन टेक्स्ट फ़ील्ड को सभी कीबोर्ड इनपुट को अनदेखा करने का कारण बनता है (इस प्रकार यदि उपयोगकर्ता कीबोर्ड का उपयोग करने का प्रयास करता है तो केवल पढ़ने के व्यवहार का भ्रम देता है) ।यह करने के लिए सबसे आसान तरीका है __init__ विधि बदलने के लिए इस तरह देखने के लिए (tk.NORMAL करने के लिए राज्य को बदलने और बाध्यकारी बदलने <Key> घटनाओं के लिए) है:

def __init__(self, master=None, cnf={}, **kw): 
     '''See the __init__ for Tkinter.Text for most of this stuff.''' 

     tk.Text.__init__(self, master, cnf, **kw) 

     self.started = False 
     self.write_lock = threading.Lock() 

     self.tag_configure('STDOUT',background='white',foreground='black') 
     self.tag_configure('STDERR',background='white',foreground='red') 

     self.config(state=tk.NORMAL) 
     self.bind('<Key>',lambda e: 'break') #ignore all key presses 

आशा है कि जो कोई एक ही समस्या में चलाता है मदद करता है।

+1

नैश: कीप्रेस को अनदेखा करने के बजाय, विजेट के लिए बाइंडटैग से "टेक्स्ट" को निकालने का विकल्प है। –

3

मुझे लगता है कि यह एक बड़े, थ्रेडेड प्रोग्राम का हिस्सा है।

लॉक का उपयोग करने के बजाय, अपना कोड थ्रेड-सुरक्षित कतार ऑब्जेक्ट पर लिखें। फिर, अपने मुख्य धागे में आप कतार मतदान करते हैं और टेक्स्ट विजेट पर लिखते हैं। आप मतदान लूप चलाकर इवेंट लूप (बनाम अपना खुद का लूप लिखकर) का उपयोग करके मतदान कर सकते हैं जो बाद में कुछ एमएस चलाने के लिए खुद को फिर से निर्धारित करता है (कुछ सौ एमएस शायद काफी पर्याप्त है)।

+0

दुर्भाग्य से मुझे लगता है कि मेरे पास एक बड़ी और बहुत बड़ी समस्या है कि मैं अभी भी डिबगिंग कर रहा हूं, लेकिन मुझे लगता है कि यह मॉडल डिस्प्ले करने का एक क्लीनर और बेहतर तरीका है। धन्यवाद प्रतिक्रिया देना के लिए। –

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