【发布时间】:2021-05-25 18:47:16
【问题描述】:
我制作了一个 Tkinter 小部件,它本质上是一个 Combobox,其列表 1) 在打字期间可见,2) 在打字期间缩短,3) 允许箭头键/输入功能。我使用这两个帖子(first 和second)来找出一些功能。请参阅下面的课程代码和 MRE。
我的问题:我的 Search 小部件适用于 Windows,但不适用于 Mac OS,我相信这是因为 .wm_overrideredirect() 方法在 Mac OS 中的行为不同(至少对于大苏尔)与 Windows。我的预期功能是让TopLevel 小部件仅包含并显示Text 小部件而不接收焦点。下面的代码在 Windows 中实现了这一点,但在 Mac OS 中却没有。 Mac OS 的替代品是什么?换句话说,是否有任何替代方法可以让小部件扩展到root 之外?
在 Windows 10 上运行时单击条目小部件会执行以下操作:
在 Mac OS Big Sur 上运行时单击条目小部件会执行以下操作:
谢谢!
搜索小部件
from tkinter import Entry, Text, StringVar, Toplevel, WORD, END
class Search:
'''A widget with features of Entry and Combobox that allows for a dropdown list
that 1) dynamically reduces listed options to those that match user input and
2) allows for arrow key/enter and mouseover/click functionality.'''
def __init__(self, root, lst, width=15, allow_unlisted=True):
self.root = root
self.lst = lst
self.current_lst = lst
self.width = width
self.allow_unlisted = allow_unlisted
self.indices = [0.0] * 2
self.stringvar = StringVar()
self.stringvar.trace_add("write", self.updateList)
self.entry = Entry(root, width=self.width, font=("Arial", 9), textvariable=self.stringvar)
self.entry.bind("<FocusIn>", self.showList)
self.entry.bind("<FocusOut>", self.hideList)
self.entry.bind("<Up>", self.keyList)
self.entry.bind("<Down>", self.keyList)
self.entry.bind("<Return>", self.hideList)
self.toplevel = None
self.text = None
self.updateList()
def showList(self, *args):
self.toplevel = Toplevel(self.root)
self.toplevel.wm_overrideredirect(True)
x = self.entry.winfo_rootx()
y = self.entry.winfo_rooty() + self.entry.winfo_height()
self.toplevel.wm_geometry(f"+{x}+{y}")
self.text = Text(self.toplevel, wrap=WORD, foreground="#333333")
self.text.config(font=("Arial", 9), width=self.width)
self.text.tag_configure("highlight", background="dodger blue", foreground="white")
self.text.bind("<Motion>", self.motionList)
self.text.bind("<Up>", self.keyList)
self.text.bind("<Down>", self.keyList)
self.text.bind("<Button-1>", self.hideList)
self.text.bind("<Return>", self.hideList)
self.text.pack()
self.updateList()
def hideList(self, *args):
if self.text and self.text.winfo_ismapped():
self.select()
if self.toplevel:
self.toplevel.destroy()
self.toplevel = self.text = None
self.root.focus_set()
def updateList(self, *args):
var = self.stringvar.get()
self.indices = [0.0] * 2
self.current_lst = [item for item in self.lst if var.lower() in item.lower()]
if self.text:
self.text.tag_remove("highlight", 1.0, END)
self.text.config(height=min(10, len(self.current_lst)))
self.text.delete(1.0, END)
self.text.insert(END, "\n".join(self.current_lst))
def motionList(self, event):
index1 = float(self.text.index(f"@{event.x},{event.y} linestart"))
self.highlight(index1)
def keyList(self, event):
if event.keysym == "Up" and self.indices[0] > 0:
self.indices[0] -= 1
elif event.keysym == "Down" and self.indices[0] < len(self.current_lst):
self.indices[0] += 1
if self.indices[0]:
self.highlight(self.indices[0])
else:
self.indices = [0.0] * 2
self.text.tag_remove("highlight", 1.0, END)
def highlight(self, index1):
self.indices = [index1, float(self.text.index(f"{index1} lineend"))]
self.text.tag_remove("highlight", 1.0, END)
self.text.tag_add("highlight", *self.indices)
def select(self, *args):
if self.indices[0]:
self.stringvar.set(self.text.get(*self.indices))
def get(self):
user_input = self.stringvar.get()
if user_input in self.lst or self.allow_unlisted:
return user_input
else: return ""
def set(self, user_input):
self.stringvar.set(user_input)
def __getattr__(self, name):
return lambda *args, **kwargs: getattr(Entry, name)(self.entry, *args, **kwargs)
MRE
from tkinter import Tk, Label
from Search import Search # or however you want to import this
# example options for widget
options = ["Option 1", "Option 2", "Option 3", "Rabala", "Ploplepla",
"This is a very long option compared to others",
"OPTION 1", "option 2", "option 3", "option1", "option2",
"option3", "oPTION1"]
root = Tk()
l0 = Label(root, text="Widget:")
r = Search(root, lst=options)
l0.grid(row=0, column=0, padx=10, pady=50)
r.grid(row=0, column=1, padx=10, pady=50)
root.mainloop()
【问题讨论】:
-
为什么你认为这在 Big Sur 上不起作用?它似乎对我有用。这种行为与其他平台上的行为有何不同?
-
您是否尝试过使用:
<tkinter.Tk/Toplevel>.attributes("-type", "splash")?我没有 MacOS 设备来测试它,但我认为它应该可以工作。 -
@BryanOakley 如果这就是你的意思,它不会在 MacOS 上崩溃。我在上面添加了图片以显示功能差异。
-
@TheLizzard 感谢您的建议,我只是试了一下,得到了这个错误:
_tkinter.TclError: bad attribute "-type": must be -alpha, -fullscreen, -modified, -notify, -titlepath, -topmost, or -transparent。也许这也取决于操作系统? -
我仍然不清楚有什么区别。您是说单击条目(无需键入)应该使下拉菜单出现吗?它对我来说就是这样。