Tôi đang viết một chương trình bằng Python với giao diện người dùng Tkinter. Tôi muốn có một cửa sổ nhỏ không có thanh tiêu đề. Cửa sổ này phải nhận đầu vào bàn phím. Tôi không cầu kỳ cho dù điều này là trong các hình thức của một phụ tùng nhập cảnh hoặc chỉ cần ràng buộc để KeyPress. overrideredirect(True)
thường là cách tắt thanh tiêu đề. Thật không may, (ngoại trừ trong Windows), điều này dường như để ngăn chặn nhiều sự kiện nhận được. Tôi đã viết mã này để minh họa sự cố:Tách tắt của Tkinter ngăn chặn các sự kiện nhất định trong Mac và 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()
Điều này tạo ra một cửa sổ nhỏ (không có thanh tiêu đề) in tên sự kiện phổ biến khi nhận được sự kiện. Tôi đã chạy tập lệnh này trên Windows 7, Mac OSX (El Capitan) và Ubuntu 14.04.1. Tôi chỉ chạy Ubuntu trong một máy ảo (VMWare).
Trong Windows, điều này dường như hoạt động như mong đợi. Tất cả các sự kiện mà kiểm tra mã của tôi có thể được nhận.
Trong Ubuntu, cửa sổ Tkinter nhận
<Enter>
,<Leave>
, và<Button-1>
sự kiện như mong đợi, nhưng<KeyPress>
,<FocusIn>
, và<FocusOut>
không bao giờ nhận được. Trong thực tế, ngay cả sau khi cửa sổ đã được nhấp vào, cửa sổ cuối cùng với tiêu điểm tiếp tục nhận được các phím bấm.Trong OSX, cửa sổ Tkinter nhận
<Button-1>
sự kiện như mong đợi, nhưng<KeyPress>
,<FocusIn>
, và<FocusOut>
không bao giờ nhận được. Cửa sổ cuối cùng với tiêu điểm không tiếp tục nhận các lần nhấn phím như trong Ubuntu. Các sự kiện<Enter>
và<Leave>
hoạt động một cách kỳ lạ. Sự kiện<Enter>
không được nhận cho đến khi cửa sổ được nhấp. Sau đó, khi sự kiện<Leave>
xảy ra, cửa sổ cần được nhấp lại để nhận sự kiện<Enter>
khác.
Tôi cũng đã thử self.focus_force()
ngay trước khi kết thúc chức năng __init__
. Điều này làm cho cửa sổ nhận được sự kiện <FocusIn>
khi chương trình bắt đầu nhưng không nhận được thêm <KeyPress>
, <FocusIn>
hoặc <FocusOut>
sự kiện không bao giờ được nhận.
Cuối cùng, câu hỏi của tôi là: có cách nào để ẩn thanh tiêu đề nhưng tiếp tục nhận đầu vào bàn phím trong OSX và Linux không?
Tôi biết một số câu hỏi khác liên quan đến cùng vấn đề này. Trong ba câu hỏi sau:
- python tkinter overrideredirect; cannot receive keystrokes (Linux)
- root.overrideredirect and <Any-KeyPress> binding
- How to bind Tkinter destroy() to a key in Debian?
Câu trả lời được chấp nhận là sử dụng self.attributes('-fullscreen', True)
, mà sẽ không làm việc cho tôi khi tôi muốn có một cửa sổ nhỏ bé, không phải là một ứng dụng toàn màn hình.
Có một câu hỏi khác: Tkinter overrideredirect no longer receiving event bindings. Điều này dường như rất gần với câu hỏi của tôi, nhưng cung cấp ít chi tiết hơn và không có câu trả lời.
Cập nhật: Tôi đã cố gắng để điều tra về cơ chế cơ bản của vấn đề của tôi. Tôi biết rằng Tkinter là một wrapper xung quanh Tcl/Tk, vì vậy tôi nghĩ rằng tôi sẽ cố gắng viết lại mã của tôi trong Tcl. Tôi không thực sự biết Tcl, nhưng tôi nghĩ rằng tôi đã quản lý (nhiều hay ít) dịch Python của mình:
#!/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>"}
Tôi đã thử chương trình kết quả trong Windows và Mac OSX. Trong Windows, tôi nhận được <KeyPress>
sự kiện, nhưng trong OSX thì không. Nếu không có đường dây wm overrideredirect . True
, OSX sẽ không nhận được sự kiện <KeyPress>
. Vì vậy, có vẻ như vấn đề này không phải là với Python, nhưng với Tcl/Tk.
Tắt 'mainloop' và' cách truy cập lại lần nữa? 'Binding (key listen) hoạt động với các phần tử phụ. Bạn đã đạt được một ứng dụng 'ghost' nếu' listener' là 'frozen'. – dsgdfg
Một thủ thuật: Làm cho nút [X] của bạn thành vòng lặp chính (do đó, 'deiconify()')! – dsgdfg