Python3-tkinter中的只读文本小部件;跨平台

6
如何禁止终端用户编辑/添加/删除Text小部件中的文本?(Python v3.2...和tkinter)
重点是仅禁止更改/添加/删除文本的功能,而不是砍掉其他功能。也许一个名为NoEdit Text小部件会更好。
我尝试了.text['state'] = 'disabled',在Windows上它基本正常工作(它仍允许用户选择/复制文本,并突出显示选择区域,page up/down和up/down按钮也能工作。唯一出现问题的似乎是将光标隐藏)。但是在MacIntosh上所有功能都无法使用。没有高亮,没有选择/复制,太糟糕了!
由于Tkinter在Python中几乎没有文档,我搜索并找到了一些TCL建议,可以派生一个新类并取消插入和删除函数。
因此,我尝试了这样做:
class roText(tk.Text):
    def insert(self,*args,**kwargs):
        print(" Hey  - Im inside roText.insert")
        pass
    def delete(self,*args,**twargs):
        pass    
    def pInsert(self,*args,**twargs):
        super().insert(*args,**twargs)

很不幸,它并没有正常工作。显然,当最终用户输入/删除代码时,tkinter不使用那些插入和删除函数。也许那些TCL插入/删除是其他东西,我在从TCL和斯瓦希里语的翻译中失去了一些东西。 tkinter.Text 使用什么函数来编辑文本?希望它们不是内部函数...

那么,有没有一种方法可以修改Text小部件以仅抑制最终用户编辑?有没有一种方法可以在不深入并覆盖Tkinter内部代码的情况下完成,以便该内容不会被下一个Tkinter版本破坏?

看着Idle shell窗口,我发现他们设法抑制了编辑(除了最后一行)。所以有办法。但代价是什么?

3个回答

3
抱歉打扰了一个旧问题,但我也在寻找答案,最终找到了一个解决方案。我发现的解决方案涉及当文本小部件具有焦点时重写键绑定,而且非常简单。可以在这里找到:链接
要重写小部件的绑定,需要使用绑定函数,其中传递一个要被覆盖的字符串和您希望调用的新函数。
    self.txtBox.bind("<Key>", self.empty)

在类的其他地方,您需要定义处理事件的函数。

    def empty(self, event):
        return "break"

通过返回字符串"break",事件处理程序知道在您的函数后停止,而不是继续默认操作。
希望这回答了你的问题。干杯。

1
对我来说很有效,目前只在Linux上进行了测试。不过不需要单独的空函数。只需执行:self.txtBox.bind('<Key>', lambda _: 'break') - travc

2
disabled状态在Mac上似乎不起作用的原因是它关闭了给小部件焦点的绑定。没有焦点,Mac上的高亮显示就不会出现。如果将状态设置为disabled ,然后将绑定分配给<ButtonPress-1>以显式地将焦点设置到禁用的文本小部件上,您就可以选择和复制文本,并且高亮显示将会出现。
至于光标消失...可以说,这正是应该发生的事情。光标告诉用户“这里是插入文本的位置”。由于不会插入任何文本,拥有那个视觉提示会让用户感到困惑。如果真的很重要,你可以做的是,在他们点击的任何地方插入一个小图片来模拟光标。
关于小部件是否实际使用insertdelete方法的问题:默认绑定使用的是实际底层小部件上的方法,因此在子类中覆盖它们没有效果。你需要重新做所有的默认绑定才能使其生效。这是可行的,但需要大量的工作。
不幸的是,这是Tcl编程真正闪耀的领域之一,因为你可以简单地禁用小部件的insertdelete命令。当然,你也可以直接在Tkinter中这样做,因为最终它运行tcl代码来完成所有操作,但这将涉及编写一些tcl代码,对于Python程序员来说并不是一个很好的解决方案。
我认为最好的解决方案是使用禁用状态,然后添加足够的绑定来实现您想要的功能。
下面是一个简单的示例,通过在鼠标按钮单击时显式地设置焦点来工作。使用这个代码,我能够单击和滑动以选择区域,或者双击或三击以选择单词和行:
import Tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.text = tk.Text(width=40, height=20)
        self.text.bind("<1>", self.set_focus)
        self.text.insert("end", "\n".join(dir(tk.Tk)))
        self.text.configure(state="disabled")
        self.text.pack(fill="both", expand=True)

    def set_focus(self, event):
        '''Explicitly set focus, so user can select and copy text'''
        self.text.focus_set()

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

