使用 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
,他们将不会被允许,因为alex
在 alexander
中,尽管它们是不同的用户名)。如果它找到一个非唯一的用户名,它将 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')
我正在使用 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
,他们将不会被允许,因为alex
在 alexander
中,尽管它们是不同的用户名)。如果它找到一个非唯一的用户名,它将 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')