跳转至

MessageDialog

Bases: Dialog

A simple modal dialog class that can be used to build simple message dialogs.

Displays a message and a set of buttons. Each of the buttons in the message window is identified by a unique symbolic name. After the message window is popped up, the message box awaits for the user to select one of the buttons. Then it returns the symbolic name of the selected button. Use a Toplevel widget for more advanced modal dialog designs.

Source code in src/ttkbootstrap/dialogs/message.py
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
class MessageDialog(Dialog):
    """A simple modal dialog class that can be used to build simple
    message dialogs.

    Displays a message and a set of buttons. Each of the buttons in the
    message window is identified by a unique symbolic name. After the
    message window is popped up, the message box awaits for the user to
    select one of the buttons. Then it returns the symbolic name of the
    selected button. Use a `Toplevel` widget for more advanced modal
    dialog designs.
    """

    def __init__(
            self,
            message: str,
            title: str = " ",
            buttons: Optional[List[str]] = None,
            command: Optional[Tuple[Callable[..., Any], str]] = None,
            width: int = 50,
            parent: Optional[tkinter.Misc] = None,
            alert: bool = False,
            default: Optional[str] = None,
            padding: "tuple[int, int] | int" = (20, 20),
            icon: Optional[str] = None,
            **kwargs: Any,
    ) -> None:
        """Create a message dialog.

        Parameters:

            message (str):
                The message text to display. Supports multiline strings
                (separated by \\n).

            title (str):
                The dialog window title (default=' ').

            buttons (List[str]):
                List of button labels. Each button can optionally specify
                a bootstyle using "label:bootstyle" format (e.g., "OK:primary").
                If None, defaults to ["Cancel", "OK"]. The buttons are
                displayed in reverse order (rightmost first).

            command (Callable):
                Optional callback function to execute when a button is pressed.

            width (int):
                Maximum width in characters for text wrapping (default=50).

            parent (Widget):
                Parent widget. The dialog will be centered on this widget.

            alert (bool):
                If True, rings the system bell when the dialog is shown
                (default=False).

            default (str):
                The button label to use as the default (receives primary
                bootstyle and initial focus). If None, the rightmost button
                becomes the default.

            padding (int | tuple):
                Padding around the message content. Can be a single int or
                tuple (horizontal, vertical) (default=(20, 20)).

            icon (str):
                Optional icon to display. Can be image data, file path,
                or Icon constant (e.g., Icon.info).

            **kwargs (Dict):
                Additional keyword arguments. Supports 'localize' (bool)
                to enable message translation.
        """
        super().__init__(parent, title, alert)
        self._message = message
        self._command: Optional[Tuple[Callable[..., Any], str]] = command
        self._width = width
        self._alert = alert
        self._default = default
        self._padding = padding
        self._icon = icon
        self._localize = kwargs.get("localize")

        if buttons is None:
            self._buttons = [
                f"{MessageCatalog.translate('Cancel')}",
                f"{MessageCatalog.translate('OK')}",
            ]
        else:
            self._buttons = buttons

    def create_body(self, master: tkinter.Misc) -> None:
        """Overrides the parent method; adds the message section."""
        container = ttk.Frame(master, padding=self._padding)
        if self._icon:
            try:
                # assume this is image data
                self._img = ttk.PhotoImage(data=self._icon)
                icon_lbl = ttk.Label(container, image=self._img)
                icon_lbl.pack(side=LEFT, anchor=N, padx=(0, 5))
            except Exception:
                try:
                    # assume this is a file path
                    self._img = ttk.PhotoImage(file=self._icon)
                    icon_lbl = ttk.Label(container, image=self._img)
                    icon_lbl.pack(side=LEFT, anchor=N, padx=(0, 5))
                except Exception:
                    # icon is neither data nor a valid file path
                    print("MessageDialog icon is invalid")

        if self._message:
            for msg in self._message.split("\n"):
                message = "\n".join(textwrap.wrap(msg, width=self._width))
                message_label = ttk.Label(container, text=message)
                message_label.pack(pady=(0, 3), fill=X, anchor=N)
        container.pack(fill=X, expand=True)

    def create_buttonbox(self, master: tkinter.Misc) -> None:
        """Overrides the parent method; adds the message buttonbox"""
        frame = ttk.Frame(master, padding=(5, 5))

        button_list: list[ttk.Button] = []

        for i, button in enumerate(self._buttons[::-1]):
            cnf = button.split(":")
            text = cnf[0]

            is_default = False
            if self._default is not None and text == self._default:
                is_default = True
            elif self._default is None and i == 0:
                is_default = True

            if len(cnf) == 2:
                bootstyle = cnf[1]
            elif is_default:
                bootstyle = "primary"
            else:
                bootstyle = "secondary"

            if self._localize is True:
                text = MessageCatalog.translate(text)

            btn = ttk.Button(frame, bootstyle=bootstyle, text=text)
            btn.configure(command=lambda b=btn: self.on_button_press(b))
            btn.pack(padx=2, side=RIGHT)
            btn.lower()  # set focus traversal left-to-right
            button_list.append(btn)

            if is_default:
                self._initial_focus = btn

            # bind default button to return key press and set focus
            btn.bind("<Return>", lambda _, b=btn: b.invoke())
            btn.bind("<KP_Enter>", lambda _, b=btn: b.invoke())

        for index, btn in enumerate(button_list):
            if index > 0:
                nbtn = button_list[index - 1]
                btn.bind("<Right>", lambda _, b=nbtn: b.focus_set())
            if index < len(button_list) - 1:
                nbtn = button_list[index + 1]
                btn.bind("<Left>", lambda _, b=nbtn: b.focus_set())

        ttk.Separator(self._toplevel).pack(fill=X)
        frame.pack(side=BOTTOM, fill=X, anchor=S)

        if not self._initial_focus:
            self._initial_focus = button_list[0]

    def on_button_press(self, button: ttk.Button) -> None:
        """Save result, destroy the toplevel, and execute command."""
        self._result = button["text"]
        command = self._command
        if command is not None:
            command()
        self._toplevel.after_idle(self._toplevel.destroy)

    def show(self, position: Optional[Tuple[int, int]] = None, wait_for_result: bool = True) -> None:
        """Create and display the popup messagebox."""
        super().show(position, wait_for_result=wait_for_result)

