警告用户未保存的更改将丢失

时间:2015-08-30 07:52:34

标签: python tkinter frame

我的应用程序由一个包含两个较小框架的大框架(cp2)组成:顶部框架包含允许用户在应用程序的不同屏幕之间切换的按钮,底部框架包含屏幕本身(也包括框架) )。我在开始时初始化所有屏幕,然后使用它们的提升方法在它们之间切换。

问题是,如果用户点击某个按钮转到另一个屏幕,则当前所做的未保存更改将会丢失。我想用确认消息显示警告,但我只看到两种触发警告的方法,我似乎无法弄清楚如何实现。

选项1是将警告添加到exibirTela方法:如果用户单击调用此方法的按钮,该方法将在提升另一帧之前将屏幕上的值与数据库进行比较。问题是,该方法知道哪个帧即将被提升(t),但它不知道哪个帧现在位于右上方(用户即将离开的屏幕)。

选项2将在一个单独的方法上发出警告,由框架失去其位置的事件触发。这个选项的问题是我似乎没有这样的事件将方法绑定到它。

任何一个都适合我。当然,除非我不应该使用它们,否则请随时告诉我。当然,也欢迎任何其他建议。

代码如下。对不起葡萄牙语的名字。我在英文中添加了一些评论:希望这会有所帮助。

from tkinter import *
from tkinter.messagebox import *
import sqlite3

class cp2(Frame):
    def __init__(self, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)
        root.title(string="Controle de Produtos e Pedidos")
        self.columnconfigure(0, weight=1)
        self.rowconfigure(1, weight=1)

# Here I create two frames: one for the buttons, one for the screens

        barraOpcoes = Frame(self, bd=10, bg="yellow")
        barraOpcoes.grid(row=0, column=0, sticky=EW)
        barraOpcoes.columnconfigure(2, weight=1)
        areaPrincipal = Frame(self, bd=10)
        areaPrincipal.grid(row=1, column=0, sticky=NSEW)
        areaPrincipal.columnconfigure(0, weight=1)

# Here I create a set (telasAplicacao) to which I'll add all the screens (frames)

        self.telasAplicacao = {}

        for tela in (telaInicial,
                     telaCrudFabricante, telaCrudRevista,
                     telaInclusaoFabricante, telaInclusaoRevista,
                     telaAlteracaoFabricante, telaAlteracaoRevista):
            novaTela = tela(areaPrincipal, self)
            self.telasAplicacao[tela] = novaTela
            novaTela.grid(row=0, column=0, sticky=NSEW)

# Here I add the buttons that switch between frames

        btInicio = Button(barraOpcoes, text="Início", command=self.exibirTelaInicial)
        btInicio.grid(row=0, column=0, sticky=W)
        btFabricantes = Button(barraOpcoes, text="Fabricantes", command=self.exibirTelaCrudFabricante)
        btFabricantes.grid(row=0, column=1, sticky=W)
        btRevistas = Button(barraOpcoes, text="Revistas", command=self.exibirTelaCrudRevista)
        btRevistas.grid(row=0, column=2, sticky=W)
        btSair = Button(barraOpcoes, text="SAIR", command=lambda: sairCP2(self))
        btSair.grid(row=0, column=3, sticky=E)

# Always start with telaInicial on top: this is the welcome screen

        self.exibirTelaInicial()

    def exibirTela(self, t):
        minhaTela = self.telasAplicacao[t]
        minhaTela.exibirDados(codigo=kwargs["codigo"])
        minhaTela.lift()

    def exibirTelaInicial(self):
        self.exibirTela(telaInicial)

    def exibirTelaCrudFabricante(self):
        self.exibirTela(telaCrudFabricante)

    def exibirTelaCrudRevista(self):
        self.exibirTela(telaCrudRevista)

class telaAlteracaoFabricante(Frame):
    def __init__(self, parent, controller):
# lots of widgets on this frame
# also, all the other methods of this class

# and so on to all the other frames in telasAplicacao...

1 个答案:

答案 0 :(得分:1)

我认为我为您的选项找到了部分解决方案。有一个名为winfo_children的方法,并根据effbot.org文档:

  

返回包含此窗口小部件的所有子项的窗口小部件实例的列表。窗口从底部到顶部 的堆叠顺序返回。

现在,我已经创建了一个示例,说明了这种机制的工作原理。该示例基于"famous" Bryan Oakley's program on how to switch between frames。我添加了一个Text窗口小部件,显示self.container的堆叠顺序。为此,我使用了上面提到的winfo_children方法,该方法以堆叠顺序返回self.container的小部件。堆栈的顶部(可见小部件)是此列表的最后一个元素(如上所述),但我使用reversed函数将其显示为第一个元素。

import tkinter as tk
from tkinter import ttk


LARGE_FONT= ("Verdana", 12)


class MainWindowController(tk.Tk):

    def __init__(self, *args, **kwargs):        
        tk.Tk.__init__(self, *args, **kwargs)

        self.container = tk.Frame(self)
        self.container.grid_rowconfigure(0, weight=1)
        self.container.grid_columnconfigure(0, weight=1)
        self.container.pack(side="top", fill="both", expand=True)

        self.frames = {}

        for F in (StartPage, PageOne, PageTwo):
            frame = F(self.container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.so = tk.Text(self.container, state="disabled", font=("Arial", 14),
                          width=70, height=12, bd=1, relief="groove")
        self.so.grid(row=1, column=0, sticky="nsew", pady=(60, 0))
        self.update_stack_order()

        self.show_frame(StartPage)

    def update_stack_order(self):
        self.so.config(state="normal")
        self.so.delete("1.0", "end")
        self.so.insert("end", "Stack order of the widgets of self.container (0 means top)\n\n\n")
        for i, child in enumerate(reversed(self.container.winfo_children())):
            self.so.insert("end", str(i) + "\t" + repr(child) + "\n\n")
        self.so.config(state="disabled")

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()
        self.update_stack_order()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        label = ttk.Label(self, text="START PAGE", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button = ttk.Button(self, text="Visit Page 1",
                            command=lambda: controller.show_frame(PageOne))
        button.pack()

        button2 = ttk.Button(self, text="Visit Page 2",
                            command=lambda: controller.show_frame(PageTwo))
        button2.pack()


class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        label = ttk.Label(self, text="PAGE ONE", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button1 = ttk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.pack()

        button2 = ttk.Button(self, text="Page Two",
                            command=lambda: controller.show_frame(PageTwo))
        button2.pack()


class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        label = ttk.Label(self, text="PAGE TWO", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button1 = ttk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.pack()

        button2 = ttk.Button(self, text="Page One",
                            command=lambda: controller.show_frame(PageOne))
        button2.pack()


app = MainWindowController()
app.mainloop()

当您更改帧时,您肯定会注意到堆栈顺序会从Text小部件的输出发生变化。 (请注意,Text窗口小部件永远不会位于顶部。所以,现在您知道哪个框架位于容器的顶部,您可以继续使用第一个选项的想法。

如果您想进一步了解tkinter中“提升”和“降低”的工作原理,请查看Tk的官方文档,其中包含专门讨论此主题的部分:

  

http://wiki.tcl.tk/12752

代码不在Python中,因为Tk是一个Tcl库,但这些概念也适用于tkinter。