有没有办法让 Tkinter 文本小部件只读?

Posted

技术标签:

【中文标题】有没有办法让 Tkinter 文本小部件只读?【英文标题】:Is there a way to make the Tkinter text widget read only? 【发布时间】:2011-04-20 00:29:58 【问题描述】:

它看起来没有那个属性,但它对我来说真的很有用。

【问题讨论】:

一个 Tkinter Entry 小部件允许 entry.config(state='readonly')。不幸的是,这似乎不适用于 Text 小部件。 【参考方案1】:

您必须将Text 小部件的the state 从NORMAL 更改为DISABLED 输入text.insert()text.bind() 之后:

text.config(state=DISABLED)

【讨论】:

那你不能选择文本,复制它。 选择和复制(在 Windows 中通过 CTRL-C 并在 Linux 中自动)对我来说似乎工作得很好。 @CraigMcQueen 实际上,您可以通过将<1> 与将焦点设置在文本小部件上的函数绑定来做到这一点:text.bind("<1>", lambda event: text.focus_set()) @nbro 但是在 Python 3.6 中你需要使用 state="readonly" 而不是 state=DISABLED @szmoore state="readonly" 不被文本小部件接受。它被 Ttk 小部件使用;你在想 Ttk Entry 小部件吗?【参考方案2】:
text = Text(app, state='disabled', width=44, height=5)

插入前后改变状态,否则不会更新

text.configure(state='normal')
text.insert('end', 'Some Text')
text.configure(state='disabled')

【讨论】:

【参考方案3】:

非常简单的解决方案是将任何按键绑定到返回“break”的函数,如下所示:

import Tkinter

root = Tkinter.Tk() 

readonly = Tkinter.Text(root)
readonly.bind("<Key>", lambda e: "break")

【讨论】:

这对我的用例非常有用。我需要绑定一个函数以允许跟踪超链接。 这应该是公认的答案!简洁大方!【参考方案4】:

tcl wiki 详细描述了这个问题,并列出了三种可能的解决方案:

    其他答案中描述的禁用/启用技巧 替换插入/删除事件的绑定 与 (2) 相同,但将其封装在单独的小部件中。

(2) 或 (3) 会更好,但是,解决方案并不明显。但是,a worked solution is available on the unpythonic wiki:

 from Tkinter import Text
 from idlelib.WidgetRedirector import WidgetRedirector

 class ReadOnlyText(Text):
     def __init__(self, *args, **kwargs):
         Text.__init__(self, *args, **kwargs)
         self.redirector = WidgetRedirector(self)
         self.insert = self.redirector.register("insert", lambda *args, **kw: "break")
         self.delete = self.redirector.register("delete", lambda *args, **kw: "break")

【讨论】:

什么是idlelib,它来自哪里?最好有一个不需要idlelib 依赖的解决方案。 在 Ubuntu Linux 上,我可以通过sudo apt-get install idle-python2.7 获得idlelib idlelib 是 Python 标准库的一部分。然而,出于某种原因,Ubuntu 似乎喜欢将 Python 打包成许多小部分。【参考方案5】:

我没有 50 名声望,所以我无法在 nbro's 答案上添加评论。尽管如此,这就是这个答案的归属。

如果你的用例真的很简单,nbro'stext.bind('', lambda event: text.focus_set()) 代码解决了Craig McQueen 看到的交互问题在 OS X 上,但其他人在 Windows 和 Linux 上看不到。

OTOH,如果您的只读数据具有任何上下文结构,那么您可能最终会使用 Tkinter.Text.insert(position, text , taglist) 将其添加到标签下的只读文本框窗口中。您将这样做是因为您希望部分数据根据上下文脱颖而出。使用标签标记的文本可以通过调用 .Text.tag_config() 来更改字体或颜色等来强调。同样,使用标签标记的文本可以使用 .Text.tag_bind()。有一个使用these functions here 的好例子。如果 mark_for_paste() 函数很好,那么理解数据上下文的 mark_for_paste() 函数可能会更好。

【讨论】:

【参考方案6】:
from Tkinter import *
root = Tk()
text = Text(root)
text.insert(END,"Some Text")
text.configure(state='disabled')

【讨论】:

那你不能选择文本,复制它。 您也可以选择文本并复制。它在 Windows 中为我工作 @CraigMcQueen - 我很确定无论状态如何,这都是在内部处理的。我也不知道你是否可以禁用选择和复制。【参考方案7】:

我就是这样做的。最后将状态设为禁用会禁止用户编辑文本框,但在编辑文本框之前使状态正常是插入文本所必需的。