__init__(message, title=' ', buttons=None, command=None, width=50, parent=None, alert=False, default=None, padding=(20, 20), icon=None, **kwargs)

Create a message dialog.

Parameters:

message (str):
    The message text to display. Supports multiline strings
    (separated by \n).

title (str):
    The dialog window title (default=' ').

buttons (List[str]):
    List of button labels. Each button can optionally specify
    a bootstyle using "label:bootstyle" format (e.g., "OK:primary").
    If None, defaults to ["Cancel", "OK"]. The buttons are
    displayed in reverse order (rightmost first).

command (Callable):
    Optional callback function to execute when a button is pressed.

width (int):
    Maximum width in characters for text wrapping (default=50).

parent (Widget):
    Parent widget. The dialog will be centered on this widget.

alert (bool):
    If True, rings the system bell when the dialog is shown
    (default=False).

default (str):
    The button label to use as the default (receives primary
    bootstyle and initial focus). If None, the rightmost button
    becomes the default.

padding (int | tuple):
    Padding around the message content. Can be a single int or
    tuple (horizontal, vertical) (default=(20, 20)).

icon (str):
    Optional icon to display. Can be image data, file path,
    or Icon constant (e.g., Icon.info).

**kwargs (Dict):
    Additional keyword arguments. Supports 'localize' (bool)
    to enable message translation.
Source code in src/ttkbootstrap/dialogs/message.py
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def __init__(
        self,
        message: str,
        title: str = " ",
        buttons: Optional[List[str]] = None,
        command: Optional[Tuple[Callable[..., Any], str]] = None,
        width: int = 50,
        parent: Optional[tkinter.Misc] = None,
        alert: bool = False,
        default: Optional[str] = None,
        padding: "tuple[int, int] | int" = (20, 20),
        icon: Optional[str] = None,
        **kwargs: Any,
) -> None:
    """Create a message dialog.

    Parameters:

        message (str):
            The message text to display. Supports multiline strings
            (separated by \\n).

        title (str):
            The dialog window title (default=' ').

        buttons (List[str]):
            List of button labels. Each button can optionally specify
            a bootstyle using "label:bootstyle" format (e.g., "OK:primary").
            If None, defaults to ["Cancel", "OK"]. The buttons are
            displayed in reverse order (rightmost first).

        command (Callable):
            Optional callback function to execute when a button is pressed.

        width (int):
            Maximum width in characters for text wrapping (default=50).

        parent (Widget):
            Parent widget. The dialog will be centered on this widget.

        alert (bool):
            If True, rings the system bell when the dialog is shown
            (default=False).

        default (str):
            The button label to use as the default (receives primary
            bootstyle and initial focus). If None, the rightmost button
            becomes the default.

        padding (int | tuple):
            Padding around the message content. Can be a single int or
            tuple (horizontal, vertical) (default=(20, 20)).

        icon (str):
            Optional icon to display. Can be image data, file path,
            or Icon constant (e.g., Icon.info).

        **kwargs (Dict):
            Additional keyword arguments. Supports 'localize' (bool)
            to enable message translation.
    """
    super().__init__(parent, title, alert)
    self._message = message
    self._command: Optional[Tuple[Callable[..., Any], str]] = command
    self._width = width
    self._alert = alert
    self._default = default
    self._padding = padding
    self._icon = icon
    self._localize = kwargs.get("localize")

    if buttons is None:
        self._buttons = [
            f"{MessageCatalog.translate('Cancel')}",
            f"{MessageCatalog.translate('OK')}",
        ]
    else:
        self._buttons = buttons

