Home > Software engineering >  Register and login issue using Tkinter
Register and login issue using Tkinter

Time:10-07

I'm making a login and register system with tkinter. I have multiple classes so I can have it look like an website with multiple pages. It looks like this: enter image description here

So my issue is: when I'm registering a new account it writes the username and password to a txt file. Now I'm trying to make it give an error when the username already exists. I tried doing this with a simple if statement. This worked in another file but while working with these classes it doesnt. Here is the code for the registering:

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)

Can anyone can help me with this issue? Thanks in advance!

Below I'll show my entire code and my text file:

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()

this is what the text file with user data looks like. But it keeps appending users that already exist

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

CodePudding user response:

The problem is caused by how you open and read the file. When you use with open('user_data.txt', 'r ') as f: you are given a file object, f. This is not the text content of the file, it is an object representing it. The file object is also an iterator, which is why for line in f will work, as you can iterate through the lines in the file, but this is not the right way to read a file. The problem is when you use f.write the iterator stops working, so the program only checks the first line of the file. Instead of for line in f, use for line in f.read().splitlines(). .read() gets the text content from the file object. This is all one string with newline characters. To turn it into a list of lines, we can use .splitlines(). This turns the block of text into a list of lines. Because we're no longer relying on the f iterator, the for loop will look at every line in the file.

This causes the second problem - for every line in the file you check if the name has been used before, so for every line where it isn't, you insert another. This means you end up inserting the record more than once, which you don't want. To fix this, you need to check if the username is unique first, then write the new record. Here's a fixed register_user function:

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)

I've used username_good to keep track of whether the username is unique or not. Then it loops through the lines in the file. For every line it checks if username_info is equal to line.split(",")[0]. This is different to how you did it before, as it splits the line into username and password and only checks the username. Otherwise the user couldn't have a username which was part of another username or password (For example, if the user wanted the username alex but someone already had alexander, they wouldn't be allowed it because alex is in alexander even though they're different usernames). If it finds a non-unique username, it sets username_good to False and breaks the loop so it doesn't check any more lines. After the for loop finishes you can check username_good. If it's true then no duplicates were found, so you can write the new line to the file. Otherwise, you can create the label. The file writing should now work as intended.

CodePudding user response:

If you think carefully about the for loop:

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()

Whenever username_info is not found in a line, the credentials will be appended at the end of the file and break the for loop.

Below is one of the way of using for loop for your purpose:

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')
  • Related