簡體   English   中英

Readonly tkinter文本小部件

[英]Readonly tkinter text widget

我想使用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將用戶輸入寫入窗口小部件。 如何反轉此順序並after將用戶輸入寫入窗口小部件after調用readonly函數?

任何提示?

插入最后一個字符的原因是因為默認綁定(導致插入)發生放在窗口小部件上的自定義綁定之后 因此,首先觸發綁定, 然后默認綁定插入字符。 這里還有其他問題和答案,可以更深入地討論這個問題。 例如,請參閱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()

請不要刪除並重新插入文本:

  • 這是一個巨大的性能問題。
  • 它將刪除文本上設置的任何標記和標記
  • 這對用戶是可見的,用戶不喜歡閃爍的界面
  • 這不是必需的,Tkinter可以自定義,只是不允許用戶更改內容。

我發現創建只讀文本的最佳方法是禁用導致文本更改的所有綁定。

我的解決方案是創建一個只包含“只讀命令”的新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,...)仍然可用。

我最近使用了一種不同的,稍微簡單的解決方案。 可以添加一個函數來刪除所有輸入字符,而不是更改所有綁定:

  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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM