Tôi đang trong quá trình xây dựng một ứng dụng dựa trên GUI với Python/Tkinter được xây dựng trên đỉnh của mô-đun bdb Python hiện có. Trong ứng dụng này, tôi muốn tắt tất cả stdout/stderr từ giao diện điều khiển và chuyển hướng nó đến GUI của tôi. Để thực hiện mục đích này, tôi đã viết một đối tượng Tkinter.Text chuyên dụng (mã ở cuối bài viết).Lỗi phân đoạn khi chuyển hướng sys.stdout sang phụ kiện Tkinter.Text
Ý tưởng cơ bản là khi một cái gì đó được ghi vào sys.stdout, nó xuất hiện dưới dạng một dòng trong "Văn bản" với màu đen. Nếu một cái gì đó được ghi vào sys.stderr, nó hiển thị như một dòng trong "Văn bản" với màu đỏ. Ngay sau khi một cái gì đó được viết, Văn bản luôn cuộn xuống để xem dòng gần đây nhất.
Tôi đang sử dụng Python 2.6.1 tại thời điểm này. Trên Mac OS X 10.5, điều này dường như làm việc tuyệt vời. Tôi đã không có vấn đề với nó. Tuy nhiên, trên RedHat Enterprise Linux 5, tôi khá chắc chắn có được lỗi phân đoạn trong khi chạy tập lệnh. Lỗi phân đoạn không phải lúc nào cũng xảy ra ở cùng một nơi, nhưng nó luôn luôn xảy ra. Nếu tôi nhận xét các dòng sys.stdout=
và sys.stderr=
từ mã của tôi, lỗi phân đoạn dường như biến mất.
Tôi chắc chắn có nhiều cách khác mà tôi có thể phải sử dụng, nhưng có ai có thể thấy bất cứ điều gì tôi đang làm sai ở đây có thể gây ra những lỗi phân đoạn này không? Nó làm tôi khốn khổ. Cảm ơn!
PS - Tôi nhận ra chuyển hướng sys.stderr sang GUI có thể không phải là một ý tưởng tuyệt vời, nhưng tôi vẫn nhận được lỗi phân đoạn ngay cả khi tôi chỉ chuyển hướng sys.stdout chứ không phải sys.stderr. Tôi cũng nhận ra rằng tôi cho phép Văn bản phát triển vô thời hạn vào lúc này.
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()
cũng giống như một sang một bên, tôi sẽ đề nghị * không * tự động cuộn xuống trong mọi trường hợp. Nếu người dùng đã cuộn lên để xem một cái gì đó và sau đó một mục mới được thêm vào, họ sẽ là một người dùng không hài lòng khi những gì họ đang xem xét thay đổi. Thuật toán tôi sử dụng là, nếu dòng cuối cùng hiển thị trước khi nhập văn bản mới, tôi sẽ tự động cuộn. Nếu không thì tôi thì không. –
Cuộc gọi tốt. Tôi chắc chắn rằng một trong những sẽ được hiển thị trong danh sách "Để sửa chữa" của tôi đủ sớm. –