好的,我有机会在Mac上进行测试,text.focus_set()绑定到<1>解决了问题,就像你说的那样。谢谢!!!(也许这个页面可以为其他寻找解决方案的人清理一下。我在网上看到了很多)。不幸的是,正如我担心的那样,这显然是Tkinter移植到Mac的众多问题之一。'绿色'颜色在按钮上不起作用,按钮上的文本需要更多的间距(这可能与分辨率有关),等等...这些问题很容易解决,我只希望不会出现更严重的问题。 - Momus

-1

@BryanOakley,我花了一些时间来测试你的建议,因为我没有Mac电脑。 不幸的是,Python在Mac上的实现存在缺陷。 我已经添加了焦点,也就是我的禁用函数,在创建窗口并插入文本后,现在首先调用:

self.txt['state'] = 'disabled'

然后

self.txt.focus_set()

这就是我认为你所建议的。

它“有点”奏效。即:选择文本(单击和拖动或双击)时,大多数情况下都可以正常高亮显示。Python可能存在一些错误的内存引用或其他错误:有时高亮显示一开始不起作用,然后在更多点击后开始工作(在同一个窗口中)。有时候程序被调用时会立刻起作用。有时候使用Shift-rightArrow键进行选择可以正常工作,但使用鼠标选择则无法正常工作,然后又开始正常工作了。或者它在一个窗口中正常工作,但在另一个窗口中(两个窗口都属于同一类)却无法正常工作,然后又开始在所有窗口中正常工作...等等。

好消息是,添加焦点并没有对Windows产生不良影响(即所有功能都像没有焦点一样正常工作)。我想此时我只能希望未来/下一个版本的Mac Python将修复这些错误。

顺便说一句,似乎Mac对Python来说有点孤儿。实现比Windows要丑陋得多。我的意思是字体看起来更糟糕,按钮等等。或者这可能是由于不同的屏幕分辨率和Python端口不良导致的。不确定。

无论如何,感谢您的帮助和建议在Mac上使用焦点。


你需要在<1>事件的回调函数中调用focus_set,而不仅仅是在创建小部件时。从你的回答中看来,你只设置了一次焦点。我再次强调:为了显示高亮,小部件必须具有焦点。如果你让它获得焦点,那么当你点击其他任何地方时,它都可以失去焦点。添加一个绑定到<1>来设置焦点,这将确保在尝试进行选择时它始终具有焦点(因为任何选择始终从鼠标单击开始)。 - Bryan Oakley
@BryanOakley 我不知道你所说的“<1>事件回调”是什么意思。看来我的猜测是错误的... 我接下来的猜测是,你建议将文本小部件中的单击绑定到某个回调函数,该函数将调用...txt.focus_set()。 如果tkinter有<Tripple-1>(还没有检查),也许还可以为双击和三击做同样的事情。目前,我只为<Double-1>绑定/回调,但当然我可以为此制作一个特殊的绑定和一行回调,使用focus_set()。我会尝试将其发送给我的“Mac客户端”进行测试...再次感谢。 - Momus
我的原始答案是“将绑定分配给<ButtonPress-1>以显式设置焦点到禁用的文本小部件”。我认为这已经足够清楚了,但显然不是。我添加了一个示例来澄清。此外,您不需要对双击或三击执行相同的操作,因为执行双击或三击的唯一方法是先执行单击,因此此解决方案将使您能够双击或三击选择单词和行,以及单击并拖动以选择区域。 - Bryan Oakley
@BryanOakley 感谢您添加示例。(我不知道<1>是<Button-1>的替代品,因此有些困惑)。 是的,我已经通过print()测试了在<Button-1>上设置焦点,双击时也会设置焦点。实际上,只设置<Enter>可能就足够了,因为需要先按Enter再点击。但是现在我仍然保留了所有三个focus_set,因为不清楚Mac中的错误原因。我会在有机会在Mac上测试后发布。(还要感谢您的“奖励”,即使用“dir”) - Momus
如果您的GUI中有其他小部件,那么在按下“Enter”键时执行此操作似乎是一个非常糟糕的想法。您不希望焦点仅因为用户稍微移动了鼠标而发生变化。至于导致该错误的原因,我已经在我的原始答案中回答过了。这不是一个错误,而是设计的副作用。 - Bryan Oakley
@BryanOakley 是的,我在我的真实程序中使用多个窗口后很快就学会了回车键是个坏主意... :-) 所以现在它完全按照你在<1>上建议的方式进行.. [] 至于“这”是否是一个错误:我的理解是Tkinter应该在所有平台上都能够正常工作,除了本地外观和一些平台惯例可能有所不同。您是在暗示当文本被禁用时,高亮显示等功能应该在PC上工作但在Mac上不应该工作吗?显然我不是Mac用户,但这似乎很奇怪。让我想知道在Mac或Linux上还有什么其他不同的工作方式。 - Momus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接