Tkinter - 了解如何切换帧 [英] Tkinter - Understanding how to switch frames

查看:50
本文介绍了Tkinter - 了解如何切换帧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试自学如何使用 tkinter,但我通过 youtube 找到了一段有用的代码,但我并不完全理解.如果有人能帮助我理解它,我将不胜感激.用# ... **标记我不明白的东西.

import tkinter as tk # 为什么不从 tkinter 导入?**class SampleApp(tk.Tk): # 为什么是 tk.TK **def __init__(self, *args, **kwargs):tk.Tk.__init__(self, *args, **kwargs)# 容器是我们堆叠一堆帧的地方# 在彼此之上,然后是我们想要可见的那个# 将高于其他人容器 = 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 = {}对于 F 输入(StartPage、PageOne、PageTwo):page_name = F.__name__框架 = F(容器,自我)# **self.frames[page_name] = 框架 # **# 把所有的页面放在同一个位置;# 堆叠顺序顶部的那个# 将是可见的.frame.grid(row=0, column=0,sticky=nsew")self.show_frame(StartPage")def show_frame(self, page_name):'''显示给定页面名称的框架'''frame = self.frames[page_name]frame.tkraise() # **类 StartPage(tk.Frame):def __init__(self, parent, controller):tk.Frame.__init__(self, parent) # **self.controller = 控制器# **label = tk.Label(self, text="This is the start page",字体=TITLE_FONT)label.pack(side="top", fill="x", pady=10)button1 = tk.Button(self, text =转到第一页",命令= lambda:controller.show_frame(PageOne"))button2 = tk.Button(self, text="转到第二页",命令= lambda:controller.show_frame(PageTwo"))button1.pack()button2.pack()

解决方案

import tkinter as tk # 为什么不从 tkinter 导入?**

为什么不 from tkinter import *?因为那是错误的做法.全球进口不好.由于某种我不明白的原因,Tkinter 教程倾向于以错误的方式进行操作.

as tk 部分的原因是你可以做 tk.Frame 而不是 tkinter.Frame,使代码成为更容易打字和更容易阅读.这是完全可选的.


class SampleApp(tk.Tk):

tk 是导入的 tkinter 模块的名称.Tk 是该模块中代表根窗口的类的名称.每个 tkinter 应用程序都必须有一个根窗口.通过将其放置在 SampleApp 中,这将创建此小部件的子类——具有附加功能的副本.

没有必要从 tk.Tk 继承.您可以从 tk.Frame、任何其他 tkinter 小部件,甚至 object 继承.这是个人喜好.选择让一些事情更容易,一些事情更难.


container = tk.Frame(self)

上面创建了一个 Frame 小部件的实例,它将用作其他页面"的容器.这些页面"将全部堆叠在此容器中.


frame = F(container, self)

F 是循环变量.循环遍历一个类列表,所以每次通过循环 F 将代表一个类.F(...) 创建类的一个实例.这些类(StartPagePageOnePageTwo)都需要两个参数:一个是这个类的父类的小部件,以及一个对象将作为控制器(从 UI 模式 model/view/controller 借用的术语).

这行代码创建了一个类的实例(它本身是一个 Frame 小部件的子类),并将框架临时分配给局部变量 frame.

通过将 self 作为第二个(controller")参数传递,这些新的类实例将能够调用 SampleApp 类对象中的方法.

这会在字典中保存对刚刚创建的框架的引用.字典的关键是页面名称(或者更准确地说,是类的名称).

这就是 show_frame 方法如何仅根据类的名称确定实际页面小部件的方式.

在循环中创建框架在功能上等同于以下内容:

f1 = StartPage(container, self)f2 = PageOne(容器,自身)f3 = PageTwo(容器,自身)f1.grid(row=0, column=0,sticky=nsew")f2.grid(row=0, column=0,sticky=nsew")f3.grid(row=0, column=0,sticky=nsew")self.frames = {StartPage":f1,PageOne":f2,PageTwo":f3}


frame.tkraise()

在几乎所有的 GUI 工具包中——包括 tkinter——都有堆叠顺序"的概念:事物堆叠的顺序.一些工具包可能将此称为 z 顺序.如果两个或多个小部件相互堆叠(此代码通过将所有页面放在同一行和列中来实现),则位于堆栈顶部的小部件通常是可见的小部件.

tkraise 是一个 Frame 对象的方法,它将把框架提升到堆叠顺序的顶部.在这行代码中,frame 指的是其中一个页面的一个特定实例.


tk.Frame.__init__(self, parent)

因为每个页面都是一个tk.Frame 类的子类,这就调用了父类的构造函数.这对于初始化构成实际框架小部件的所有内部结构是必要的.尽管 Frame 可以有很多选项,但这段代码选择只发送一个 - 对另一个小部件的引用,该小部件将充当这个新小部件的父级.


self.controller = 控制器

上面的代码只是简单地记住"了传入的 controller 变量的值.在这种情况下,controller 是应用程序.通过保存它,这个类可以调用 SampleApp 对象上的方法.


注意:问题中的代码来自从这个答案复制代码的教程:https://stackoverflow.com/a/7557028/7432.我是原始代码的作者,但不是教程的作者.在该原始答案中,提供了与此代码相关的其他问题的链接.

Im trying to teach my self how to use tkinter and I found a useful code through youtube that I don't really fully understand. Would appreciate it if some could help me understand it. Marked the things I did not understand with # ... **.

import tkinter as tk  # why not from tkinter import? **

class SampleApp(tk.Tk): # why tk.TK **

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

        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others

        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 = {}
        for F in (StartPage, PageOne, PageTwo):
            page_name = F.__name__
            frame = F(container, self) # **
            self.frames[page_name] = frame # **

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise() # **


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent) # **
        self.controller = controller # **
        label = tk.Label(self, text="This is the start page",
                         font=TITLE_FONT)
        label.pack(side="top", fill="x", pady=10)

        button1 = tk.Button(self, text="Go to Page One",
                            command=lambda: controller.show_frame("PageOne"))
        button2 = tk.Button(self, text="Go to Page Two",
                            command=lambda: controller.show_frame("PageTwo"))
        button1.pack()
        button2.pack()

