与我提出的另一个问题类似,但觉得这可能是经过深思熟虑后才能解决的问题。
我想要的是让用户选择两个单选按钮中的一个,点击“下一页”按钮并将其带到一帧。在该帧类中,将有两个标签,但根据前一帧中选择的单选按钮,我希望出现两个标签中的一个
这是我的代码 -
import Tkinter as tk
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the main container that holds all the frames
container = tk.Frame(self)
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0,weight = 1)
self.frames = {}
# adding frames to the dictionary
for F in (Page1,Page2):
frame = F(container,self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "w")
self.show_frame(Page1)
def show_frame(self,page_name):
#SHOWS A FRAME WITH THE GIVEN NAME
for frame in self.frames.values():
frame.grid_remove()
frame = self.frames[page_name]
frame.grid()
#STACKING THE FRAMES
#frame = self.frames[cont]
#frame.tkraise()
class Page1(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lbl1 = tk.Label(self,text = "Yes",font =("Helvetica",12,"bold"))
lbl1.grid(row=1,sticky="W")
lbl2 = tk.Label(self,text = "No",font =("Helvetica",12,"bold"))
lbl2.grid(row=1,column=1,sticky="W")
btn1 = tk.Button(self, text="next page", font=('MS', 24, 'bold'))
btn1.grid(row=3,column = 0,columnspan=1)
self.var1 = tk.BooleanVar()
rButton1 = tk.Radiobutton(self,variable = self.var1,value=True)
rButton1.grid(row=2,sticky = "W")
rButton2 = tk.Radiobutton(self,variable = self.var1,value=False)
rButton2.grid(row=2,column=1,sticky = "W")
btn1['command']= lambda: controller.show_frame(Page2)
class Page2(tk.Frame,Page1):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
self.var1 = Page1.var1
lbl = tk.Label(self,text="This is reccomendation 2",font=("Helvetica",12,"bold"))
lbl.pack_forget()
lbl1 = tk.Label(self,text="This is reccomendation 3",font=("Helvetica",12,"bold"))
lbl1.pack_forget()
# if self.var1.get() == 0:
# lbl.pack()
# else:
# lbl1.pack()
所以有两件事,首先,我假设Page2必须继承Page1的self.var1,我尝试用它来做 -
class Page2(tk.Frame,Page1):
但只收到此错误消息 -
self.var1 = Page1.var1
AttributeError: class Page1 has no attribute 'var1'
哪个,我觉得奇怪,因为第1页有var1?!其次,我甚至不确定pack_forget()方法是否是实现此目的的正确方法?
更新4/4/16
经过一番挖掘后,我发现了StringVar变量。
所以实施后 -
def get_page(self,className):
for page in self.frames.values():
if str(page.__class__.__name__) == className:
return page
return None
在控制器中,我现在可以访问第1页的self.var1
我更新了单选按钮 -
self.var1 = tk.StringVar()
rButton1 = tk.Radiobutton(self,variable = self.var1,value="reco 1"
,command = "this is reco 1")
rButton1.grid(row=2,sticky = "W")
rButton2 = tk.Radiobutton(self,variable = self.var1,value="reco 2"
,command = "this is reco 2")
rButton2.grid(row=2,column=1,sticky = "W")
从我收集的有关StringVar的内容中,根据选择的单选按钮,与单选按钮关联的字符串存储在String Var中?可能完全错了......无论如何,我现在更新了第2页 -
class Page2(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
self.controller = controller
page_one = self.controller.get_page("Page1")
# Access to Page1's self.var1
reco = page_one.var1.get()
lbl = tk.Label(self,text= reco,font=("Helvetica",12,"bold"))
lbl.pack()
程序运行,但令人沮丧的是它没有按我的意愿运行,只要下一页按钮被按下,第二帧就不会出现任何内容。通过这个思考过程,我是朝着正确的方向前进,还是有另一种方法可以做到这一点?无论哪种方式,文字必须出现在下一帧。
答案 0 :(得分:0)
这有很多问题,但我试着采用与你使用的方法类似的方法。它有效......但我通常采取一种截然不同的方法。
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the main container that holds all the frames
container = tk.Frame(self)
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0,weight = 1)
def show_1(button):
self.frame_2.grid_remove()
self.frame_1.show(button)
def show_2(button):
self.frame_1.grid_remove()
self.frame_2.show(button)
self.frame_1 = Page1(container, show_2)
self.frame_2 = Page2(container, show_1)
class Page1(tk.Frame):
def __init__(self,parent,callback):
tk.Frame.__init__(self,parent)
self.grid(row = 0, column = 0, sticky = "w")
self.callback = callback
lbl1 = tk.Label(self,text = "Yes",font =("Helvetica",12,"bold"))
lbl1.grid(row=1,sticky="W")
lbl2 = tk.Label(self,text = "No",font =("Helvetica",12,"bold"))
lbl2.grid(row=1,column=1,sticky="W")
btn1 = tk.Button(self, text="next page", font=('MS', 24, 'bold'))
btn1.grid(row=3,column = 0,columnspan=1)
self.var1 = tk.BooleanVar()
rButton1 = tk.Radiobutton(self,variable = self.var1,value=True)
rButton1.grid(row=2,sticky = "W")
rButton2 = tk.Radiobutton(self,variable = self.var1,value=False)
rButton2.grid(row=2,column=1,sticky = "W")
btn1['command']= self.button_clicked
def button_clicked(self):
if self.var1.get():
self.callback('button_one')
else:
self.callback('button_two')
class Page2(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
def show(self, selected_button):
if selected_button == 'button_one':
text = "This is reccomendation 2"
elif selected_button == 'button_two':
text = "This is reccomendation 3"
else:
text = selected_button
print(selected_button)
lbl = tk.Label(self,text=text,font=("Helvetica",12,"bold"))
lbl.pack()
self.grid()
app = MainApp()
app.mainloop()
如果我只是使用Tkinter,我可能会使用更像这样的东西:
import random
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class Choices(tk.Frame):
def __init__(self, choice_a, choice_b, callback):
super().__init__()
self._choice = tk.StringVar()
self.left_button = tk.Radiobutton(
self,
variable=self._choice,
text=choice_a,
value=choice_a,
)
self.left_button.grid(row=0, column=0, sticky=tk.W)
self.right_button = tk.Radiobutton(
self,
variable=self._choice,
text=choice_b,
value=choice_b
)
self.right_button.grid(row=0, column=1, sticky=tk.E)
self._choice.set(choice_a)
self.next_button = tk.Button(self, text='Next', command=callback)
self.next_button.grid(row=1, column=0, columnspan=2)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1)
@property
def choice(self):
return self._choice.get()
@property
def choice_a(self):
return self.left_button['text']
@choice_a.setter
def choice_a(self, value):
self.left_button.config(text=value, value=value)
@property
def choice_b(self):
return self.right_button['text']
@choice_b.setter
def choice_b(self, value):
self.right_button.config(text=value, value=value)
class PossibleSelections(tk.Frame):
def __init__(self, root, selections, command):
super().__init__(root)
self.command = command
self.show_selections(selections)
def show_selections(self, selections):
for widget in self.winfo_children():
widget.destroy()
for selection in selections:
tk.Label(self, text=selection).pack()
tk.Button(self, command=self.command).pack()
class Example(tk.Tk):
def __init__(self):
super().__init__()
self.title('Example Chooser')
self.choice_frame = Choices(
'Do you like this?',
'Do you like that?',
self.show_options,
)
self.choice_frame.pack()
self.selections_frame = PossibleSelections(self, [], self.show_choices)
def show_options(self):
self.choice_frame.pack_forget()
self.selections_frame.show_selections(
random.sample('ABCDEF', 3)+[self.choice_frame.choice],
)
self.selections_frame.pack()
def show_choices(self):
self.selections_frame.pack_forget()
options = random.sample([
'My favorite color is blue',
'My favorite color is yellow',
'My favorite color is blu-no, yelloooooow!',
'I seek the grail',
'My name is Arthur, King of the Britons',
], 2)
self.choice_frame.choice_a = options[0]
self.choice_frame.choice_b = options[1]
self.choice_frame.pack()
if __name__ == '__main__':
Example().mainloop()
在您当前的方法中,您正在做一些大多数其他Python开发人员会发现奇怪的事情,比如保留一个框架字典。这不是必然错误的方法,但可能有更好的方法。如果你有一个未知或无限数量的帧,这可能是一个很好的方法。但实际上你可能会有两个。让它们成为属性是一种很好的方法。
第二种方法的另一个优点是被称为关注点分离。 PossibleSelections
或Choices
框架彼此之间没有任何关系。他们对在其他类中找到的属性一无所知,或者甚至不知道其他类存在的属性。这是一件好事,因为这意味着如果你需要在Choices
完成时发生不同的事情,你只需要改变Example
所做的事情。你不需要摆弄Choices
。这意味着你将有更少的机会来引入错误,如果你需要改变一些东西,你会有更多的灵活性。
最后,通过使用widget.destroy()
vs _forget()
,我们实际上正在销毁我们不再需要的小部件。如果我们只是调用_forget()
,那么我们会将这些小部件保留在内存中。当然,如果您的应用程序只通过10个屏幕,您可能不会注意到内存泄漏,但如果您的应用程序增长,您将最终耗尽内存并且您的应用程序将崩溃。
当然,如果我真的在编写一个不仅仅是玩具/作业的应用程序,我可能会使用某种类型的Model-View-Presenter架构变体。使用这种架构,您可以编写应用程序,使您的UI层(所有Tkinter类)只处理与用户的接口。您的实际核心逻辑可以在您的模型类中找到,并通过演示者进行连接。这可能是过度的,但它可能是一个有用的练习。