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

发布于 2024-12-10 07:29:23 字数 1131 浏览 1 评论 0原文

如何抑制最终用户在文本小部件中编辑/添加/删除文本的能力? (Python v3.2.. 和 tkinter)

重点是仅抑制更改/添加/删除文本的能力,而不是阉割其他功能。也许 NoEdit Text widged 会是一个更好的名字。

我已经尝试过 .text['state'] = 'disabled' 并且它在 Windows 中工作几乎正常(它仍然允许用户选择/复制文本突出显示所选内容,向上/向下翻页和向上/向下按钮可以正常工作。唯一损坏的似乎是光标变得不可见。)

但在 MacIntosh 上,一切都损坏了。没有突出显示,没有选择/复制,...UGH

由于 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 使用哪些函数来供最终用户编辑文本?希望它们不是内部的...

那么,有没有办法修改文本小部件以仅禁止最终用户编辑? 有没有一种方法可以做到这一点,而无需深入研究并覆盖内部 Tkinter 代码,这样这些内容就不会被 Tkinter 的下一版本破坏?

查看空闲 shell 窗口,我发现他们已成功抑制编辑(最后一行除外)。所以有一个办法。但它是什么以及成本有多高?

How to suppress end user ability to edit/add/delete text in a Text widget? (Python v3.2.. and tkinter)

The point is to suppress only the ability to change/add/delete text but not to castrate other features. Perhaps a NoEdit Text widged would be a better name.

I've tried .text['state'] = 'disabled' and it works almost OK in Windows (it still allows user to select/copy text highlights the selection, page up/down and up/down buttons work. The only thing broken seems to be the cursor made invisible.)

But on MacIntosh everything is broken. No highlights, no select/copy,... UGH

Since Tkinter has practically no documentation in Python, I've searched and found some TCL advise, to derive a new class and suppress the insert and delete functions.

So, I've tried as so:

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)

Unfortunately it didn't work right. Apparently tkinter does not use those insert and delete functions when end user enters/deletes code. Perhaps those TCL insert/delete are something else, and I lost something in translation from TCL and Swahili. What functions does tkinter.Text use for end user editing text? Hopefully they are not internal...

So, is there a way to modify the Text widget to suppress only end user editing?
Is there a way to do it without diving inside and overriding internal Tkinter code, so the stuff doesn't get broken by next releases of Tkinter?

Looking at the Idle shell window, I see that they've managed to suppress edits (except for the last line). So there is a way. But what is it and how costly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

柒七 2024-12-17 07:29:23

抱歉提出了一个老问题,但我也在寻找这个问题的答案并最终找到了解决方案。我发现的解决方案涉及当文本小部件具有焦点时覆盖键绑定并且非常简单。找到此处

要覆盖小部件的绑定,有一个绑定函数,您可以在其中传递要覆盖的字符串以及您希望它调用的新函数。

    self.txtBox.bind("<Key>", self.empty)

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

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

通过返回字符串“break”,事件处理程序知道在函数之后停止,而不是继续执行默认操作。

我希望这能回答你的问题。干杯。

Sorry for bumping an old question, but I was searching for an answer to this question also and finally found a solution. The solution I found involves overriding the key bindings when the text widget has focus and is pretty simple. Found here.

To override the bindings of a widget there is a bind function where you pass a string of what is to be overridden and the new function you want it to call.

    self.txtBox.bind("<Key>", self.empty)

Somewhere else in the class you'll need to define the function to handle the event.

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

By returning the string "break" the event handler knows to stop after your function, instead of continuing with the default action.

I hope this answers your question. Cheers.

岁月静好 2024-12-17 07:29:23

disabled 状态似乎在 Mac 上不起作用的原因是它关闭了为小部件提供焦点的绑定。如果没有焦点,Mac 上的突出显示就不会显示。如果将状态设置为 disabled,但随后将绑定分配给 以显式将焦点设置到禁用的文本小部件,则您可以选择并复制文本并且突出显示将会显示。

至于光标消失......可以说,这就是应该发生的事情。光标告诉用户“这是文本将被插入的位置”。由于不会插入任何文本,因此视觉线索会让用户感到困惑。如果确实很重要,您可以做的就是在点击的地方插入一个小图像来模拟光标。

要回答有关小部件是否实际使用 insertdelete 方法的问题:实际底层小部件上的方法是默认绑定使用的方法,因此在子类中重写它们没有影响。您需要重做所有默认绑定才能使其正常工作。这是可行的,但工作量很大。

不幸的是,这是 Tcl 编程真正大放异彩的领域,因为您可以简单地禁用小部件的插入删除命令。当然,您也可以直接在 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()

The reason the disabled state doesn't seem to work on the Mac is because it turns off the binding that gives focus to the widget. Without focus, the highlighting on a Mac doesn't show up. If you set the state to disabled but then assign a binding to <ButtonPress-1> to explicitly set focus to the disabled text widget, you can then select and copy text and the highlighting will show.

As for the cursor disappearing... arguably, that's what's supposed to happen. The cursor tells the user "this is where text will get inserted". Since no text will get inserted, having that visual clue would be confusing to the user. What you could do instead, if it was really important, is to insert a small image wherever they click to simulate the cursor.

To answer your question about whether the widget actually uses the insert and delete methods: the methods on the actual underlying widget are what the default bindings use, so overriding them in a subclass has no effect. You would need to redo all the default bindings for that to work. It's doable, but a lot of work.

Unfortunately, this is one area where programming in Tcl really shines, because you can simply disable the insert and delete commands of the widget. Of course, you can do that directly in Tkinter also since ultimately it runs tcl code to do everything, but that would involve writing some tcl code which is not a very good solution from the perspective of a Python coder.

I think the best solution is to use the disabled state, then add in just enough bindings to do what you want.

Here's a simple example that works by explicitly setting focus on a mouse button click. With this code I'm able to click and swipe to select a region, or double- or triple-click to select words and lines:

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()
迷雾森÷林ヴ 2024-12-17 07:29:23

@BryanOakley 由于我没有 Mac,所以我花了一段时间来测试你的建议。
不幸的是,Python 的 Mac 实现存在缺陷。
我添加了焦点,即我在创建窗口并插入文本后调用的禁用函数,现在首先调用:

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

然后

self.txt.focus_set()

是我认为您建议的内容。

它“有点”有效。即:选择文本(单击并拖动或双击)时,突出显示大多数情况下都有效。 Python 一定有一些错误的内存引用或此类错误:有时突出显示一开始不起作用,然后在更多单击后它开始工作(在同一窗口中)。有时,当程序被调用时,它会在蝙蝠的右侧工作。有时使用 Shift-rightArrow 键选择可以,但使用鼠标选择则不行。然后再次开始工作。或者它在一个窗口中可以正常工作,但在另一个窗口中不能正常工作(两者都属于同一类),然后开始在所有窗口中工作......等等......

好处是添加焦点并没有对 Windows 产生严重影响(即所有工作和没有对焦一样好。
我想在这一点上我只希望 Mac 版 Python 的未来/下一个版本能够修复这些错误。

顺便说一句,对于 Python 来说,Mac 似乎有点孤儿。 Windows 的实现要丑陋得多。我的意思是字体、按钮等看起来更糟糕。或者可能是由于不同的屏幕分辨率和 Python 端口不能很好地解释这些问题。 无论如何都不确定

。感谢您对在 Mac 上使用 focus 的帮助和建议。

@BryanOakley It took me a while to test your suggestion since I have no Mac.
Unfortunately Mac implementation of Python is buggy.
I've added focus, ie my disable function which I call after creating a window and inserting text, now calls first:

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

and then

self.txt.focus_set()

Which is what I think you've suggested.

It "kind of" worked. Ie: when selecting text (click and drag or double-click) highlighting works most of the time. Python must have some bad memory references or such bugs: Sometimes highlighting doesn't work at first, then it starts working (in the same window) after more clicking. Sometimes when program is invoked it works right of the bat. Sometimes selecting with Shift-rightArrow key will work but selecting with the mouse will not. Then starts working again. Or it will work fine in one window but not in another one (both of the same class), then starts working in all windows...etc...

The good thing is that adding focus did not affect badly Windows (ie all works fine as without focus.
I guess at this point I will just hope that future/next release of Python for Mac will fix those bugs..

BTW, it seems that Mac is a bit of an orphan for Python. Implementation is much uglier then for Windows. I mean the fonts look worse, the buttons, etc.. Or it could be due to different screen resolutions and Python ports that poorly account for those. Not sure

Anyway. Thank you for your help and suggestion to use focus for Mac.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文