我的应用程序由一个包含两个较小框架的大框架(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...
答案 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的官方文档,其中包含专门讨论此主题的部分:
代码不在Python中,因为Tk是一个Tcl库,但这些概念也适用于tkinter。