【问题标题】:Python Tkinter GUI Frame: How to call a class method from inside a function of another class?Python Tkinter GUI Frame:如何从另一个类的函数内部调用类方法?
【发布时间】:2016-02-21 01:48:41
【问题描述】:

我正在尝试为我的程序创建登录脚本。我能够编写一个基本脚本来测试我的登录框架,但现在我基本上登录后能够访问另一个框架。

这是我的脚本的一部分:

#!/usr/bin/python


from tkinter import *
from tkinter import ttk

import tkinter as tk
import tkinter.messagebox as tm


Large_Font = ("Verdana", 18)
Small_Font = ("Verdana", 12)


class ATM(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.wm_title(self, "ATM Simulator")

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

        #Create Frame Library and use For Loop to switch between frames

        self.frames = {}

        for i in (LogIn, WelcomePage, Checking, Savings, Transfer):

            frame = i(container, self)
            self.frames[i] = frame 
            frame.grid(row= 100, column = 100, sticky= "nsew")

        self.show_frame(LogIn)

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

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

        global act_num_entry
        global pin_num_entry

        label = Label(self, text = "Login Using Account and PIN Numbers", font=Small_Font)
        label.pack(pady=50, padx=50)

        act_num_label = Label(self, text="Account Number")
        act_num_entry = Entry(self)

        pin_num_label = Label(self, text="PIN Number")
        pin_num_entry = Entry(self, show="*")

        act_num_label.pack(pady=5, padx=5)
        pin_num_label.pack(pady=5, padx=5)

        act_num_entry.pack(pady=5, padx=5)
        pin_num_entry.pack(pady=5, padx=5)


        logBTN = ttk.Button(self, text="Enter", 
                            command =self.log_check)
        logBTN.pack()

        quitButton = ttk.Button(self, text = "End Transaction", command = quit)
        quitButton.pack()

    def log_check(self):

        #default test pin and account numbers 

        act_num=1234567
        pin_num=1234   

        #This Try/Except handles the non-integer values being entered

        try:
            actNum = int(act_num_entry.get())
            pinNum = int(pin_num_entry.get())
        except:
            tm.showerror("Login Error", "Invalid Entry")
            pass

        if actNum == act_num and pinNum == pin_num:

            #Message Window only used to to prove my log_check function works

            tm.showinfo("ATM Login", "Login Successful")


            '''Insert script to open the WelcomePage(tk.Frame) method'''


        elif actNum != act_num:
            tm.showerror("Login Error", "Invalid Account Number")
        elif pinNum != pin_num:
            tm.showerror("Login Error", "Invalid PIN Number")
        else:
            tm.showerror("Login Error", "Invalid Entry")

class WelcomePage(tk.Frame):

    #Welcome Page Window

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = Label(self, text = "Welcome to the ATM Simulator", font = Large_Font)
        label.pack(pady=100, padx=100)

        checkButton = ttk.Button(self, text = "Checking Account", 
                             command = lambda: controller.show_frame(Checking))
        checkButton.pack()

        saveButton = ttk.Button(self, text = "Savings Account", 
                            command = lambda: controller.show_frame(Savings))
        saveButton.pack()

        transButton = ttk.Button(self, text = "Transfer Funds", 
                            command = lambda: controller.show_frame(Transfer))
        transButton.pack()

        quitButton = ttk.Button(self, text = "End Transaction", command = self.client_exit)
        quitButton.pack()

    def client_exit(self):
        exit()

所以我想从我的内部调用我的WelcomePage(tk.Frame) 方法 if actNum == act_num and pinNum == pin_num: 函数,所以我基本上可以登录到我的程序。我尝试使用我的 show_frame 函数访问WelcomePage(tk.Frame),但我无法访问,因为我知道该函数是ATM(tk.Tk) 类而不是LogIn(tk.Frame) 的一部分。这是否可以完成我想要的方式,或者我将不得不编写另一个登录脚本来完成这个?

【问题讨论】:

  • 小心术语:WelcomePage(tk.Frame) 不是一种方法。 WelcomePage 是一个类。您不“调用”类,而是“实例化”它们(即:创建它们的实例)。

标签: python user-interface python-3.x tkinter


【解决方案1】:

show_frame 是控制器上的一个方法。您只需要保存对控制器的引用,然后从任何地方调用它。这就是控制器类的全部目的——控制对其他窗口的访问。

第一步是修改你的类以保存对控制器的引用:

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

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

现在,您可以随时随地拨打show_frame:

if actNum == act_num and pinNum == pin_num:
    ...
    self.controller.show_frame(WelcomePage)
    ...

有关控制器的更多信息,请参阅此答案:https://stackoverflow.com/a/32865334/7432

【讨论】:

  • 非常感谢!在我的其他框架中,我将“self.controller = controller”放在我的类中,但我忘记更新 WelcomePage() 和我的 LogIn() 类。我没有意识到我忘了在这两个类中提到我的控制器。
【解决方案2】:

在LogIn 内部,使用parent 访问ATM,您拥有self.frames[WelcomePage]

self.parent.frames[WelcomePage].some_function()

您可能需要添加LogIn.__init__ 行

self.parent = parent

编辑:

因为LogIn在container里面,在ATM里面你有使用

self.parent.master.show_frame(WelcomePage)

或者你可以使用

self.master.master.show_frame(WelcomePage)

然后就不用加self.parent = parent

【讨论】:

  • 虽然从技术上讲您的答案会起作用,但这并不是 OP 代码的设计方式。它有一个controller,专门设计用于从任何其他页面打开任何页面,同时保持两个页面松散耦合。
  • 现在我明白了。我没有注意到这个元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-03
相关资源
最近更新 更多