我想将tkinter text widget
用作readonly
小部件。它应该充当transcript
区域。我的想法是将此脚本保留在file
中,每当用户写入任何内容时,只需删除窗口小部件的所有内容,然后重新重写。
代码如下:
transcript_entry = SimpleEditor() # SimpleEditor is inherited from ScrolledText
transcript_entry.text.delete("1.0", END)
# this is just a test string, it should be the contents of the transcript file
transcript_entry.text.insert("1.0", "This is test transcript")
transcript_entry.text.bind("<KeyPress>", transcript_entry.readonly)
readonly
函数看起来像:
def readonly(self, event):
self.text.delete("1.0", END)
# this is just a test string, it should be the contents of the transcript file
self.text.insert("1.0", "This is test transcript")
这里的错误是用户输入的最后一个字符被添加到记录中。我怀疑原因是调用了readonly函数,then
用户输入被写入窗口小部件。如何扭转此顺序&amp;让readonly函数调用after
将用户输入写入小部件?
任何提示?
答案 0 :(得分:5)
插入最后一个字符的原因是因为默认绑定(导致插入)在放置在窗口小部件上的自定义绑定之后发生。因此,首先激活绑定,然后然后默认绑定将插入字符。这里还有其他问题和答案,可以更深入地讨论这个问题。例如,请参阅https://stackoverflow.com/a/11542200/
然而,有一种更好的方法来完成你想要做的事情。如果要创建只读文本窗口小部件,可以将state
属性设置为"disabled"
。这将阻止所有插入和删除(并且意味着您需要在以编程方式输入数据时还原状态)。
在某些平台上,您似乎无法突出显示和复制文本,但这只是因为默认情况下窗口小部件不会专注于鼠标单击。通过添加绑定来设置焦点,用户可以突出显示和复制文本,但无法剪切或插入。
以下是使用python 2.x的示例;对于3.x,您只需更改导入:
import Tkinter as tk
from ScrolledText import ScrolledText
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
t = ScrolledText(self, wrap="word")
t.insert("end", "Hello\nworld")
t.configure(state="disabled")
t.pack(side="top", fill="both", expand=True)
# make sure the widget gets focus when clicked
# on, to enable highlighting and copying to the
# clipboard.
t.bind("<1>", lambda event: t.focus_set())
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
答案 1 :(得分:1)
请不要删除并重新插入文字:
我发现创建只读文本的最佳方法是禁用导致文本更改的所有绑定。
我的解决方案是创建一个仅包含“只读命令”的新Widget绑定映射。然后,只需重新配置您的小部件以使用新的RO绑定映射而不是默认的映射:
from Tkinter import *
# This is the list of all default command in the "Text" tag that modify the text
commandsToRemove = (
"<Control-Key-h>",
"<Meta-Key-Delete>",
"<Meta-Key-BackSpace>",
"<Meta-Key-d>",
"<Meta-Key-b>",
"<<Redo>>",
"<<Undo>>",
"<Control-Key-t>",
"<Control-Key-o>",
"<Control-Key-k>",
"<Control-Key-d>",
"<Key>",
"<Key-Insert>",
"<<PasteSelection>>",
"<<Clear>>",
"<<Paste>>",
"<<Cut>>",
"<Key-BackSpace>",
"<Key-Delete>",
"<Key-Return>",
"<Control-Key-i>",
"<Key-Tab>",
"<Shift-Key-Tab>"
)
class ROText(Text):
tagInit = False
def init_tag(self):
"""
Just go through all binding for the Text widget.
If the command is allowed, recopy it in the ROText binding table.
"""
for key in self.bind_class("Text"):
if key not in commandsToRemove:
command = self.bind_class("Text", key)
self.bind_class("ROText", key, command)
ROText.tagInit = True
def __init__(self, *args, **kwords):
Text.__init__(self, *args, **kwords)
if not ROText.tagInit:
self.init_tag()
# Create a new binding table list, replace the default Text binding table by the ROText one
bindTags = tuple(tag if tag!="Text" else "ROText" for tag in self.bindtags())
self.bindtags(bindTags)
text = ROText()
text.insert("1.0", """A long text with several
lines
in it""")
text.pack()
text.mainloop()
请注意,只是更改了绑定。所有Text命令(如insert,delete,...)仍然可用。
答案 2 :(得分:-1)
我最近使用了一种不同的,稍微简单的解决方案。可以添加一个函数来删除所有输入字符,而不是更改所有绑定:
def read_only(self, event):
if event.char is not '': # delete only if the key pressed
# corresponds to an actual character
self.text.delete('insert-1c')
并将其绑定到任何事件:
root.bind('<Key>', self.read_only)