简体   繁体   中英

Python TKinter on Mac OS does not show message box specific icons

In Mac OS, the tkinter message boxes do NOT show different icons for different types of message box (other than warning). The error, info, and question icons are all the "Python Spaceship" icon and not specific to errors, info, or questions. See attached files starting with "Screen Shot ..."

In Windows, the message boxes show context sensitive icons. See attached file WindowsMessageBoxOutput.jpg

How do I get the context sensitive icons to load on Mac OS?

The code I used for generating/showing the message boxes is the following:

import tkinter as tk
import tkinter.messagebox as tkmb
from tkinter import Button

def show_message_boxes():
    tkmb.showinfo(title='Info Box', message='Info with info icon', icon='info')
    tkmb.showinfo(title='Info Box', message='Info with error icon', icon='error')
    tkmb.showinfo(title='Info Box', message='Info with question icon', icon='question')
    tkmb.showinfo(title='Info Box', message='Info with warning icon', icon='warning')

    tkmb.showinfo(title='Info Box', message='Info box with info icon', icon='info')
    tkmb.showerror(title='Error Box', message='Error box with default icon', icon='error')
    tkmb.showwarning(title='Warning Box', message='Warning box with default icon', icon='warning')

    tkmb.showinfo(title='Info Box', message='Info box with default icon')
    tkmb.showerror(title='Error Box', message='Error box with default icon')
    tkmb.showwarning(title='Warning Box', message='Warning box with default icon')

window = tk.Tk()

but = Button(window, text ='Click', command = show_message_boxes, width=20, height=10)
but.grid(row=0, column=0)

window.mainloop()

Note: I tried various options to try and generate message boxes with icons (hence the various calls in the code above).

Environment

I'm running with the following on Mac OS:

  • Mojave 10.14.6
  • Python 3.7.5
  • tkinter 8.5

Images:

MacOS 消息框 Windows 消息框

I can confirm that this happens on MacOS at least in Big Sur in Python 3.9.9 and 3.10.4.

The only fix I found was to - only in macos! -change the app icon before the call to the messagebox as suggested in How to correct picture tkinter messagebox tkinter on macos and back after the call to messagebox.

I've tried to wrap this behaviour in a python decorator 'if_mac_set_icon' for a clean appearance. The program needs some supplied images in a folder 'images'. See the code for details. Tested on Big Sur and Windows (decorator does nothing there).

from tkinter import Tk, Tcl, Button, messagebox, PhotoImage
from tkinter import ttk
import sys
"""
On MacOS Big Sur using Python 3.9.3:
- messagebox.showwarning() shows yellow exclamationmark with small rocket icon
- showerror(),askretrycancel,askyesno,askquestion, askyesnocancel
On MacOS BigSur using Python 3.10.4 same but with a folder icon instead 
of the rocket item. Tcl/Tk version is 8.6.12 """


# use a decorator with a parameter to add pre and postrocessing
# switching the iconphoto of the root/app see
# https://stackoverflow.com/questions/51530310/how-to-correct-picture-tkinter-messagebox-tkinter-on-macos
# decorator info: see https://realpython.com/primer-on-python-decorators/
def if_mac_set_icon(icon):
    def set_icon(icon):
     """ this function needs a folder 'images' with images with the below 
     names like app.png"""
        images = dict(
            app="app.png",
            info="exclamation.png",
            warning="exclamation.png",
            question="question.png",
            error="error.png"
        )
        img = PhotoImage(file=f"images/{images[icon]}")
        root.iconphoto(False, img)

    def decorator_func(original_func):
        def wrapper_func(*args, **kwargs):
            if sys.platform == "darwin":
                set_icon(icon)
            return original_func(*args, **kwargs)
            if sys.platform == "darwin":
                set_icon('app')  # restore app icon
        return wrapper_func
    return decorator_func


@if_mac_set_icon('warning')
def showwarning(*args, **kwargs):
    return messagebox.showwarning(*args, **kwargs)


@if_mac_set_icon('question')
def askquestion(*args, **kwargs):
    return messagebox.askquestion(*args, **kwargs)


@if_mac_set_icon('error')
def showerror(*args, **kwargs):
    return messagebox.showerror(*args, **kwargs)


@if_mac_set_icon('question')
def askretrycancel(*args, **kwargs):
    return messagebox.askretrycancel(*args, **kwargs)


@if_mac_set_icon('question')
def askyesno(*args, **kwargs):
    return messagebox.askyesno(*args, **kwargs)


root = Tk()

ttk.Button(root, text="Warningbox", command=showwarning).grid()
ttk.Button(root, text="Questionbox", command=askquestion).grid()
ttk.Button(root, text="Errorbox", command=lambda: askquestion(message="Error")).grid()

root.mainloop()

FWIW, I see the same behavior on:

  • OS 10.15.5
  • Python 3.8.3
  • tkinter 8.6

Works as expected on Windows & Linux and I can override the default messagebox icon type with the "icon" parameter.

Looks like it's been an issue for some time now: Why can't I change the icon on a tkMessagebox.askyesno() on OS X?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM