【问题标题】:tkinter dialog highlights parent entry texttkinter 对话框突出显示父条目文本
【发布时间】:2019-01-21 21:29:51
【问题描述】:

我正在尝试复制 Python Idle 的搜索对话框的行为,它突出显示后面的文本。所以我参考了这个链接并制作了我自己的对话:http://effbot.org/tkinterbook/tkinter-dialog-windows.htm

Python Idle Search Dialog

问题是使用self.grab_set(),我无法突出显示调用对话框的父窗口的文本。我不想删除self.grab_set(),因为我也不希望用户在搜索时四处点击。

按钮的 onclick 监听器执行正确,正如我在对话框的其他实现中测试的那样。例如,使用替换对话框正确替换文本。所以唯一的问题是父窗口中的条目文本没有突出显示/选择。实际上,如果我删除self.grab_set(),文本可以突出显示。但是,对话框失去焦点,一旦我这样做,焦点就会转到父窗​​口的条目。而且我无法按 Enter 键在对话框中查找下一个。

我该如何解决这个问题?提前致谢!

My Implementation

---更新---

测试代码可以很简单,如下所示。

from tkinter import *

SYSTEM_HIGHLIGHT = 'SystemHighlight'
BUTTON_BORDER = '#b5b5b5'
class FindDialog(Toplevel):
    def __init__(self, master):
        Toplevel.__init__(self, master)
        self.master = master
        self.transient(master)
        self.grab_set()
        self.geometry("+%d+%d" % (master.winfo_rootx() + 50, master.winfo_rooty() + 50))
        self.title('Search Dialog')

        ## Variables
        self.findListner = None

        self.findLabel = Label(self, text = 'Find:')
        self.findEntry = Entry(self)
        self.findEntry.focus()
        self.findEntry.select_range(0, END)
        for i, w in enumerate([self.findLabel, self.findEntry]):
            w.grid(row = 0, column = i, sticky = NSEW)
        self.findEntry.grid(columnspan = 5)
        self.findButton = Button(self, text = 'Find Next', command = self.find)
        self.findButton.grid(row = 1, column = i + 1, sticky = NSEW)
        self.bind('<Return>', lambda event: self.find())

    def setOnFindListner(self, listener):
        '''listner should have the following arguments: dialog, target, direction.'''
        self.findListner = listener

    def find(self):
        if not self.findListner: return
        self.findListner(self, self.findEntry.get())

def find():
    dialog = FindDialog(root)
    dialog.setOnFindListner(onFind)
    root.wait_window(dialog)

def onFind(*args):
    e.focus_set()
    e.select_range(0, END)
    e.icursor(END)

root = Tk()
e = Entry(root)
e.pack()
e.focus()
e.insert(0, 'HelloWorld')
root.bind('<Control-f>', lambda event: find())
root.mainloop()

【问题讨论】:

  • 请创建一个minimal reproducible example。任何人都很难从这些 sn-ps 拼凑出一个工作程序。创建minimal reproducible example 时,请务必删除重现问题所不需要的所有函数。
  • @BryanOakley 对不起,我很懒惰。我已经更新了这个问题。测试代码的期望行为应该是按 find 选择条目 e 的所有文本。但是,只有在对话框关闭后才会选择它。
  • 我们应该怎么做才能看到问题?如果我输入 control-f 然后输入字母“o”然后回车,会发生什么?此外,我们不需要看到这么多代码块。除非我们应该将所有代码放在一个文件中,否则请只包含一个完整的示例。
  • 期望的行为应该是:我按下对话框的查找,应该选择条目e的整个文本而不关闭对话框。 @BryanOakley
  • 如果不在对话框中输入任何内容,它应该选择条目小部件中的所有内容?

标签: python python-3.x tkinter tkinter-entry python-3.7


【解决方案1】:

Entry 小部件的设计使得只有一个小部件可以具有焦点,并且只有选择的焦点小部件可见。如果没有这个,很容易创建一个用户界面,用户将无法知道键盘事件会去哪里,或者复制事件会复制什么。这可能并非在所有平台上都是正确的,但自从我在 Mac 以外的任何东西上工作以来已经有一段时间了。

如果您的系统允许多个条目小部件显示一个选择,您可以通过确保将所有条目小部件的 exportselection 选项设置为 false 来解决问题。如果您尝试突出显示的小部件是Text 小部件,那应该足够了。从您的问题中不清楚您是否真的需要搜索 Text 小部件或 Entry 小部件,这种区别很重要。

可以说更好的解决方案是使用文本小部件和您自己的自定义标签而不是选择,因为您自己的标签不会有这些限制。您可以使标签看起来与选择相同,或者您可以给它一个不同的外观,以便清楚突出显示的代码具有与用户手动选择的代码不同的行为。

【讨论】:

  • 文字呢?我相信 IDLE 应该用文本来实现。它有没有焦点的文本选择。