I have been looking all over to see if I can find any help with this and haven't gotten anywhere My program is a simple tkinter menu that is set to be in a default position in the top left corner of the screen, however when I press the X button it loads the message box in the center of the screen.
How do I make it so that it snaps the message box to the corner?
root = Tk()
root.geometry('%dx%d+%d+%d' % (300, 224, 0, 0))
root.resizable(0,0)
def exitroot():
if tkMessageBox.askokcancel("Quit", "Are you sure you want to quit?"):
with open(settings, 'wb') as csvfile:
writedata = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
writedata.writerow([setpass])
writedata.writerow([opcolour] + [bkcolour])
writedata.writerow([menu_background_status] + [menu_internet_status])
root.destroy()
root.protocol("WM_DELETE_WINDOW", exitroot)`
If any extra code is needed then let me know, and thanks in advance.
Here is a drop-in replacement for messagebox.askokcancel. Mike - SMT's answer doesn't pause execution nor return an answer, and the second example requires refactoring your program further, so I modified his first example to be used without changing standard tkinter code at all (except calling my function, and adding the geometry option which my function accepts):
answer = messagewindow_askokcancel(
"Quit",
"Are you sure you want to quit?",
parent=root,
geometry="+0+0",
# geometry="+{}+{}".format(root.winfo_x(), root.winfo_y()),
)
Also, the answer set the position to the parent window at all times but I've placed it at the top left of the screen as you asked (commented part uses top left of window). Also, this version has no size in the geometry setting, so the window will automatically size to the text and text will not be cut off if made larger or more text is added. Using this class, other functions with different buttons can be written similarly.
To use the call above, place this code at the top of your (or any) program:
import tkinter as tk
from collections import OrderedDict
class MessageWindow(tk.Toplevel):
"""An independent window that can be positioned.
Based on https://stackoverflow.com/a/53839951/4541104 but configurable.
"""
def __init__(self, title, message, answers=None, **options):
parent = options.get('parent')
if parent:
super().__init__(parent)
else:
super().__init__()
# self.answer = None # a result of None would indicate *closed*
# (doesn't change default behavior much--you could still do "if"
# on self.answer like with messagebox.askokcancel's return)
self.answer = False # imitate messagebox.askokcancel behavior
# (return False if dialog closed without pressing a button).
if not answers:
answers = OrderedDict(OK=True)
self.details_expanded = False
self.title(title)
geometry = options.get('geometry')
if geometry:
self.geometry(geometry)
self.resizable(False, False)
self.rowconfigure(0, weight=0)
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
tk.Label(self, text=message).grid(row=0, column=0, columnspan=3,
pady=(7, 7), padx=(7, 7), sticky="ew")
column = 0
for text, value in answers.items():
column += 1
tk.Button(
self,
text=text,
command=lambda v=value: self.set_value(v),
# ^ v=value to force early binding (store this value
# so value of last iteration isn't used for all).
).grid(row=1, column=column, sticky="e")
def set_value(self, value):
self.answer = value
self.destroy()
def messagewindow_askokcancel(title, message, **options):
"""A drop-in replacement for askokcancel but you can set x and y.
For options not listed below, see messagebox.askokcancel documentation.
Keyword arguments:
parent (tk.Widget): The window to block.
geometry (Optional[string]): The window size and/or position
(not available in messagebox, so a TopLevel is used).
"""
answer = None
messagewindow = MessageWindow(
title,
message,
answers=OrderedDict(OK=True, Cancel=False),
**options,
)
# See https://stackoverflow.com/a/31439014/4541104
messagewindow.master.wait_window(messagewindow)
# ^ Using master allows us to know what Tk to stop without global(s)
return messagewindow.answer
You will need to build a custom Toplevel() window and then tell it to re-position to the corner of the root window. We can do this with the Toplevel() class and the winfo() methods.
import tkinter as tk
# import Tkinter as tk # for Python 2.X
class MessageWindow(tk.Toplevel):
def __init__(self, title, message):
super().__init__()
self.details_expanded = False
self.title(title)
self.geometry("300x75+{}+{}".format(self.master.winfo_x(), self.master.winfo_y()))
self.resizable(False, False)
self.rowconfigure(0, weight=0)
self.rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
tk.Label(self, text=message).grid(row=0, column=0, columnspan=3, pady=(7, 7), padx=(7, 7), sticky="ew")
tk.Button(self, text="OK", command=self.master.destroy).grid(row=1, column=1, sticky="e")
tk.Button(self, text="Cancel", command=self.destroy).grid(row=1, column=2, padx=(7, 7), sticky="e")
root = tk.Tk()
root.geometry("300x224")
root.resizable(0, 0)
def yes_exit():
print("do other stuff here then root.destroy")
root.destroy()
def exit_root():
MessageWindow("Quit", "Are you sure you want to quit?")
root.protocol("WM_DELETE_WINDOW", exit_root)
root.mainloop()
Results:

Personally I would build this all in one class inheriting from Tk(), make the buttons even with ttk buttons and use a label to reference the built in question image located at ::tk::icons::question like this:
import tkinter as tk
import tkinter.ttk as ttk
# import Tkinter as tk # for Python 2.X
class GUI(tk.Tk):
def __init__(self):
super().__init__()
self.geometry("300x224")
self.resizable(0, 0)
self.protocol("WM_DELETE_WINDOW", self.exit_window)
def yes_exit(self):
print("do other stuff here then self.destroy")
self.destroy()
def exit_window(self):
top = tk.Toplevel(self)
top.details_expanded = False
top.title("Quit")
top.geometry("300x100+{}+{}".format(self.winfo_x(), self.winfo_y()))
top.resizable(False, False)
top.rowconfigure(0, weight=0)
top.rowconfigure(1, weight=1)
top.columnconfigure(0, weight=1)
top.columnconfigure(1, weight=1)
tk.Label(top, image="::tk::icons::question").grid(row=0, column=0, pady=(7, 0), padx=(7, 7), sticky="e")
tk.Label(top, text="Are you sure you want to quit?").grid(row=0, column=1, columnspan=2, pady=(7, 7), sticky="w")
ttk.Button(top, text="OK", command=self.yes_exit).grid(row=1, column=1, sticky="e")
ttk.Button(top, text="Cancel", command=top.destroy).grid(row=1, column=2, padx=(7, 7), sticky="e")
if __name__ == "__main__":
GUI().mainloop()
Results:

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With