Skip to content

Commit b4e4552

Browse files
committed
Add window icon option
1 parent 944b7cd commit b4e4552

File tree

2 files changed

+49
-13
lines changed

2 files changed

+49
-13
lines changed

src/pymsgbox/__init__.py

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@
105105
buttonsFrame = None
106106

107107

108-
def _alertTkinter(text="", title="", button=OK_TEXT, root=None, timeout=None):
108+
def _alertTkinter(text="", title="", button=OK_TEXT, root=None, timeout=None, icon=None):
109109
"""Displays a simple message box with text and a single OK button. Returns the text of the button clicked on."""
110110
assert TKINTER_IMPORT_SUCCEEDED, "Tkinter is required for pymsgbox"
111111
text = str(text)
112112
retVal = _buttonbox(
113-
msg=text, title=title, choices=[str(button)], root=root, timeout=timeout
113+
msg=text, title=title, choices=[str(button)], root=root, timeout=timeout, icon=icon
114114
)
115115
if retVal is None:
116116
return button
@@ -122,7 +122,7 @@ def _alertTkinter(text="", title="", button=OK_TEXT, root=None, timeout=None):
122122

123123

124124
def _confirmTkinter(
125-
text="", title="", buttons=(OK_TEXT, CANCEL_TEXT), root=None, timeout=None
125+
text="", title="", buttons=(OK_TEXT, CANCEL_TEXT), root=None, timeout=None, icon=None
126126
):
127127
"""Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on."""
128128
assert TKINTER_IMPORT_SUCCEEDED, "Tkinter is required for pymsgbox"
@@ -133,29 +133,30 @@ def _confirmTkinter(
133133
choices=[str(b) for b in buttons],
134134
root=root,
135135
timeout=timeout,
136+
icon=icon
136137
)
137138

138139

139140
confirm = _confirmTkinter
140141

141142

142-
def _promptTkinter(text="", title="", default="", root=None, timeout=None):
143+
def _promptTkinter(text="", title="", default="", root=None, timeout=None, icon=None):
143144
"""Displays a message box with text input, and OK & Cancel buttons. Returns the text entered, or None if Cancel was clicked."""
144145
assert TKINTER_IMPORT_SUCCEEDED, "Tkinter is required for pymsgbox"
145146
text = str(text)
146147
return __fillablebox(
147-
text, title, default=default, mask=None, root=root, timeout=timeout
148+
text, title, default=default, mask=None, root=root, timeout=timeout, icon=icon
148149
)
149150

150151

151152
prompt = _promptTkinter
152153

153154

154-
def _passwordTkinter(text="", title="", default="", mask="*", root=None, timeout=None):
155+
def _passwordTkinter(text="", title="", default="", mask="*", root=None, timeout=None, icon=None):
155156
"""Displays a message box with text input, and OK & Cancel buttons. Typed characters appear as *. Returns the text entered, or None if Cancel was clicked."""
156157
assert TKINTER_IMPORT_SUCCEEDED, "Tkinter is required for pymsgbox"
157158
text = str(text)
158-
return __fillablebox(text, title, default, mask=mask, root=root, timeout=timeout)
159+
return __fillablebox(text, title, default, mask=mask, root=root, timeout=timeout, icon=icon)
159160

160161

161162
password = _passwordTkinter
@@ -181,7 +182,22 @@ def timeoutBoxRoot():
181182
__enterboxText = TIMEOUT_RETURN_VALUE
182183

183184

184-
def _buttonbox(msg, title, choices, root=None, timeout=None):
185+
def _seticon(window: tk.Tk, icon: str):
186+
try:
187+
img = tk.PhotoImage(file=icon)
188+
window.iconphoto(True, img)
189+
return
190+
except tk.TclError:
191+
pass
192+
193+
try:
194+
window.iconbitmap(icon)
195+
return
196+
except tk.TclError:
197+
pass
198+
199+
200+
def _buttonbox(msg, title, choices, root=None, timeout=None, icon=None):
185201
"""
186202
Display a msg, a title, and a set of buttons.
187203
The buttons are defined by the members of the choices list.
@@ -190,6 +206,7 @@ def _buttonbox(msg, title, choices, root=None, timeout=None):
190206
@arg msg: the msg to be displayed.
191207
@arg title: the window title
192208
@arg choices: a list or tuple of the choices to be displayed
209+
@arg icon: the window icon (tk bitmap name, png, gif, ico or xbm file)
193210
"""
194211
global boxRoot, __replyButtonText, __widgetTexts, buttonsFrame
195212