解决方案

import tkinter as tk  # why not from tkinter import? **

Why not from tkinter import *? Because that is the wrong way to do it. Global imports are bad. Tkinter tutorials tend to do it the wrong way for some reason that I don't understand.

The reason for the as tk part is so that you can do tk.Frame rather than tkinter.Frame, making the code a little easier to type and a little easier to read. It's completely optional.


class SampleApp(tk.Tk): 

tk is the name of the tkinter module that was imported. Tk is the name of a class in that module that represents the root window. Every tkinter application must have a single root window. By placing it inside of SampleApp, this creates a subclass of this widget -- a copy that has additional features.

It's not necessary to inherit from tk.Tk. You can inherit from tk.Frame, any other tkinter widget, or even object. It's a personal preference. The choice makes some things easier, some things harder.


container = tk.Frame(self)

The above creates an instance of a Frame widget, which will be used as a container for other "pages". These "pages" will all be stacked on top of each other in this container.


frame = F(container, self)

F is the loop variable. The loop is iterating over a list of classes, so each time through the loop F will be representing a class. F(...) creates an instance of the class. These classes (StartPage, PageOne, PageTwo) all require two parameters: a widget that will be the parent of this class, and an object that will server as a controller (a term borrowed from the UI patter model/view/controller).

The line of code creates an instance of the class (which itself is a subclass of a Frame widget), and temporarily assigns the frame to the local variable frame.

By passing self as the second ("controller") parameter, these new class instances will be able to call methods in the SampleApp class object.

This saves a reference to the just-created frame in a dictionary. The key to the dictionary is the page name (or more accurately, the name of the class).

This is how the show_frame method can determine the actual page widget just from the name of the class.

Creating the frames in a loop is functionally equivalent to the following:

f1 = StartPage(container, self)
f2 = PageOne(container, self)
f3 = PageTwo(container, self)

f1.grid(row=0, column=0, sticky="nsew")
f2.grid(row=0, column=0, sticky="nsew")
f3.grid(row=0, column=0, sticky="nsew")

self.frames = {"StartPage": f1, "PageOne": f2, "PageTwo": f3}


frame.tkraise() 

In nearly all GUI toolkits -- tkinter included -- there is the notion of a "stacking order": the order in which things are stacked. Some toolkits might call this the z-order. If two or more widgets are stacked on top of each other (which this code does by putting all pages in the same row and column), the widget that is on the top of the stack is the widget that will typically be visible.

tkraise is a method of a Frame object that will raise the frame to the top of the stacking order. In this line of code, frame refers to one particular instance of one of the pages.


tk.Frame.__init__(self, parent)

Because each page is a subclass of a tk.Frame class, this calls the constructor of the parent class. This is necessary to initialize all of the internal structures that make up the actual frame widget. Although a Frame can take many options, this code chooses to send in only one -- a reference to another widget which is to act as the parent of this new widget.


self.controller = controller

The above code is simply "remembering" the value of the controller variable which was passed in. In this case, the controller is the application. By saving it off, this class can call methods on the SampleApp object.


Note: the code in the question came from a tutorial that copied code from this answer: https://stackoverflow.com/a/7557028/7432. I am the author of that original code, but not the author of the tutorial. In that original answer are links to other questions related to this code.

这篇关于Tkinter - 了解如何切换帧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