Tôi đã viết một ứng dụng Python dựa trên Tkinter đơn giản đọc văn bản từ một kết nối nối tiếp và thêm nó vào cửa sổ, cụ thể là một văn bản được mở rộng.Python Tkinter Text Widget với Auto & Custom Scroll
Sau nhiều lần chỉnh sửa và một số ngoại lệ rất lạ, tính năng này hoạt động. Sau đó, tôi đã thêm tự động kiểm tra bằng cách thực hiện việc này:
self.text.insert(END, str(parsed_line))
self.text.yview(END)
Những dòng này chạy trong một chuỗi. Các chuỗi chặn đọc từ kết nối nối tiếp, chia tách các dòng và sau đó thêm tất cả các dòng vào tiện ích.
Điều này cũng hoạt động. Sau đó, tôi muốn cho phép người dùng cuộn để tắt tự động cuộn cho đến khi người dùng cuộn xuống dưới cùng.
Tôi tìm thấy điều này Stop Text widget from scrolling when content is changed dường như có liên quan. Đặc biệt, tôi đã thử mã từ nhận xét của DuckAssasin:
if self.myWidgetScrollbar.get() == 1.0:
self.myWidget.yview(END)
Tôi cũng đã cố gắng .get()[1]
thực sự là phần tử tôi muốn (vị trí dưới cùng). Tuy nhiên, lỗi này xảy ra với ngoại lệ sau:
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
Có vẻ như tkinter ở đâu đó sẽ trả về Không cái nào sau đó được phân tích cú pháp dưới dạng phao. Tôi đã đọc ở đâu đó, ví dụ: phương pháp chỉ mục của văn bản được mở rộng đôi khi trả về Không nếu vị trí được yêu cầu không hiển thị.
Hy vọng rằng, bất kỳ ai cũng có thể giúp tôi giải quyết vấn đề này!
[EDIT]
Ok, tôi đã tập hợp một kịch bản demo mà có thể tạo lại vấn đề này trên máy Win XP của tôi:
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)
tôi để chạy scipt này và bắt đầu di chuyển lên xuống và sau một thời gian tôi nhận được rất nhiều trường hợp ngoại lệ luôn luôn khác nhau như:
.\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
tôi hy vọng điều này sẽ giúp bạn để giúp tôi :)
Cảm ơn,
/J
Bạn có chắc chắn rằng 'self.scrollbar' thực sự là tham chiếu đến tiện ích con cuộn không? 'get' sẽ không bao giờ trả về None. Tệ nhất, nó sẽ trả về '(0.0, 0.0, 0.0, 0.0)'. –
Có, tôi chắc chắn rằng 'selfs.scrollbar' là tham chiếu chính xác. Tuy nhiên, tôi đã không nói rằng 'get()' đã thực sự trả về 'None', tôi chỉ nói rằng ở đâu đó trong ngăn xếp cuộc gọi, Tkinter đã làm (như bạn có thể thấy từ traceback' ValueError: chữ không hợp lệ cho float(): None Tôi không chắc liệu điều này có liên quan gì đến cách mà Tkinter xử lý nội bộ các cuộc gọi phương thức hay không. Theo như tôi hiểu, nó tạo ra một loại nhiệm vụ được gửi đến máy chủ Tkinter và được xử lý một cách đồng bộ. Để gọi 'update_idletask' nhưng điều này làm cho toàn bộ hệ thống bị treo sau một thời gian – jaw