create_body(master)

Overrides the parent method; adds the message section.

Source code in src/ttkbootstrap/dialogs/message.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def create_body(self, master: tkinter.Misc) -> None:
    """Overrides the parent method; adds the message section."""
    container = ttk.Frame(master, padding=self._padding)
    if self._icon:
        try:
            # assume this is image data
            self._img = ttk.PhotoImage(data=self._icon)
            icon_lbl = ttk.Label(container, image=self._img)
            icon_lbl.pack(side=LEFT, anchor=N, padx=(0, 5))
        except Exception:
            try:
                # assume this is a file path
                self._img = ttk.PhotoImage(file=self._icon)
                icon_lbl = ttk.Label(container, image=self._img)
                icon_lbl.pack(side=LEFT, anchor=N, padx=(0, 5))
            except Exception:
                # icon is neither data nor a valid file path
                print("MessageDialog icon is invalid")

    if self._message:
        for msg in self._message.split("\n"):
            message = "\n".join(textwrap.wrap(msg, width=self._width))
            message_label = ttk.Label(container, text=message)
            message_label.pack(pady=(0, 3), fill=X, anchor=N)
    container.pack(fill=X, expand=True)

create_buttonbox(master)

Overrides the parent method; adds the message buttonbox

Source code in src/ttkbootstrap/dialogs/message.py
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
def create_buttonbox(self, master: tkinter.Misc) -> None:
    """Overrides the parent method; adds the message buttonbox"""
    frame = ttk.Frame(master, padding=(5, 5))

    button_list: list[ttk.Button] = []

    for i, button in enumerate(self._buttons[::-1]):
        cnf = button.split(":")
        text = cnf[0]

        is_default = False
        if self._default is not None and text == self._default:
            is_default = True
        elif self._default is None and i == 0:
            is_default = True

        if len(cnf) == 2:
            bootstyle = cnf[1]
        elif is_default:
            bootstyle = "primary"
        else:
            bootstyle = "secondary"

        if self._localize is True:
            text = MessageCatalog.translate(text)

        btn = ttk.Button(frame, bootstyle=bootstyle, text=text)
        btn.configure(command=lambda b=btn: self.on_button_press(b))
        btn.pack(padx=2, side=RIGHT)
        btn.lower()  # set focus traversal left-to-right
        button_list.append(btn)

        if is_default:
            self._initial_focus = btn

        # bind default button to return key press and set focus
        btn.bind("<Return>", lambda _, b=btn: b.invoke())
        btn.bind("<KP_Enter>", lambda _, b=btn: b.invoke())

    for index, btn in enumerate(button_list):
        if index > 0:
            nbtn = button_list[index - 1]
            btn.bind("<Right>", lambda _, b=nbtn: b.focus_set())
        if index < len(button_list) - 1:
            nbtn = button_list[index + 1]
            btn.bind("<Left>", lambda _, b=nbtn: b.focus_set())

    ttk.Separator(self._toplevel).pack(fill=X)
    frame.pack(side=BOTTOM, fill=X, anchor=S)

    if not self._initial_focus:
        self._initial_focus = button_list[0]

on_button_press(button)

Save result, destroy the toplevel, and execute command.

Source code in src/ttkbootstrap/dialogs/message.py
184
185
186
187
188
189
190
def on_button_press(self, button: ttk.Button) -> None:
    """Save result, destroy the toplevel, and execute command."""
    self._result = button["text"]
    command = self._command
    if command is not None:
        command()
    self._toplevel.after_idle(self._toplevel.destroy)

show(position=None, wait_for_result=True)

Create and display the popup messagebox.

Source code in src/ttkbootstrap/dialogs/message.py
192
193
194
def show(self, position: Optional[Tuple[int, int]] = None, wait_for_result: bool = True) -> None:
    """Create and display the popup messagebox."""
    super().show(position, wait_for_result=wait_for_result)