【问题标题】:How to open a frame without a button如何在没有按钮的情况下打开框架
【发布时间】:2022-11-13 05:01:51
【问题描述】:

我正在使用 Python 和 Tkinter 创建一个带有用户身份验证和注册以及主页框架的 GUI。

提交功能将验证数据库中的凭据,对用户进行身份验证,然后应自动将它们传输到主页框架。

如何在不使用按钮而是在函数内切换帧?

class Application(Tk):
    
    def __init__(self, *args, **kwargs):
        
        Tk.__init__(self, *args, **kwargs)
        container = 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 (UserLogin, HomePage, RegisterUser): 
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky = "nsew")
        
        self.show_frame(UserLogin)
        
    def show_frame(self, controller):
        
        frame = self.frames[controller]
        frame.tkraise()



class UserLogin(Frame):
    
    db = mysql.connector.connect(
            host="localhost",
            port="XXXX",
            user="XXXX",
            passwd="XXXX",
            database="XXXXX"
        )
        
    cursorObject = db.cursor()
    

    def __init__(self, parent, controller):
        
        Frame.__init__(self, parent)
        controller = self.controller
        
        self.title = Label(self, text="Welcomn!", font=("Arial", 15, 'bold'))
        self.title.grid(row=1, column=1)
        
        self.description = Label(self, text="Please login to get started:", font=("Arial", 10))
        self.description.grid(row=2, column=1, pady=25, sticky=W)
    
        self.usernametitle = Label(self, text="Username")
        self.usernametitle.grid(row=3, column=1, sticky=W)

        self.passwordtitle = Label(self, text="Password")
        self.passwordtitle.grid(row=4, column=1, sticky=W)

        self.username_input = Entry(self, width=30)
        self.username_input.grid(row=3, column=1, sticky=E)

        self.password_input = Entry(self, show="*", width=30)
        self.password_input.grid(row=4, column=1, sticky=E)

        self.submit_button = Button(self, text="Submit", command=self.submit)
        self.submit_button.grid(row=5, column=1, pady=10, sticky=W)

        self.register_button = Button(self, text="New user? Register here", command=lambda: controller.show_frame(RegisterUser))
        self.register_button.grid(row=6, column=1, sticky=W)
    
    
    def submit(self):
        username = self.username_input.get()
        password = self.password_input.get()
        
        if(username == ""):
            MessageBox.showinfo(title="Error", message="Username cannot be blank")
        if(password == ""):
            MessageBox.showinfo(title="Error", message="Password cannot be blank")
        else:
            self.loginto(username, password)
            **# then switch to homepage frame**
            UserLogin.controller.show_frame(Homepage)

    def loginto(self, username, password):
        query = "SELECT username, password FROM USER WHERE username ='" + username + "' AND password='" + password + "';"
        self.cursorObject.execute(query)
        myresult = self.cursorObject.fetchall()
        
        if myresult:
            print("success login")
            return True;
        else:
            MessageBox.showinfo(title="Error", message="Incorrect username and/or password")
            print("Incorrect")
            return False;

我曾尝试在该函数中调用show_frame 函数,但它不起作用。

我已经审查了这个:Tkinter Open New Frame Without A Button Press

但这也不起作用,因为它在submit 函数而不是__init__ 内部,因此没有控制器。

更新我添加了传递实例变量并获得以下回溯:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\c\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
    return self.func(*args)
  File "C:\Users\c\eclipse-workspace\Medix.py", line 88, in submit
    controller = UserLogin.self.controller
AttributeError: type object 'UserLogin' has no attribute 'self'

谢谢,

【问题讨论】:

  • 需要将传递给实例变量的controller保存起来,比如self.controller在UserLogin.__init__()里面,然后可以调用self.controller.show_frame(HomePage)来切换帧。
  • 谢谢!我试过了,添加了自我。 UserLogin.__init__() 中的控制器,然后尝试在提交函数中调用它,但给了我一个属性错误!
  • 什么属性错误?使用更改和完整回溯更新您的问题。
  • 您需要创建一个UserLogin 实例。例如,login = UserLogin()/login.controller.show_frame(Homepage)。
  • 谢谢蒂姆!这样,我得到以下回溯: TypeError: UserLogin.__init__() missing 2 required positional arguments: 'parent' 和 'controller'.. 如果我尝试将它们添加到参数中,它仍然会失败。

