我正在使用Python和Tkinter UI编写程序。我想要一个没有标题栏的小窗口。该窗口必须接收键盘输入。无论是以Entry部件的形式还是绑定到KeyPress事件。通常使用overrideredirect(True)
来禁用标题栏。但是,不幸的是,(除了Windows),这似乎会阻止许多事件被接收。我编写了以下代码来说明问题:
#!/usr/bin/env python
from __future__ import print_function
import Tkinter
class AppWindow(Tkinter.Tk):
def __init__(self, *args, **kwargs):
Tkinter.Tk.__init__(self, *args, **kwargs)
self.overrideredirect(True)
self.geometry("400x25+100+300")
titleBar = Tkinter.Frame(self)
titleBar.pack(expand = 1, fill = Tkinter.BOTH)
closeButton = Tkinter.Label(titleBar, text = "x")
closeButton.pack(side = Tkinter.RIGHT)
closeButton.bind("<Button-1>", lambda event: self.destroy())
self.bind("<KeyPress>", lambda event: print("<KeyPress %s>" % event.char))
self.bind("<Button-1>", lambda event: print("<Button-1>"))
self.bind("<Enter>", lambda event: print("<Enter>"))
self.bind("<Leave>", lambda event: print("<Leave>"))
self.bind("<FocusIn>", lambda event: print("<FocusIn>"))
self.bind("<FocusOut>", lambda event: print("<FocusOut>"))
if __name__ == "__main__":
app = AppWindow()
app.mainloop()
这会创建一个小窗口(没有标题栏),当它接收到常见事件时会打印出它们的名称。我已经在Windows 7、Mac OSX(El Capitan)和Ubuntu 14.04.1上运行了此脚本。我只在虚拟机(VMWare)中运行了Ubuntu。
在Windows中,这似乎按预期工作。所有我的代码测试的事件都可以被接收。
在Ubuntu中,Tkinter窗口如预期地接收
<Enter>
、<Leave>
和<Button-1>
事件,但<KeyPress>
、<FocusIn>
和<FocusOut>
从未被接收。事实上,即使窗口已经被单击,仍然会继续将焦点保留在最后一个具有焦点的窗口上。在OSX中,Tkinter窗口如预期地接收
<Button-1>
事件,但<KeyPress>
、<FocusIn>
和<FocusOut>
从未被接收。最后一个具有焦点的窗口不会像在Ubuntu中那样继续接收键盘输入。<Enter>
和<Leave>
事件的行为有些奇怪。只有在单击窗口后,才会接收到<Enter>
事件。然后,一旦发生了<Leave>
事件,需要再次单击窗口才能接收到另一个<Enter>
事件。
我还尝试了在__init__
函数结束前加入self.focus_force()
。这会导致程序启动时窗口接收到一个<FocusIn>
事件,但从未接收到进一步的<KeyPress>
、<FocusIn>
或<FocusOut>
事件。
最终,我的问题是这样的:是否有任何方法可以在OSX和Linux中隐藏标题栏但继续接收键盘输入?
我知道还有其他几个与此相同问题有关的问题。在这三个问题中:
- python tkinter overrideredirect; cannot receive keystrokes (Linux)
- root.overrideredirect and <Any-KeyPress> binding
- How to bind Tkinter destroy() to a key in Debian?
self.attributes('-fullscreen', True)
,但这对我来说不起作用,因为我想要一个小窗口,而不是全屏应用程序。还有一个问题:Tkinter overrideredirect no longer receiving event bindings。这似乎非常接近我的问题,但提供的细节较少,没有答案。
更新:我一直在尝试调查我的问题的基本机制。我知道Tkinter是Tcl/Tk的包装器,所以我想尝试用Tcl重写我的代码。我不太了解Tcl,但我认为我已经成功(或多或少)地将我的Python代码翻译成了Tcl。
#!/usr/bin/env wish
wm overrideredirect . True
wm geometry . "400x25+100+300"
bind . <KeyPress> {puts "<KeyPress %K>"}
bind . <Button-1> {puts "<Button-1>"}
bind . <Enter> {puts "<Enter>"}
bind . <Leave> {puts "<Leave>"}
bind . <FocusIn> {puts "<FocusIn>"}
bind . <FocusOut> {puts "<FocusOut>"}
我在Windows和Mac OSX中尝试了生成的程序。在Windows中,我收到了<KeyPress>
事件,但在OSX中没有收到。没有wm overrideredirect . True
这行命令,OSX就可以接收<KeyPress>
事件。因此,看起来问题不在于Python,而是在于Tcl/Tk。
mainloop
和如何再次访问它?
绑定(键监听)仅适用于子元素。如果listener
被冻结,您将获得一个ghost
应用程序。 - dsgdfgdeiconify()
)! - dsgdfg