【问题标题】:python - entry.focus_set() not working in tkinterpython - entry.focus_set() 在 tkinter 中不起作用
【发布时间】:2017-09-25 17:53:40
【问题描述】:

我有一个条目、一个列表框(下拉列表)和另一个列表框。每当在条目中键入超过 3 个字符时。查找完成列表并将其插入到下拉列表中,然后显示下拉列表。如果从下拉列表中选择了一个项目。它的值应该被插入到列表框中并从下拉列表中删除,并且该条目应该再次获得焦点。但事实并非如此。

这是我的代码:

from tkinter import *


class Autocomplete(Frame, object):
    def __init__(self, *args, **kwargs):
        super(Autocomplete, self).__init__(*args, **kwargs)
        self.text = StringVar()
        self.entry = Entry(self, textvariable=self.text)
        self.frame = Frame(self)
        self.listbox = Listbox(self.frame)
        self.dropdown = Listbox(self.frame)

    def build(self):
        self.text.trace("w", lambda name, index, mode: self._update_dropdown())
        self.entry.focus_set()
        self.entry.pack()
        self.frame.pack()
        self.listbox.grid(column=0, row=0, sticky=N)
        self.dropdown.bind("<<ListboxSelect>>", lambda event: self._select_entry())
        self.dropdown.grid(column=0, row=0, sticky=N)
        self.dropdown.grid_forget()
        return self

    def _shorten_dropdown(self, index):
        self.dropdown.grid_forget()
        self.dropdown.delete(index)
        self.dropdown["height"] -= 1
        self.dropdown.selection_clear(0, END)
        self.dropdown.grid(column=0, row=0, sticky=N)

    def _select_entry(self):
        index = int(self.dropdown.curselection()[0])
        value = self.dropdown.get(index)
        self._shorten_dropdown(index)
        self.entry.focus_set()

这是最少的代码。 Here 是可测试的版本。下面是构建自动完成实例的代码:

from tkinter import *
from autocomplete import Autocomplete

listt = ["a","aa","aaa","ab","bba","aba","abbnb","cd","c","abc","abcd"]
root = Tk()

autocomplete_frame = Autocomplete(
    60,
    10,
    listt
).build()
autocomplete_frame.pack()

mainloop()

【问题讨论】:

  • 您的代码不可测试。我们需要能够复制粘贴您的代码并查看您的问题。请提供Minimal, Complete, and Verifiable example,以便我们测试您的代码。
  • 指向您的“可测试版本”的链接仍然不可测试。您如何创建Autocomplete() 的对象实例。没有调用该类的代码。您无需提供所有代码。只是一个 MCVE。这只需要包括有问题的方法以及您如何创建 tkinter 实例。您的代码中没有 Tk()mainloop(),它是 tkinter 运行所必需的。我们需要能够复制粘贴您的示例,而不必猜测您是如何实现您的课程的。
  • 您拥有的第二个链接应该是您原始问题代码的一部分。
  • abc"" 中的拼写错误 listt 是您原始代码的一部分吗?这可能会导致问题。
  • 没关系。我刚刚注意到您问题中的类型,所以我想我应该指出它以防万一。至于你的代码的其余部分,我在尝试实现你的类时遇到了引用错误。这条线super(Autocomplete, self).__init__(*args, **kwargs) 引起了问题。 TypeError: __init__() takes from 1 to 3 positional arguments but 4 were given

标签: python tkinter focus


【解决方案1】:

因此,我必须更改一些内容才能使其至少在一个单词上起作用。目前,如果您希望继续在连续字符串中输入更多单词,它将不起作用。

我确信我最终也可以让它工作,但我正在尝试回答从列表框中更新单词并将焦点重新回到输入字段的问题。

我不得不改变几件事。

首先我必须改变:

index = int(self.dropdown.curselection()[0])

收件人:

index = self.dropdown.curselection()[0]

因为self.dropdown.curselection()[0] 的返回值已经是一个int。不需要再把整数变成整数。

第二个我必须改变:

def _add_course(self, value):
    self.listbox.insert(END, value)
    self.my_list.append(value)

收件人:

def _add_course(self, value):
    self.entry.delete(0,END)
    self.entry.insert(END, value)
    self.my_list.append(value)

