I’ve been using Python a lot more lately and have discovered some pretty interesting things – one of which I want to share here. A recent project had a requirement for a Python script that would be deployed to users’ machines as a scheduled task, triggered on login to run at a set interval every n minutes. Normally, the script executes silently, without the need for any user interaction. However, there may be an occasional error or warning condition I want to surface to the user so that they may take the appropriate action. Because the script runs as a background task, without opening a command line window, there is no standard output to which print()
statements will be displayed to the user and there is no UI to alert the user.
If a UI is needed in Python, libraries like Qt, Tk, and many others get the job done nicely, but I didn’t want any additional dependencies. This script needs to maximize portability across a wide array of target machines, so sticking to the default libraries as much as possible was my goal. I only needed a basic message box to display the error or warning details with an “OK” button to acknowledge the user saw the alert – importing one of the GUI libraries would be too complex of a solution in my opinion. Because all of the target machines will be running Windows, I can directly use OS-specific features to render a message box using the ctypes library and the Windows API. Ctypes allows Python code to directly call various libraries, written in C, included with Windows.
Here is the sample code – you can also view as a GitHub Gist.
import ctypes
def main():
WS_EX_TOPMOST = 0x40000
windowTitle = "Python Windows Message Box Test"
message = "Hello, world! This Message box was created by calling the Windows API using the ctypes library."
# display a message box; execution will stop here until user acknowledges
ctypes.windll.user32.MessageBoxExW(None, message, windowTitle, WS_EX_TOPMOST)
print("User clicked OK.")
if __name__ == "__main__":
main()
Here’s what’s happening in the script: the ctypes
library is imported first, and inside the main()
method, a variable named WX_EX_TOPMOST
is assigned a hexadecimal value of 0x40000
. The variable name is taken from the different window styles in the Windows API, and “0x40000” is a constant value that will apply a “top most” window style to the dialog box. This will set its z-order so that the message box is on top of all other open windows. The ctypes
library exposes methods which essentially wrap up calls to the Windows API functions like MessageBoxExW
, making interacting with the API easy. MessageBoxExW()
is called, passing in None
for the owner window handle (so the message box has no parent window), the message to display, the window title, and the window style.
When the script is run, a Windows MessageBox is displayed. Clicking OK will resume execution of the script.
Pyautogui creates this message box easily and also use ctypes, i.e.
import pyautogui
pyautogui.alert(“Message here”,”MsgBx Title”)
LikeLike
Way cool that it’s so straightforward and self-contained. Thanks for posting.
LikeLiked by 1 person
This was the perfect solution for me: all target machines are running Windows, and I only needed to show a message box during infrequent error conditions. A GUI library or framework would have been way overkill.
LikeLike
There seems to be an error. The code says 0x40000 and the text says 0x4000 (one zero missing).
LikeLiked by 1 person
Thank you for catching that! The correct value for the topmost window style is β0x40000β β this was correct in my sample code block, but incorrect in the body text of this post. I have corrected those typos and re-published.
LikeLike
is there an equally simple way to get user input and display it in a label? I am having a hard time with the tkinter way
LikeLike
is there an equally simple way to get user input and display it in a label
LikeLike