如何使用 tkinter 设置 MessageBox 的位置

问题描述 投票:0回答:2

我一直在到处寻找是否可以找到任何帮助,但没有得到任何帮助 我的程序是一个简单的 tkinter 菜单,它设置为屏幕左上角的默认位置,但是当我按 X 按钮时,它会在屏幕中央加载消息框。

如何才能将消息框对齐到角落?

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)`

如果需要任何额外的代码,请告诉我,并提前致谢。

python python-2.7 tkinter
2个回答
0
投票

您需要构建一个自定义

Toplevel()
窗口,然后告诉它重新定位到根窗口的一角。我们可以使用
Toplevel()
类和
winfo()
方法来做到这一点。

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()

结果:

就我个人而言,我会将这一切构建在继承自

Tk()
的一个类中,使按钮与ttk按钮均匀,并使用标签来引用位于
::tk::icons::question
的内置问题图像,如下所示:

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()

结果:


0
投票

这是 messagebox.askokcancel 的直接替代品。 Mike - SMT 的答案不会暂停执行,也不会返回答案,第二个示例需要进一步重构您的程序,因此我修改了他的第一个示例,根本不更改标准 tkinter 代码(除了调用我的函数并添加几何图形)我的函数接受的选项):

    answer = messagewindow_askokcancel(
        "Quit",
        "Are you sure you want to quit?",
        parent=root,
        geometry="+0+0",
        # geometry="+{}+{}".format(root.winfo_x(), root.winfo_y()),
    )

此外,答案始终将位置设置为父窗口,但我已按照您的要求将其放置在屏幕的左上角(注释部分使用窗口的左上角)。此外,该版本在几何设置中没有尺寸,因此窗口会自动调整文本大小,并且如果变大或添加更多文本,文本不会被切断。使用这个类,可以类似地编写具有不同按钮的其他功能。

要使用上面的调用,请将此代码放在您(或任何)程序的顶部:

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  # immitate 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
© www.soinside.com 2019 - 2024. All rights reserved.