from tkinter import *
text=Text(root)
text.pack()
text.config(state="normal")
text.insert(END, "Text goes here")
text.config(state="disabled")

【讨论】:

本网站上通常不赞成仅使用代码的答案。您能否编辑您的答案以包含一些 cmets 或对您的代码的解释?解释应回答以下问题:它有什么作用?它是如何做到的?它去哪儿了?它如何解决OP的问题?见:How to anwser。谢谢!【参考方案8】:

如果您想禁用用户编辑并允许 Ctrl+C 在屏幕上复制文本,请在 Windows 中使用此代码:

def txtEvent(event):
    if(event.state==12 and event.keysym=='c' ):
        return
    else:
        return "break"

txt.bind("<Key>", lambda e: txtEvent(e))

【讨论】:

很好的解决方案。正是我需要的。这在 Windows 上不起作用?【参考方案9】:

如果不需要选择文本,则禁用状态是最简单的方法。为了支持复制,您可以使用外部实体 - Button - 来完成这项工作。每当用户按下按钮时,Text 的内容将被复制到剪贴板。 Tk 具有处理剪贴板的内置支持(请参阅here),因此模拟Ctrl-C 的行为是一项简单的任务。如果您正在构建一个写入日志消息的控制台,您可以进一步添加Entry,用户可以在其中指定他想要复制的日志消息的数量。

【讨论】:

【参考方案10】:

许多人提到当状态被禁用时,您无法从文本小部件中复制。对于 Ubuntu Python 3.8.5 上的我来说,复制问题原来是由于小部件没有关注 Ubuntu(适用于 Windows)引起的。

我一直在使用将状态设置为禁用然后切换状态的解决方案,当我需要使用 1) text.config(state=tkinter.NORMAL) 2) 编辑文本和 3) 文本以编程方式编辑它时.config(状态=tkinter.DISABLED)。 在 Windows 上,我能够正常地从小部件中复制文本,但在 Ubuntu 上,看起来我已经选择了文本,但我无法复制它。

经过一些测试,结果证明,只要文本小部件有焦点,我就可以复制它。在 Windows 上,无论状态如何,当您单击文本小部件时,它似乎都会获得焦点,但在 Ubuntu 上,单击文本小部件不会获得焦点。

所以我通过将 text.focus_set() 绑定到鼠标单击事件“

import tkinter
root = tkinter.Tk()
text0 = tkinter.Text(root, state=tkinter.DISABLED)
text0.config(state=tkinter.NORMAL)
text0.insert(1.0, 'You can not copy or edit this text.')
text0.config(state=tkinter.DISABLED)
text0.pack()

text1 = tkinter.Text(root, state=tkinter.DISABLED)
text1.config(state=tkinter.NORMAL)
text1.insert(1.0, 'You can copy, but not edit this text.')
text1.config(state=tkinter.DISABLED)
text1.bind("<Button>", lambda event: text1.focus_set())
text1.pack()

至少对我来说,这是一个简单但有效的解决方案,希望其他人觉得它有用。

【讨论】:

【参考方案11】:

禁用 Text 小部件并不理想,因为您需要重新启用它才能对其进行更新。一种更简单的方法是捕捉鼠标按钮和任何击键。所以:

    textWidget.bind("<Button-1>", lambda e: "break")
    textWidget.bind("<Key>", lambda e: "break")

似乎可以解决问题。这就是我在文本编辑器中禁用“行号”文本小部件的方式。第一行是更强大的行。我不确定是否需要第二个,但它让我感觉更好。 :)

【讨论】:

附带说明,禁用鼠标左键会阻止用户单击并选择完成大部分工作的文本小部件。但禁用键也有帮助,以防可以将 Text 小部件插入或获得键盘焦点。【参考方案12】:

您可以改用标签。标签可以通过编程方式进行编辑,并且用户不能进行编辑。

【讨论】:

这样做会失去很多功能。 @BryanOakley 如果打算用作只读功能,您还需要什么功能? 滚动的能力和将格式应用于单个字符的能力是你失去的两个最大的东西。此外,您失去了选择文本的能力,并且文本小部件中的自动换行比标签中的换行要好得多。

以上是关于有没有办法让 Tkinter 文本小部件只读?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在tkinter treeview中重置索引?

tkinter Text() 小部件上的 4096 个单行字符限制?

PyQt QTabWidget 多角小部件

Tkinter Label小部件中的下划线文本?

有没有办法在 tkinter 中正确显示标签边框?

如何为 Tkinter 条目小部件设置默认文本