Python tkinter消息框未显示在Windows任务栏上

Python tkinter消息框未显示在Windows任务栏上,python,windows,python-3.x,tkinter,Python,Windows,Python 3.x,Tkinter,我正在编写一个Python应用程序,并希望messagebox通知用户一个错误,它的行为方式与我在Linux(在Mint和Ubuntu上测试)中希望的方式相同,但在Windows上,它没有在任务栏上创建应用程序,因此它会丢失。我也可以让它贴在前面,但这也有点讨厌。以下是我的工作内容: from tkinter import Tk, messagebox root = Tk() messagebox.showerror("Oh please work oh please work oh plea

我正在编写一个Python应用程序,并希望messagebox通知用户一个错误,它的行为方式与我在Linux(在Mint和Ubuntu上测试)中希望的方式相同,但在Windows上,它没有在任务栏上创建应用程序,因此它会丢失。我也可以让它贴在前面,但这也有点讨厌。以下是我的工作内容:

from tkinter import Tk, messagebox

root = Tk()
messagebox.showerror("Oh please work oh please work oh please", "Show up on taskbar! ... *sigh")
root.withdraw()

我发现的一个解决方法是,我没有退出根窗口,而是将不可见或根设置为0,然后将其最小化,以大大降低按下不可见退出按钮的概率。然后我检查操作系统是否在运行Windows,如果没有,我就退出root

from tkinter import Tk, messagebox
import sys

root = Tk()  # We need a main window
root.attributes('-alpha', 0.0)
root.wm_state('iconic')
if not sys.platform.lower().startswith("win"):
    root.withdraw()
messagebox.showerror("Oops!", "Sorry! Could not connect to the server!")
root.withdraw()

注意:Windows和Linux是我唯一支持的两个平台,但我推测这也适用于Mac。请让我知道您是否有不同的发现

首先,让我们详细说明根顶级示例上的瞬态窗口是什么

默认情况下,
Toplevel
显示为非瞬态,但由于该方法,我们能够修复该问题。 下面是一个片段:

import tkinter as tk

root = tk.Tk()
tk.Label(root, text='root').pack()
top = tk.Toplevel(root)
tk.Label(top, text='toplevel').pack()
# uncomment to make top transient
# top.transient(root)
root.mainloop()
好的,现在我们知道了一些关于它的事情,特别是关于Windows上任务栏行为的事实

但解决方案呢?有一些,你的方法还可以,让我们稍微修改一下:

import tkinter as tk
import tkinter.messagebox as msg

root = tk.Tk()

if root._windowingsystem == 'win32':
    # windows showerror
    top = tk.Toplevel(root)
    top.iconify()
    msg.showerror("Oh please work oh please work oh please", "Show up on taskbar! ... *sigh", parent=top)
    top.destroy()
else:
    # non-windows showerror
    msg.showerror("Oh please work oh please work oh please", "Show up on taskbar! ... *sigh")

root.destroy()
如果您在
tkinter
的引擎盖下爬行,您将看到
parent
参数不是一个真正的可选参数,如果您通过
None
,则
tkinter
Tk
视为父项。但是我们可以使用虚拟的Toplevel为它提供信息,因此我们的消息将是瞬态的
Toplevel
,而不是
Tk
实例

另外,正如我在评论中所说的,我们可以称之为native:


虽然这对我来说算不上是一种变通方法(我们不采用tkinter,我们做我们想做的事情),但这是一种对轮子的重新发明,因为这些东西已经在引擎盖下实现了。然而,它在外观上更灵活,但这不是你的问题所在。

这种行为,让你感到奇怪的是临时窗口,它们共享任务栏位置。在Windows上,您可以将
tk_messageBox
视为本机
messageBox
函数的包装器,默认情况下,这是一个瞬态和模式窗口。如果你想让它成为任务栏上的一个单独的东西,你可以通过
ctypes
内置的方式手动调用它,作为一个非暂时的东西。@CommonSense这听起来像是一种方法!不幸的是,我不太了解ctypes,也不知道如何在MessageBox周围创建包装器。我现在正在研究它,但如果你给我一些代码让我开始,我会很高兴接受一个工作的答案!对不起,我花了这么长时间才接受——学校发生了!不管怎么说,这就是我想要的行为。我可以稍后再调查原因
import tkinter as tk
import tkinter.messagebox as msg
import ctypes

MB_OK = 0x0
ICON_STOP = 0x10


root = tk.Tk()

# non-transient app-wide version
native_showerror = lambda: ctypes.windll.user32.MessageBoxW(0, "Oh please work oh please work oh please",
                                                            "Show up on taskbar! ... *sigh", MB_OK | ICON_STOP)
# transient version if we pass hWnd of the root window
native_showerror_transient = lambda: ctypes.windll.user32.MessageBoxW(root.winfo_id(),
                                                                      "Oh please work oh please work oh please",
                                                                      "Show up on taskbar! ... *sigh", MB_OK | ICON_STOP)

if root._windowingsystem == 'win32':
    # windows showerror
    root.update_idletasks()
    native_showerror()

else:
    # non-windows showerror
    msg.showerror("Oh please work oh please work oh please", "Show up on taskbar! ... *sigh")

root.mainloop()