标签: python tkinter frames


【解决方案1】:

很难给你答案,因为你的代码不完整。您还提供与您的 GUI 不相关的部分代码(例如与数据库的连接)。

所以我们必须做很多猜测才能给你一个有用的答案。这并不能帮助您获得适当的答案。但是让我们尝试一下。

对您的代码进行最少的修改可能如下所示:

from tkinter import Tk, W, E
from tkinter.ttk import Frame, Label, Entry, Button
from tkinter import messagebox
import mysql.connector

class Application(Tk):
    
    def __init__(self, *args, **kwargs):
        
        Tk.__init__(self, *args, **kwargs)
        container = 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 (UserLogin, HomePage, RegisterUser): 
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky = "nsew")
        
        self.show_frame(UserLogin)
        
    def show_frame(self, controller):
        
        frame = self.frames[controller]
        frame.tkraise()



class UserLogin(Frame):
    
    db = mysql.connector.connect(
            host="localhost",
            port="XXXX",
            user="XXXX",
            passwd="XXXX",
            database="XXXXX"
        )
        
    cursorObject = db.cursor()
    

    def __init__(self, parent, controller):
        
        Frame.__init__(self, parent)
        self.controller = controller
        
        self.title = Label(self, text="Welcomn!", font=("Arial", 15, 'bold'))
        self.title.grid(row=1, column=1)
        
        self.description = Label(self, text="Please login to get started:", font=("Arial", 10))
        self.description.grid(row=2, column=1, pady=25, sticky=W)
    
        self.usernametitle = Label(self, text="Username")
        self.usernametitle.grid(row=3, column=1, sticky=W)

        self.passwordtitle = Label(self, text="Password")
        self.passwordtitle.grid(row=4, column=1, sticky=W)

        self.username_input = Entry(self, width=30)
        self.username_input.grid(row=3, column=1, sticky=E)

        self.password_input = Entry(self, show="*", width=30)
        self.password_input.grid(row=4, column=1, sticky=E)

        self.submit_button = Button(self, text="Submit", command=self.submit)
        self.submit_button.grid(row=5, column=1, pady=10, sticky=W)

        self.register_button = Button(self, text="New user? Register here", command=lambda: self.controller.show_frame(RegisterUser))
        self.register_button.grid(row=6, column=1, sticky=W)
    
    
    def submit(self):
        username = self.username_input.get()
        password = self.password_input.get()
        
        if(username == ""):
            messagebox.showinfo(title="Error", message="Username cannot be blank")
        if(password == ""):
            messagebox.showinfo(title="Error", message="Password cannot be blank")
        else:
            self.loginto(username, password)
            # then switch to homepage frame**
            self.controller.show_frame(Homepage)

    def loginto(self, username, password):
        query = "SELECT username, password FROM USER WHERE username ='" + username + "' AND password='" + password + "';"
        self.cursorObject.execute(query)
        myresult = self.cursorObject.fetchall()
        
        if myresult:
            print("success login")
            return True;
        else:
            messagebox.showinfo(title="Error", message="Incorrect username and/or password")
            print("Incorrect")
            return False;

但我无法对此进行测试,因为缺少HomePage 和RegisterUSer,而我觉得没有必要安装 MySQL 连接器/Python 模块。

但这里有一个可行的解决方案:

mport tkinter as tk
from tkinter import ttk
import tkinter.messagebox as messagebox

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

        self.title("StackOverflow Question 74249473")
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)
        
        background = Background_Frame(self, padding=(10, 10, 10, 10))
        background.grid(column=0, row=0, sticky=(tk.N, tk.W, tk.E, tk.S))

