Piszę program w Pythonie z interfejsem użytkownika Tkinter. Chcę mieć małe okno bez paska tytułu. To okno musi odbierać dane z klawiatury. Nie jestem wybredny, czy ma to postać widżetu wpisowego, czy tylko wiążącego się z KeyPress. overrideredirect(True)
to zazwyczaj sposób wyłączania paska tytułu. Niestety, (z wyjątkiem Windows) wydaje się, że nie można odbierać wielu zdarzeń. Napisałem ten kod do zilustrowania problemu:Overrideredirect Tkintera zapobiega niektórym zdarzeniom w systemie Mac i Linux
#!/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()
Stwarza to małe okienko (bez paska tytułowego), który drukuje nazwę wspólnych imprez, gdy otrzyma je. Uruchomiłem ten skrypt na Windows 7, Mac OSX (El Capitan) i Ubuntu 14.04.1. Uruchomiłem tylko Ubuntu na wirtualnej maszynie (VMWare).
W systemie Windows wygląda na to, że działa poprawnie. Wszystkie zdarzenia, na które mój kod testuje, mogą zostać odebrane.
W Ubuntu, okna Tkinter odbiera
<Enter>
,<Leave>
i<Button-1>
wydarzenia jak oczekiwano, ale<KeyPress>
,<FocusIn>
i<FocusOut>
nigdy nie są odbierane. W rzeczywistości, nawet po kliknięciu okna, ostatnie okno z fokusem kontynuuje otrzymywanie naciśnięć klawiszy.W OSX, okna Tkinter odbiera
<Button-1>
wydarzenia jak oczekiwano, ale<KeyPress>
,<FocusIn>
i<FocusOut>
nigdy nie są odbierane. Ostatnie okno z fokusem nie kontynuuje odbierania naciśnięć klawiszy, tak jak w Ubuntu. Zdarzenia<Enter>
izachowują się trochę dziwnie. Zdarzenie<Enter>
nie zostanie odebrane, dopóki okno nie zostanie kliknięte. Następnie, po wystąpieniu zdarzenia<Leave>
, okno musi zostać ponownie kliknięte, aby odebrać kolejne zdarzenie<Enter>
.
Próbowałem również self.focus_force()
tuż przed końcem funkcji __init__
. Powoduje to, że okno odbiera zdarzenie <FocusIn>
podczas uruchamiania programu, ale żadne dalsze zdarzenia nie są nigdy odbierane.
W końcu moje pytanie brzmi następująco: czy istnieje sposób na ukrycie paska tytułu, ale nadal otrzymujesz dane z klawiatury w systemach OSX i Linux?
Jestem świadomy kilku innych pytań dotyczących tego samego problemu. W tych trzech pytań:
- python tkinter overrideredirect; cannot receive keystrokes (Linux)
- root.overrideredirect and <Any-KeyPress> binding
- How to bind Tkinter destroy() to a key in Debian?
Zaakceptowanych odpowiedź jest użycie self.attributes('-fullscreen', True)
, które nie będą pracować dla mnie jak chcę to malutkie okna, a nie aplikacja pełnoekranowa.
Jest jeszcze jedno pytanie: Tkinter overrideredirect no longer receiving event bindings. Wydaje się to bardzo bliskie mojemu pytaniu, ale zawiera mniej szczegółów i nie ma odpowiedzi.
Aktualizacja: I zostały próby zbadania mechanizmu leżącego u podstaw mojego problemu. Wiem, że Tkinter jest opakowaniem wokół Tcl/Tk, więc pomyślałem, że spróbuję przepisać mój kod w Tcl. I naprawdę nie wiem, Tcl, ale myślę, że udało mi się (mniej lub bardziej) przetłumaczyć moją 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>"}
Próbowałem wynikowy program w systemie Windows i Mac OSX. W systemie Windows otrzymałem <KeyPress>
zdarzeń, ale w systemie OSX nie. Bez linii wm overrideredirect . True
system OSX odbiera zdarzenia <KeyPress>
. Dlatego wygląda na to, że ten problem nie występuje w Pythonie, ale w Tcl/Tk.
Wyłączyć 'mainloop' i' jak uzyskać do niego dostęp ponownie? 'Binding (key listen) działa z elementami podrzędnymi. Zyskałeś aplikację 'ghost', jeśli' listener' jest 'zamrożony'. – dsgdfg
Sztuczki: Ustaw swój przycisk [X] jako mainloop (a więc 'deiconify()')! – dsgdfg