Tkinter的overrideredirect可以防止Mac和Linux中的某些事件

我正在用Tkinter UI编写Python程序。 我想有一个没有标题栏的小窗口。 该窗口必须接收键盘input。 我不挑剔这是否是一个Entry小部件的forms,或者只是绑定到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() 

这会创build一个小窗口(没有标题栏),当它接收到这些窗口时,会显示常见事件的名称。 我已经在Windows 7,Mac OSX(El Capitan)和Ubuntu 14.04.1上运行这个脚本。 我只在一台虚拟机(VMWare)上运行Ubuntu。

我也在__init__函数结束之前尝试了self.focus_force() 。 这会导致窗口在程序启动时收到一个<FocusIn>事件,但不会再收到<KeyPress><FocusIn><FocusOut>事件。

最终,我的问题是:是否有任何方法来隐藏标题栏,但继续在OSX和Linux接收键盘input?


我知道还有一些其他问题涉及这个相同的问题。 在这三个问题中:

  • python tkinter overrideredirect; 无法接收按键(Linux)
  • root.overrideredirect和<Any-KeyPress>绑定
  • 如何将Tkinter destroy()绑定到Debian中的某个键?

接受的答案是使用self.attributes('-fullscreen', True) ,这对我不起作用,因为我想要一个小窗口,而不是全屏应用程序。

还有一个问题: Tkinter overrideredirect不再接收事件绑定 。 这似乎与我的问题非常接近,但提供的细节不多,没有答案。


更新:我一直在试图调查我的问题的基本机制。 我知道Tkinter是Tcl / Tk的包装,所以我想我会尝试在Tcl中重写我的代码。 我不是很了解Tcl,但是我想我已经(或多或less地)翻译了我的Python:

 #!/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 wm overrideredirect . True line,OSX确实收到<KeyPress>事件。 因此,看起来这个问题不是Python,而是Tcl / Tk。

对于这种情况,我已经向Tk提交了一个错误报告。

您可以使用devilspie程序从您的窗口中删除装饰品。 使用wm title . myname wm title . myname命令给你的窗口一个特定的名字,并在下面的devilspie配置片段中使用这个名字。 从您的程序中删除overrideredirect命令。

我已经测试了这个(作为一个Tk程序),未修饰的窗口仍然会收到按键等。 绑定。

请注意, devilspie被写为守护进程并保持活动状态。 守护进程可以在启动后被杀死,窗口的改变仍然有效。 或者它可以保持运行,并且任何时候您的窗口被激活, devilspie配置将被应用。

 (if (is (application_name) "t.tcl") (begin (undecorate)))