使用 Tkinter 注册和登录问题

Register and login issue using Tkinter

我正在使用 tkinter 制作登录和注册系统。我有多个 类 所以我可以让它看起来像一个有多个页面的网站。它看起来像这样:

所以我的问题是:当我注册一个新帐户时,它会将用户名和密码写入一个 txt 文件。现在我试图让它在用户名已经存在时给出错误。我试着用一个简单的 if 语句来做到这一点。这在另一个文件中有效,但在使用这些 类 时却不起作用。这是注册代码:

def register_user():


    with open('user_data.txt', 'r+') as f:
        username_info = username.get()
        password_info = password.get()
        for line in f:
            if username_info not in line:
                f.write(username_info + ',')
                f.write(password_info + '\n')
            else:
                Label(text='This user already exists!').pack()

    username_entry.delete(0, END)
    password_entry.delete(0, END)

谁能帮我解决这个问题?提前致谢!

下面我将展示我的全部代码和我的文本文件:

import tkinter as tk
from tkinter import *

class Page(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

class Page1(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       Label(self, text='').pack()
       Label(self, text='').pack()
       Label(self, text='').pack()
       Label(self, text="Hello welcome to Break-Through!").pack()



class Page2(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)

       username = StringVar()
       password = StringVar()

       Label(self, text='').pack()
       Label(self, text='').pack()
       Label(self, text='').pack()
       Label(self, text='Please enter details below').pack()
       Label(self, text='').pack()
       Label(self, text='Username * ').pack()
       Entry(self, textvariable=username).pack()
       Label(self, text='Password * ').pack()
       Entry(self, textvariable=password).pack()
       Label(self, text='').pack()
       Button(self, text='Login', width=10, height=1).pack()


def register_user():


    with open('user_data.txt', 'r+') as f:
        username_info = username.get()
        password_info = password.get()
        for line in f:
            if username_info not in line:
                f.write(username_info + ',')
                f.write(password_info + '\n')
            else:
                Label(text='This user already exists!').pack()

    username_entry.delete(0, END)
    password_entry.delete(0, END)


class Page3(Page):
    def __init__(self, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)

        global username
        global password
        global username_entry
        global password_entry

        username = StringVar()
        password = StringVar()

        Label(self, text='').pack()
        Label(self, text='').pack()
        Label(self, text='').pack()
        Label(self, text='Please enter details below').pack()
        Label(self, text='').pack()
        Label(self, text='Username * ').pack()
        username_entry = Entry(self, textvariable=username)
        username_entry.pack()
        Label(self, text='Password * ').pack()
        password_entry = Entry(self, textvariable=password)
        password_entry.pack()
        Label(self, text='').pack()
        Button(self, text='Register', width=10, height=1, command=register_user).pack()




class MainView(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        p1 = Page1(self)
        p2 = Page2(self)
        p3 = Page3(self)

        buttonframe = tk.Frame(self)
        container = tk.Frame(self)
        buttonframe.pack(side="top", fill="x", expand=False)
        container.pack(side="top", fill="both", expand=True)

        p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p2.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p3.place(in_=container, x=0, y=0, relwidth=1, relheight=1)


        main_screen = tk.Button(buttonframe, text="Main-Screen", width=30, height=2, command=p1.show)
        login = tk.Button(buttonframe, text="Login", width=30, height=2, command=p2.show)
        register = tk.Button(buttonframe, text="Register", width=30, height=2, command=p3.show)

        main_screen.pack(side='left')
        login.pack(side='left')
        register.pack(side='left')



        p1.show()

if __name__ == "__main__":
    root = tk.Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("800x800")
    root.mainloop()

这是带有用户数据的文本文件的样子。但它不断追加已经存在的用户

a,a
b,b
c,c
d,d

问题是由您打开和读取文件的方式引起的。当您使用 with open('user_data.txt', 'r+') as f: 时,您会得到一个文件对象 f。这不是文件的文本内容,而是代表它的对象。文件对象也是一个迭代器,这就是 for line in f 起作用的原因,因为您可以遍历文件中的行,但这不是读取文件的正确方法。问题是当你使用 f.write 时,迭代器停止工作,所以程序只检查文件的第一行。使用 for line in f.read().splitlines() 而不是 for line in f.read() 从文件对象中获取文本内容。这是一个带有换行符的字符串。要将其转换为行列表,我们可以使用 .splitlines()。这会将文本块变成行列表。因为我们不再依赖 f 迭代器,for 循环将查看文件中的每一行。

这会导致第二个问题 - 对于文件中的每一行你检查这个名字以前是否被使用过,所以对于没有使用过的每一行,你插入另一个。这意味着您最终会多次插入记录,这是您不希望的。要解决此问题,您需要先检查用户名是否唯一,然后写入新记录。这是一个固定的 register_user 函数:

def register_user():
    with open('user_data.txt', 'r+') as f:
        username_info = username.get()
        password_info = password.get()
        username_good = True
        for line in f.read().splitlines():
            if username_info == line.split(",")[0]:
                username_good = False
                break #Stop the for loop from continuing
        if username_good:
            f.write(username_info + "," + password_info + "\n")
        else:
            Label(text='This user already exists!').pack()
    username_entry.delete(0, END)
    password_entry.delete(0, END)

我已经使用 username_good 来跟踪用户名是否唯一。然后循环遍历文件中的行。对于每一行,它检查 username_info 是否等于 line.split(",")[0]。这与您之前的做法不同,因为它将行拆分为用户名和密码,并且只检查用户名。否则,用户不能拥有作为另一个用户名或密码一部分的用户名(例如,如果用户想要用户名 alex 但其他人已经拥有 alexander,他们将不会被允许,因为alexalexander 中,尽管它们是不同的用户名)。如果它找到一个非唯一的用户名,它将 username_good 设置为 False 并中断循环,因此它不再检查任何行。 for 循环完成后,您可以检查 username_good。如果为真,则没有找到重复项,因此您可以将新行写入文件。否则,您可以创建标签。文件写入现在应该可以正常工作了。

如果仔细想想for循环:

for line in f:
    if username_info not in line:
        # when username_info is not found in current line
        # the file pointer will be moved to EOF due to f.write()
        f.write(username_info + ',')
        f.write(password_info + '\n')
        # as the file pointer is at EOF, the for loop will be terminated
    else:
        Label(text='This user already exists!').pack()

每当在一行中找不到 username_info 时,凭据将附加到文件末尾并中断 for 循环。

以下是为您的目的使用 for 循环的方法之一:

for line in f:
    user, passwd = line.strip().split(',')
    if username_info == user:
        # better create the label once and update its text here instead
        Label(text=f'User "{username_info}" already exists!').pack()
        break
else:
    # user not found, so register user
    f.write(f'{username_info},{password_info}\n')