class Background_Frame(ttk.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.frames = {
            'login': User_login(self, change_frame=self.change_frame_to), 
            'home': Home_page(self), 
            'register': Register_user(self, change_frame=self.change_frame_to)
        }

        for frame in self.frames.values():
            frame.grid(column=0, row=0, sticky=(tk.N, tk.W, tk.E, tk.S))
        
        self.change_frame_to('login')
    
    def change_frame_to(self, page_to_show):
        frame_to_show = self.frames[page_to_show]
        frame_to_show.tkraise()

class User_login(ttk.Frame):
    def __init__(self, parent, change_frame, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)

        self.change_frame_to = change_frame

        title = ttk.Label(self, text="Welcomn!", font=("Arial", 15, 'bold'))
        title.grid(row=1, column=0)
        
        description = ttk.Label(self, text="Please login to get started:", font=("Arial", 10))
        description.grid(row=2, column=0, pady=25, sticky=tk.W)
    
        username_title = ttk.Label(self, text="Username")
        username_title.grid(row=3, column=0, sticky=tk.W)

        password_title = ttk.Label(self, text="Password")
        password_title.grid(row=4, column=0, sticky=tk.W)

        self.authentication_information = {
            'Username': tk.StringVar(),
            'Password': tk.StringVar()
        }
        
        username_input = ttk.Entry(self, width=30, textvariable=self.authentication_information['Username'])
        username_input.grid(row=3, column=1, sticky=tk.E)

        password_input = ttk.Entry(self, show="*", width=30, textvariable=self.authentication_information['Password'])
        password_input.grid(row=4, column=1, sticky=tk.E)

        submit_button = ttk.Button(self, text="Submit", command=self.submit)
        submit_button.grid(row=5, column=0, pady=10, sticky=tk.W)

        register_button = ttk.Button(self, text="New user? Register here", command=lambda : self.change_frame_to('register'))
        register_button.grid(row=5, column=1, sticky=tk.E)

    def submit(self):
        error_message = '
'.join(
            f'{info} cannot be blank' 
            for (info, value) in self.authentication_information.items() if not value.get()
        )

        if error_message:
            messagebox.showerror(title="Error", message=error_message)
        else:
            if self.check_authentication():
                self.change_frame_to('home')
            else:
                messagebox.showerror(title="Error", message="Incorrect username and/or password")

    def check_authentication(self):
        # Use the information from self.authentication_information to 
        # compare with the information from the database
        # 
        # But here in this example we will return True or false randomly
        import random

        return random.choice((True, False))


class Home_page(ttk.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        description = ttk.Label(self, text="This is the home page", font=("Arial", 20))
        description.grid(row=0, column=0, sticky=(tk.N, tk.E, tk.S, tk.W))

class Register_user(ttk.Frame):
    def __init__(self, parent, change_frame, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)

        self.change_frame_to = change_frame

        description = ttk.Label(self, text="Please register:", font=("Arial", 10))
        description.grid(row=2, column=0, pady=25, sticky=tk.W)
    
        username_title = ttk.Label(self, text="Username")
        username_title.grid(row=3, column=0, sticky=tk.W)

        password_title = ttk.Label(self, text="Password")
        password_title.grid(row=4, column=0, sticky=tk.W)

        password_confirmation = ttk.Label(self, text='Password confirmation')
        password_confirmation.grid(row=5, column=0, sticky=tk.W)
        
        self.authentication_information = {
            'Username': tk.StringVar(),
            'Password': tk.StringVar(),
            'Password confirmation': tk.StringVar(),
        }
        
        username_input = ttk.Entry(self, width=30, textvariable=self.authentication_information['Username'])
        username_input.grid(row=3, column=1, sticky=tk.E)

        password_input = ttk.Entry(self, show="*", width=30, textvariable=self.authentication_information['Password'])
        password_input.grid(row=4, column=1, sticky=tk.E)

        password_confirmation = ttk.Entry(self, show="*", width=30, textvariable=self.authentication_information['Password confirmation'])
        password_confirmation.grid(row=5, column=1, sticky=tk.E)

        submit_button = ttk.Button(self, text="Submit", command=self.submit)
        submit_button.grid(row=6, column=0, pady=10, sticky=tk.W)

    def submit(self):

        if (self.authentication_information['Password'].get() 
            != self.authentication_information['Password confirmation'].get()):
            messagebox.showerror(title="Registering", message="The password field and its confirmation are not the same")
        else:
            # You would probably record that information in your database.
            messagebox.showinfo(title='Registering', message='Registration has been completed')
            self.change_frame_to('home')


root = Application()
root.mainloop()

我不得不做很多假设,这远非生产水平。这与你相关吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-04
    • 2020-07-28
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    • 2016-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多