Python/Tkinter:如何防止主窗口失焦时退出全屏状态?
Tkinter全屏主窗口弹出子窗口/MessageBox时退出全屏的解决办法
我用Python/Tkinter开发了一款全屏应用,主窗口设置为全屏模式,但调用Toplevel窗口或MessageBox时,主窗口会退出全屏,系统任务栏随之显示。点击主窗口可重新聚焦并恢复全屏,请问有没有办法防止主窗口失焦时退出全屏?
复现代码
# coding: utf-8 from tkinter import * from tkinter.messagebox import askokcancel, showinfo, WARNING # 创建主窗口 fenetre = Tk() larg = fenetre.winfo_screenwidth() haut = fenetre.winfo_screenheight() fenetre.title("Tests") fenetre.geometry(f"{larg}x{haut}+0+0") fenetre.attributes("-fullscreen", 1) def fermeture(): reponse = askokcancel(title='Confirmation', message='Quitter ?', icon=WARNING) if reponse == True: fenetre.destroy() bouton_quitter = Button(fenetre, text="quitter", command=fermeture) bouton_quitter.place(x=larg/2, y=haut/2) fenetre.mainloop()
我试过用fenetre.after(500, ffocus)强制主窗口在MessageBox弹出后重新聚焦,但效果不好:一是仍会短暂失焦显示任务栏;二是500ms的延迟会因处理器性能差异出现适配问题。另外也尝试给MessageBox添加parent=fenetre参数,但是没有改善。
解决方案
方法1:绑定焦点事件自动恢复全屏
给主窗口绑定<<FocusIn>>事件,一旦主窗口重新获得焦点就立刻重置全屏属性,能最大程度减少任务栏显示的时间,体验比延迟聚焦好很多:
# coding: utf-8 from tkinter import * from tkinter.messagebox import askokcancel, WARNING def restore_fullscreen(event): fenetre.attributes("-fullscreen", 1) fenetre = Tk() larg = fenetre.winfo_screenwidth() haut = fenetre.winfo_screenheight() fenetre.title("Tests") fenetre.attributes("-fullscreen", 1) # 绑定焦点进入事件,自动恢复全屏 fenetre.bind("<<FocusIn>>", restore_fullscreen) def fermeture(): # 务必指定parent参数,让MessageBox归属于主窗口 reponse = askokcancel(title='Confirmation', message='Quitter ?', icon=WARNING, parent=fenetre) if reponse == True: fenetre.destroy() bouton_quitter = Button(fenetre, text="quitter", command=fermeture) bouton_quitter.place(x=larg/2, y=haut/2) fenetre.mainloop()
方法2:用overrideredirect替代原生全屏
如果任务栏弹出的问题特别顽固,可以尝试隐藏窗口的系统装饰,手动设置窗口为屏幕尺寸。注意这个方法会让窗口失去系统默认的拖动、关闭等功能,需要自己实现:
# coding: utf-8 from tkinter import * from tkinter.messagebox import askokcancel, WARNING fenetre = Tk() larg = fenetre.winfo_screenwidth() haut = fenetre.winfo_screenheight() fenetre.title("Tests") # 隐藏窗口边框和标题栏,手动设置全屏尺寸 fenetre.overrideredirect(True) fenetre.geometry(f"{larg}x{haut}+0+0") def fermeture(): reponse = askokcancel(title='Confirmation', message='Quitter ?', icon=WARNING, parent=fenetre) if reponse == True: fenetre.destroy() # 自定义关闭按钮 bouton_quitter = Button(fenetre, text="quitter", command=fermeture) bouton_quitter.place(x=larg/2, y=haut/2) # 可以添加ESC快捷键退出 fenetre.bind("<Escape>", lambda e: fenetre.destroy()) fenetre.mainloop()
方法3:Windows系统专属优化
如果是在Windows平台运行,可以调用系统API把主窗口设为最顶层,进一步减少任务栏弹出的概率:
# coding: utf-8 import ctypes from tkinter import * from tkinter.messagebox import askokcancel, WARNING # Windows API设置窗口为最顶层 HWND_TOPMOST = -1 SWP_NOMOVE = 0x0002 SWP_NOSIZE = 0x0001 def set_topmost(window): hwnd = ctypes.windll.user32.GetParent(window.winfo_id()) ctypes.windll.user32.SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) fenetre = Tk() larg = fenetre.winfo_screenwidth() haut = fenetre.winfo_screenheight() fenetre.title("Tests") fenetre.attributes("-fullscreen", 1) # 把主窗口设为最顶层 set_topmost(fenetre) def fermeture(): reponse = askokcancel(title='Confirmation', message='Quitter ?', icon=WARNING, parent=fenetre) if reponse == True: fenetre.destroy() bouton_quitter = Button(fenetre, text="quitter", command=fermeture) bouton_quitter.place(x=larg/2, y=haut/2) fenetre.mainloop()
内容的提问来源于stack exchange,提问作者Jouski
相关产品推荐
相关产品推荐

