I have a program that needs to display graphical error messages to users. It is a tkinter GUI, so I am using tkinter.messagebox.showerror
When I call showerror, it shows the error, but also creates a blank "tk" window, the kind created when an instance of the Tk class is called, like root = Tk().
from tkinter.messagebox import showerror
showerror(title = "Error", message = "Something bad happened")
Produces
How can I make this blank window not appear?
from Tkinter import *
from tkMessageBox import showerror
Tk().withdraw()
showerror(title = "Error", message = "Something bad happened")
Calling Tk().withdraw() before showing the error message will hide the root window.
Note: from tkinter import * for Python 3.x
As explained in this answer, Tkinter requires a root window before we create any more widgets/dialogs. If there is no root window, tkinter creates one. So, to make the blank window disappear, first we need to create a root window ourselves, hide it and destroy it once your dialog action is complete. Sample code below
from tkinter import Tk
from tkinter.messagebox import showerror
root = Tk()
root.withdraw()
showerror(title = "Error", message = "Something bad happened")
root.destroy()
Note: This is applicable when you just have to display a dialog and no other window exists.
Related
The messagebox by default opens in the center of the screen:
But I would like it to open at the bottom right of the screen:
My original code:
from tkinter import Tk
from tkinter.messagebox import Message
from _tkinter import TclError
TIME_TO_WAIT = 1000
root = Tk()
root.withdraw()
try:
root.after(TIME_TO_WAIT, root.destroy)
Message(title="Visual Studio Code", message="New Match Found", master=root).show()
except TclError:
pass
As per indications, I tried using root.geometry but realized that it doesn't work for messagebox, only for standard box:
root = Tk()
x = 1000
y = -1000
root.geometry(f'250x150+{x}+{y}')
root.withdraw()
# rest of code...
Prints dedicated to Claudio's answer (to help understand our debate):
The code below works on my system displaying the message box in the right bottom corner of the display. The 'trick' is that the messagebox hoovers over the parent window, so the appropriate setting of root.geometry() causes it to appear where the root window is placed on the screen. You have found it out by yourself already, but the root.withdraw() prevented the expected placement of the messagebox:
from tkinter import Tk
from tkinter.messagebox import Message
TIME_TO_WAIT = 3000
root = Tk()
root.geometry(f'100x100+{root.winfo_screenwidth()-100}+{root.winfo_screenheight()-100}')
root.after(TIME_TO_WAIT, root.destroy)
Message(title="Visual Studio Code", message="New Match Found", master=root).show()
I am trying to restart my main GUI/Halt the program flow when I Click on the "X" button in my tkinter messagebox . Any idea how can I do this ?
PS: I have read the many threads about closing the main GUI itself but nothing specific to messagebox
By default , my code proceeds to ask me for an output path using the filedailog.askdirectory() method when clicking "ok", or on closing the messagebox
My message box and the main GUI in the background
There's no simple way to add a custom handler to the "X" button. I think it's better to use messagebox.askokcancel() variation of messageboxes instead of showinfo, and halt the program if the returned result is False:
import tkinter as tk
from tkinter import messagebox, filedialog
root = tk.Tk()
def show_messagebox():
result = messagebox.askokcancel("Output path", "Please select an output file path")
if result:
filedialog.askdirectory()
else:
messagebox.showinfo("Program is halted")
tk.Button(root, text="Show messagebox", command=show_messagebox).pack()
root.mainloop()
Or, even simpler, you can just show filedialog.askdirectory() directly. If the user doesn't want to choose directory, they can click on the "Cancel" button, and then the program checks if there was empty value returned, and halts if so:
import tkinter as tk
from tkinter import messagebox, filedialog
root = tk.Tk()
def show_askdirectory():
directory = filedialog.askdirectory(title="Please select an output file path")
if not directory:
messagebox.showinfo(message="The program is halted")
else:
messagebox.showinfo(message="Chosen directory: " + directory)
tk.Button(root, text="Choose directory", command=show_askdirectory).pack()
root.mainloop()
I'm currently trying to write in a few basic user input boxes using the tkinter module in Python 3.6 (via Spyder). I can confirm that the module loads, and that the option to select simpledialog comes up, but I keep getting the following error:
AttributeError: module 'tkinter' has no attribute 'simpledialog'
Image of tkinter simpledialog
I've tried to look for other options, but other user input options do not seem to work on my Python interface. It either crashes, or the data isn't structured properly.
Interestingly enough, in the past, I've done similar things in Python with no errors, but this keeps coming up with this particular programming piece.
import tkinter as tk
import pyodbc as py
py.pooling = False
## INPUT YOUR USER ID AND PASSWORD AND DECLARE YOUR CONNECTION
## THE DIALOG BOXES MAY POP OPEN ON ANOTHER SCREEN
## THE PASSWORD INPUT IS MASKED AND WILL NOT SHOW IN THE
## VARIABLE EXPLORER
ID = tk.simpledialog.askstring("Please input your username.","Username: ")
PW = tk.simpledialog.askstring("Please input your password.",
"Password: ", show='*')
CONN = tk.simpledialog.askstring("Please input your connection.",
"Connection: ")
My expected results are that a popup window will appear and that I'll be able to get the user information I need to maintain a stable connection to the server I'm using.
Thank you in advance for your advice!
simpledialog is not in tkinter but in tkinter.simpledialog and you have to import it
import tkinter as tk
import tkinter.simpledialog
root = tk.Tk() # create main window
#root.iconify() # minimize main window
root.withdraw() # hide main window
answer = tkinter.simpledialog.askstring("Question", 'Your name:')
print(answer)
#root.destroy() # should work without it
#root.mainloop() # should work without it
See tkinter modules
import tkinter as tk
from tkinter import simpledialog
root = tk.Tk()
ID = simpledialog.askstring("Please input your username.", "Username: ", parent=root)
root.mainloop()
This will keep the popup within the parent window and visible.
I have a program that needs to display graphical error messages to users. It is a tkinter GUI, so I am using tkinter.messagebox.showerror
When I call showerror, it shows the error, but also creates a blank "tk" window, the kind created when an instance of the Tk class is called, like root = Tk().
from tkinter.messagebox import showerror
showerror(title = "Error", message = "Something bad happened")
Produces
How can I make this blank window not appear?
from Tkinter import *
from tkMessageBox import showerror
Tk().withdraw()
showerror(title = "Error", message = "Something bad happened")
Calling Tk().withdraw() before showing the error message will hide the root window.
Note: from tkinter import * for Python 3.x
As explained in this answer, Tkinter requires a root window before we create any more widgets/dialogs. If there is no root window, tkinter creates one. So, to make the blank window disappear, first we need to create a root window ourselves, hide it and destroy it once your dialog action is complete. Sample code below
from tkinter import Tk
from tkinter.messagebox import showerror
root = Tk()
root.withdraw()
showerror(title = "Error", message = "Something bad happened")
root.destroy()
Note: This is applicable when you just have to display a dialog and no other window exists.
In my script I sometimes call my ErrorWindow class to show an error message. This creates an empty tkinter window and a messagebox error window. I either only want the messagebox window, or I want the tkinter window to close automatically when I close the error window.
I've tried two pieces of code:
class ErrorWindow:
def __init__(self,error_message):
self.error_window = tk.Tk()
messagebox.showerror("ERROR",error_message,command=self.close)
self.error_window.protocol("WM_DELETE_WINDOW", self.close)
self.error_window.mainloop()
def close(self):
self.error_window.destroy()
.
class ErrorWindow:
def __init__(self,error_message):
messagebox.showerror("ERROR",error_message) #automatically creates a tk window too
But even with the second one, the tkinter window remains after I close the messagebox.
How can I program the class so that I only have to press a button (either Ok or the X in the top right of a window) once to close all windows (whether that is one or two)?
You need to withdraw the main window:
class ErrorWindow:
def __init__(self,error_message):
if not tk._default_root: # check for existing Tk instance
error_window = tk.Tk()
error_window.withdraw()
messagebox.showerror("ERROR",error_message)
This has no business as a class. You should remake this a simple function.
You did not specify whether there is just one place or multiple places where you might want want an error message. If the latter, you can create and withdraw a tk window just once. I believe a wrapper function rather than class should be sufficient for your purposes.
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
# consider placing root to control where messagebox appears
root.withdraw()
def showerror(message):
messagebox.showerror('XYZ ERROR', message, parent=root)
To avoid possible problems, I always use an explicit master or parent for everything and never depend on _default_root.
The small function below will do the job. By setting the type you can choose for: info, warning or error message box, the default is 'Info'. You can set also the timeout, the default is 2.5 seconds.
def showMessage(message, type='info', timeout=2500):
import tkinter as tk
from tkinter import messagebox as msgb
root = tk.Tk()
root.withdraw()
try:
root.after(timeout, root.destroy)
if type == 'info':
msgb.showinfo('Info', message, master=root)
elif type == 'warning':
msgb.showwarning('Warning', message, master=root)
elif type == 'error':
msgb.showerror('Error', message, master=root)
except:
pass
Call the function as follow:
For message type 'Info' and timeout of 2.5 seconds:
showMessage('Your message')
Or by your own settings for type message 'Error' and timeout 4 seconds:
showMessage('Your message', type='error', timeout=4000)