当您尝试将value 插入列表框而不是输入字段时。另请注意,我将 self.list 更改为 self.my_list`。你应该避免命名可能覆盖内置函数的东西。

我需要更改的最后一件事是我们如何将焦点设置回输入字段。我相信焦点的问题在于您将焦点设置在鼠标单击上,但是您仍在单击列表框并且正在获得焦点。我们需要为焦点集添加延迟,以便我们有时间在焦点设置到输入字段之前完成鼠标单击。

变化:

self.entry.focus_set()

到:

self.master.after(200, lambda: self.entry.focus())

将焦点设置回输入字段的替代方法是将bind() 按钮释放事件改为焦点命令。

你也可以像这样强制聚焦:

self.dropdown.bind("<ButtonRelease-1>", lambda x: self.entry.focus())

以下代码应该可以解决您的主要问题:

from tkinter import *

class Autocomplete(Frame, object):
    def __init__(self, width, height, entries, *args, **kwargs):
        super(Autocomplete, self).__init__(*args, **kwargs)
        self.my_list = []
        self._entries = entries
        self.listbox_height = height
        self.entry_width = width
        self.text = StringVar()
        self.entry = Entry(self, textvariable=self.text, width=self.entry_width)
        self.frame = Frame(self)
        self.listbox = Listbox(self.frame, height=self.listbox_height, width=self.entry_width)
        self.dropdown = Listbox(self.frame, height=self.listbox_height, width=self.entry_width, background="#cfeff9")

    def build(self):
        self.text.trace("w", lambda name, index, mode: self._update_dropdown())
        self.entry.focus_set()
        self.entry.pack()
        self.frame.pack()
        self.listbox.grid(column=0, row=0, sticky=N)
        self.dropdown.bind("<<ListboxSelect>>", lambda event: self._select_entry())
        self.dropdown.grid(column=0, row=0, sticky=N)
        self.dropdown.grid_forget()
        return self

    def _update_dropdown(self):
        self.dropdown["height"] = self.listbox_height
        self.dropdown.delete(0, END)
        text = self.text.get()
        print("update: " + text)
        if len(text) < 3:
            self.dropdown.grid_forget()
            return
        else:
            for entry in self._entries:
                if entry not in self.my_list and text.lower() in entry.lower():
                    self.dropdown.insert(END, entry)
        listbox_size = self.dropdown.size()
        if not listbox_size:
            self.dropdown.insert(END, "No results found for '{}'".format(text))
            self.dropdown["height"] = 1
        else:
            if listbox_size <= self.dropdown["height"]:
                self.dropdown["height"] = listbox_size
        self.dropdown.grid(column=0, row=0, sticky=N)

    def _shorten_dropdown(self, index):
        print("shorten: {}".format(str(index)))
        self.dropdown.grid_forget()
        self.dropdown.delete(index)
        if self.dropdown["height"] == 1:
            self.dropdown.insert(END, "No more results found for '{}'".format(self.text.get()))
        else:
            self.dropdown["height"] -= 1
        self.dropdown.selection_clear(0, END)
        self.dropdown.grid(column=0, row=0, sticky=N)

    def _select_entry(self):
        index = self.dropdown.curselection()[0]
        value = self.dropdown.get(index)
        print(value)
        if "results found for" in value:
            print("return")
            return
        print("select: {}".format(value))
        self._shorten_dropdown(index)
        self._add_course(value)
        self.master.after(200, lambda: self.entry.focus())

    def _add_course(self, value):
        self.entry.delete(0,END)
        self.entry.insert(END, value)
        self.my_list.append(value)



listt = ["a","aa","aaa","ab","bba","aba","abbnb","cd","c","abc","abcd"]
root = Tk()

autocomplete_frame = Autocomplete(60, 10, listt).build()
autocomplete_frame.pack()

mainloop()

【讨论】:

  • 哇,迈克!你真的尽力帮忙了。寿,你做的比我需要的多得多,这可能是我没有正确解释我的目标和问题。对于第一次编辑,我知道最好删除 int() 但无论如何我都没有收到任何错误。再次将 int 强制转换为 int 一定不是错误。对于第二次编辑,我认为你弄错了我的目标。该值不应插入到应插入第二个列表框的条目中。但这没关系。感谢您提供有关命名的提示。我会记住这一点。关于延迟的事情是我的问题。你帮我修好了!>:D
  • @aran:你的问题有点乱,所以我按照我认为你的目标工作。对困惑感到抱歉。看看我对焦点部分的更新。我为您可能更喜欢使用的焦点部分添加了第二个选项。
  • 是的。这实际上更好。谢谢:)
  • @aran:关于列表框的事情。我在您的代码中只看到一个列表框。如果您可以更具体一点,我也可以回答这个问题。
  • 我有两个列表框。一个名为 listbox,另一个名为 dropdown。这没有问题。现在一切都很好:)
猜你喜欢
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多