@@ -205,6 +222,9 @@ def _buttonbox(msg, title, choices, root=None, timeout=None):
205222
boxRoot = tk.Tk()
206223
boxRoot.withdraw()
207224

225+
if icon:
226+
_seticon(boxRoot, icon)
227+
208228
boxRoot.title(title)
209229
boxRoot.iconname("Dialog")
210230
boxRoot.geometry(rootWindowPosition)
@@ -311,7 +331,7 @@ def __cancelButtonEvent(event):
311331
boxRoot.quit()
312332

313333

314-
def __fillablebox(msg, title="", default="", mask=None, root=None, timeout=None):
334+
def __fillablebox(msg, title="", default="", mask=None, root=None, timeout=None, icon=None):
315335
"""
316336
Show a box in which a user can enter some text.
317337
You may optionally specify some default text, which will appear in the
@@ -337,6 +357,9 @@ def __fillablebox(msg, title="", default="", mask=None, root=None, timeout=None)
337357
boxRoot = tk.Tk()
338358
boxRoot.withdraw()
339359

360+
if icon:
361+
_seticon(boxRoot, icon)
362+
340363
boxRoot.title(title)
341364
boxRoot.iconname("Dialog")
342365
boxRoot.geometry(rootWindowPosition)

src/pymsgbox/_native_win.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,34 @@
5050
messageBoxFunc = ctypes.windll.user32.MessageBoxW
5151

5252

53+
def _getsysicon(icon):
54+
icons = {
55+
'stop': STOP,
56+
'question': QUESTION,
57+
'warning': WARNING,
58+
'info': INFO
59+
}
60+
61+
return icons.get(icon, NO_ICON)
62+
63+
5364
def alert(
5465
text="",
5566
title="",
5667
button=pymsgbox.OK_TEXT,
5768
root=None,
5869
timeout=None,
59-
icon=NO_ICON,
70+
icon=None,
6071
_tkinter=False,
6172
):
6273
"""Displays a simple message box with text and a single OK button. Returns the text of the button clicked on."""
6374
text = str(text)
6475
if (_tkinter) or (timeout is not None) or (button != pymsgbox.OK_TEXT):
6576
# Timeouts are not supported by Windows message boxes.
6677
# Call the original tkinter alert function, not this native one:
67-
return pymsgbox._alertTkinter(text, title, button, root, timeout)
78+
return pymsgbox._alertTkinter(text, title, button, root, timeout, icon)
6879

80+
icon = _getsysicon(icon)
6981
messageBoxFunc(0, text, title, MB_OK | MB_SETFOREGROUND | MB_TOPMOST | icon)
7082
return button
7183

@@ -76,7 +88,7 @@ def confirm(
7688
buttons=(pymsgbox.OK_TEXT, pymsgbox.CANCEL_TEXT),
7789
root=None,
7890
timeout=None,
79-
icon=QUESTION,
91+
icon='question',
8092
_tkinter=False,
8193
):
8294
"""Displays a message box with OK and Cancel buttons. Number and text of buttons can be customized. Returns the text of the button clicked on."""
@@ -114,8 +126,9 @@ def confirm(
114126

115127
if (_tkinter) or (timeout is not None) or (buttonFlag is None):
116128
# Call the original tkinter confirm() function, not this native one:
117-
return pymsgbox._confirmTkinter(text, title, buttons, root, timeout)
129+
return pymsgbox._confirmTkinter(text, title, buttons, root, timeout, icon)
118130

131+
icon = _getsysicon(icon)
119132
retVal = messageBoxFunc(
120133
0, text, title, buttonFlag | MB_SETFOREGROUND | MB_TOPMOST | icon
121134
)

0 commit comments

Comments
 (0)