Frage Tkinter's overrideredirect verhindert bestimmte Ereignisse in Mac und Linux


Ich schreibe ein Programm in Python mit einem Tkinter UI. Ich möchte ein kleines Fenster ohne Titelleiste haben. Dieses Fenster muss Tastatureingabe erhalten. Ich bin nicht wählerisch, ob dies in Form eines Entry-Widgets oder nur Bindung an KeyPress ist. overrideredirect(True) In der Regel ist die Titelleiste deaktiviert. Leider scheint dies (außer in Windows) zu verhindern, dass viele Ereignisse empfangen werden. Ich habe diesen Code geschrieben, um das Problem zu veranschaulichen:

#!/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()

Dadurch wird ein kleines Fenster (ohne Titelleiste) erstellt, das den Namen gemeinsamer Ereignisse beim Empfang ausgibt. Ich habe dieses Skript unter Windows 7, Mac OSX (El Capitan) und Ubuntu 14.04.1 ausgeführt. Ich habe nur Ubuntu in einer virtuellen Maschine (VMWare) ausgeführt.

  • In Windows scheint dies wie erwartet zu funktionieren. Alle Ereignisse, für die mein Code testet, können empfangen werden.

  • In Ubuntu erhält das Tkinter-Fenster <Enter>, <Leave>, und <Button-1> Ereignisse wie erwartet, aber <KeyPress>, <FocusIn>, und <FocusOut> werden nie empfangen. Sogar nachdem das Fenster angeklickt wurde, erhält das letzte Fenster mit Fokus weiterhin die Tastendrücke.

  • In OSX empfängt das Tkinter-Fenster <Button-1> Ereignisse wie erwartet, aber <KeyPress>, <FocusIn>, und <FocusOut> werden nie empfangen. Das letzte Fenster mit Fokus erhält keine Tastenbetätigungen wie in Ubuntu. Das <Enter> und <Leave> Ereignisse verhalten sich etwas merkwürdig. Das <Enter> Das Ereignis wird erst empfangen, wenn auf das Fenster geklickt wird. Dann, einmal <Leave> Ereignis tritt auf, das Fenster muss erneut angeklickt werden, um ein anderes zu erhalten <Enter> Veranstaltung.

Ich habe es auch versucht self.focus_force() kurz vor dem Ende der __init__ Funktion. Dies führt dazu, dass das Fenster a erhält <FocusIn> Ereignis, wenn das Programm startet, aber nicht weiter <KeyPress>, <FocusIn>, oder <FocusOut> Ereignisse werden nie empfangen.

Letztendlich ist meine Frage: Gibt es eine Möglichkeit, die Titelleiste zu verbergen, aber weiterhin Tastatureingaben in OSX und Linux zu erhalten?


Mir sind einige andere Fragen bekannt, die sich mit demselben Problem befassen. In diesen drei Fragen:

Die akzeptierte Antwort ist zu verwenden self.attributes('-fullscreen', True), die für mich nicht funktioniert, da ich ein kleines kleines Fenster, keine Vollbildanwendung möchte.

Es gibt noch eine andere Frage: Tkinter overrideredirect empfängt keine Ereignisbindungen mehr. Das kommt meiner Frage sehr nahe, liefert aber weniger Details und hat keine Antwort.


Aktualisieren: Ich habe versucht, den zugrunde liegenden Mechanismus meines Problems zu untersuchen. Ich weiß, dass Tkinter ein Wrapper um Tcl / Tk ist, also dachte ich, ich würde versuchen, meinen Code in Tcl umzuschreiben. Ich kenne Tcl nicht wirklich, aber ich glaube, es ist mir gelungen, mein Python (mehr oder weniger) zu übersetzen:

#!/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>"}

Ich habe das resultierende Programm in Windows und Mac OSX ausprobiert. In Windows habe ich empfangen <KeyPress> Ereignisse, aber in OSX habe ich nicht. Ohne das wm overrideredirect . True Zeile, OSX empfängt die <KeyPress> Veranstaltungen. Daher sieht es so aus, als ob dieses Problem nicht bei Python, sondern bei Tcl / Tk liegt.


13
2018-01-03 23:02


Ursprung


Antworten:


Ich habe Tk einen Fehlerbericht für diese Situation geschickt.

Du kannst den ... benutzen devilspie Programm, um die Dekorationen aus Ihrem Fenster zu entfernen. Benutze die wm title . myname Befehl geben Sie Ihrem Fenster einen bestimmten Namen und verwenden Sie diesen Namen in der devilspie Konfigurationsfragment unten. Entferne das overrideredirect Befehl von Ihrem Programm.

Ich habe dies getestet (als Tk-Programm), und das undekorierte Fenster wird weiterhin den Tastendruck & etc. Erhalten. Bindungen.

Beachten Sie, dass devilspie wird als Daemon-Prozess geschrieben und bleibt aktiv. Der Daemon kann nach dem Start gelöscht werden und das Fenster ändert sich. Oder es kann ausgeführt werden, und jedes Mal, wenn Ihr Fenster aktiviert ist, wird die devilspie Konfiguration wird angewendet.

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

3
2017-08-25 18:13