MUSTANGBOSS8055
MUSTANGBOSS8055

Reputation: 69

Checkbox variable not updating in tkinter

I am a bit new to Tkinter. I'm running Python 3.7.4 on Windows x64. I am trying to make a simple checkbox driven menu that will pass certain values based on the checked boxes. Here is the code:

main.py

import sqlite3
import os
from cryptography.fernet import Fernet

path = r"C:\Users\anves\PycharmProjects\pwdatabase\pwprotect.db"


def dbcreate():
    db = sqlite3.connect('pwprotect.db')
    csr = db.cursor()
    csr.execute("CREATE TABLE INFO(SITENAME TEXT, USERNAME TEXT, PASSWORD TEXT, PWKEY TEXT)")


if not os.path.exists(path):
    dbcreate()

db = sqlite3.connect('pwprotect.db')


def home():
    print("Welcome to Password Database!")
    print()
    print("1. Make a new entry")
    print("2. Search in existing entries")
    print("3. Update an existing entry")
    ch = int(input("Enter your choice: "))
    print()
    if ch == 1:
        insert()
    if ch == 2:
        search()
    if ch == 3:
        update()


def insert(sitename, username, password):
    while True:
        '''
        print()
        sitename = input("Enter the name of the site: ").lower()
        username = input("Enter your username for the site: ")
        password = ""
        ch = input("Do you want to use our generated password?(y/n): ")
        if ch == "y":
            password = pwgenerator()
            print("Your generated password is ", password)
        elif ch == "n":
            password = input("Enter your password for the site: ")
'''
        enk, key = encrypt(password)
        entities = (sitename, username, enk, key)
        cursor = db.cursor()
        cursor.execute('INSERT INTO INFO(SITENAME,USERNAME,PASSWORD,PWKEY) VALUES (?,?,?,?)', entities)
        db.commit()
        '''
        ch = input("Do you want to make another entry?(y/n): ")
        if ch == 'n':
            ch = input("Do you want to return to home screen?(y/n): ")
            print()
            if ch == 'y':
                home()
                break

            elif ch == 'n':
                print("Thank you for using Password Database")
                return

        elif ch == 'y':
            continue

        else:
            print("Invalid input")
            home()
            break
'''
        break
    return


def search(site):
    while True:
        # site = input('Enter the name of the site: ').lower()
        csr = db.cursor()
        csr.execute('SELECT USERNAME, PASSWORD, PWKEY FROM INFO WHERE SITENAME == ?', (site,))
        row = csr.fetchone()
        if row is not None:
            username = row[0]
            enk = row[1]
            key = row[2]
        else:
            # print("Data not found")
            # home()
            return "not found", "not found"

        password = decrypt(enk, key)
        '''
        print()
        print("Username: ",username)
        print("Password: ",password)

        ch = input("Do you want to search again?(y/n): ")
        if ch == 'n':
            ch = input("Do you want to return to home screen?(y/n): ")
            print()
            if ch == 'y':
                home()
                break

            elif ch == 'n':
                print("Thank you for using Password Database")
                return

        elif ch == 'y':
            continue

        else:
            print("Invalid input")
            home()
            break
            '''
        break
    return username, password


def update(site, user, passw):
    while True:
        # site = input('Enter the name of the site: ').lower()
        # ch = int(input("1 = Change Username, 2 = Change Password: "))
        csr = db.cursor()
        if passw is None:
            # user = input("Enter new username: ")
            csr.execute('UPDATE INFO SET USERNAME = ? WHERE SITENAME = ?', (user, site))
            db.commit()
            # print("Your new username is ", user)

        elif site is None:
            # passw = ""
            # c = input("Do you want to use our generated password?(y/n): ")
            '''
            if c == "y":
                passw = pwgenerator()
            elif c == "n":
                passw = input("Enter new password: ")
            '''
            enk, key = encrypt(passw)

            csr.execute('UPDATE INFO SET PASSWORD = ? WHERE SITENAME = ?', (enk, site))
            csr.execute('UPDATE INFO SET PWKEY = ? WHERE SITENAME = ?', (key, site))
            db.commit()
            # print("Your new password is ", passw)

        else:
            enk, key = encrypt(passw)
            csr.execute('UPDATE INFO SET USERNAME = ? WHERE SITENAME = ?', (user, site))
            csr.execute('UPDATE INFO SET PASSWORD = ? WHERE SITENAME = ?', (enk, site))
            csr.execute('UPDATE INFO SET PWKEY = ? WHERE SITENAME = ?', (key, site))
            db.commit()
        '''
        else:
            print("Invalid input")
            home()
            break

        ch = input("Do you want to update again?(y/n): ")

        if ch == 'n':
            ch = input("Do you want to return to home screen?(y/n): ")
            print()
            if ch == 'y':
                home()
                break

            elif ch == 'n':
                print("Thank you for using Password Database")
                return

        elif ch == 'y':
            continue

        else:
            print("Invalid input")
            home()
            break
        '''
        break


def pwgenerator():
    import random
    pw = ""
    lower = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
             "v", "w", "x", "y", "z"]
    upper = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
             "V", "W", "X", "Y", "Z"]
    digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
    special = ["@", "%", "+", '/', "!", "#", "$", "^", "?", ":", ",", ".", "_", "-"]
    i = 0
    while i <= 15:
        n = random.randint(0, 4)
        if n == 1:
            pw = pw + random.choice(lower)
        elif n == 2:
            pw = pw + random.choice(upper)
        elif n == 3:
            pw = pw + random.choice(digits)
        elif n == 4:
            pw = pw + random.choice(special)
        i += 1
    print(pw)
    return pw


def encrypt(pw):
    key = Fernet.generate_key()
    f = Fernet(key)
    b = bytes(pw, 'utf-8')
    encoded = f.encrypt(b)
    return encoded, key


def decrypt(enk, key):
    f = Fernet(key)
    decoded = f.decrypt(enk)
    pw = str(decoded.decode('utf-8'))
    return pw

gui.py

from tkinter import messagebox
import tkinter
import main

win1 = tkinter.Tk()
win1.geometry("500x200")
win1.title("Password Database")
l1 = tkinter.Label(win1, text="Welcome to Password Database!").grid(row=0, column=0)
l2 = tkinter.Label(win1, text="").grid(row=1, column=0)
entry = tkinter.Label(win1, text="1. Make a new entry")
entry.grid(row=2, column=0)
search = tkinter.Label(win1, text="2. Search for an existing entry")
search.grid(row=3, column=0)
update = tkinter.Label(win1, text="3. Update an existing entry")
update.grid(row=4, column=0)
choice = tkinter.Entry(win1, width=10)
choice.grid(row=5, column=0)


def entrygui():
    wini = tkinter.Tk()
    wini.geometry("500x200")
    wini.title("New Entry")
    entryl1 = tkinter.Label(wini, text="Enter name of the site: ")
    entryl2 = tkinter.Label(wini, text="Enter your username for the site: ")
    entryl3 = tkinter.Label(wini, text="Enter the password the site: ")
    entrye1 = tkinter.Entry(wini, width=20)
    entrye2 = tkinter.Entry(wini, width=20)
    entrye3 = tkinter.Entry(wini, width=20)
    entryl1.grid(row=0, column=0)
    entryl2.grid(row=1, column=0)
    entryl3.grid(row=2, column=0)
    entrye1.grid(row=0, column=1)
    entrye2.grid(row=1, column=1)
    entrye3.grid(row=2, column=1)

    def insertbt():
        site = str(entrye1.get())
        user = str(entrye2.get())
        passw = str(entrye3.get())
        main.insert(site, user, passw)
        messagebox.showinfo("Success!", "Entry added!")
        wini.destroy()

    insert = tkinter.Button(wini, text="Insert", command=insertbt)
    insert.grid(row=3, column=0)

    wini.mainloop()


def searchgui():
    wins = tkinter.Tk()
    wins.geometry("500x200")
    wins.title("Search")
    searchl1 = tkinter.Label(wins, text="Enter the name of the site: ")
    searchl1.grid(row=0, column=0)
    searche1 = tkinter.Entry(wins, width=20)
    searche1.grid(row=0, column=1)

    def searchbt():
        site = str(searche1.get())
        user, passw = main.search(site)
        messagebox.showinfo("Success!", "Username is "+user+"\nPassword is "+passw)
        wins.destroy()

    searchbtn = tkinter.Button(wins, text="Search", command=searchbt)
    searchbtn.grid(row=1, column=0)

    wins.mainloop()


def updategui():
    winu = tkinter.Tk()
    winu.geometry("500x200")
    winu.title("Update")
    caution = tkinter.Label(winu, text="Please select the option if you are updating the corresponding value")
    caution.grid(row=0, column=0)
    sitel = tkinter.Label(winu, text="Enter site name: ")
    sitee = tkinter.Entry(winu, width=20)
    userv = tkinter.IntVar()
    userr = tkinter.Checkbutton(winu, text="New Username: ", variable=userv)
    passv = tkinter.IntVar()
    passr = tkinter.Checkbutton(winu, text="New Password: ", variable=passv)
    usere = tkinter.Entry(winu, width=20)
    passe = tkinter.Entry(winu, width=20)
    sitel.grid(row=1, column=0)
    sitee.grid(row=1, column=1)
    userr.grid(row=2, column=0)
    usere.grid(row=2, column=1)
    passr.grid(row=3, column=0)
    passe.grid(row=3, column=1)

    def updatebt():
        userval = int(userv.get())
        passval = int(passv.get())
        print(userval, passval)
        site = str(sitee.get())
        if userval == 1 and passval == 0:
            user = str(usere.get())
            passw = None
            main.update(site, user, passw)
            messagebox.showinfo("Success", "Username updated")
            winu.destroy()
        elif userval == 0 and passval == 1:
            user = None
            passw = passe.get()
            main.update(site, user, passw)
            messagebox.showinfo("Success", "Password updated")
            winu.destroy()
        elif userval == 1 and passval == 1:
            user = str(usere.get())
            passw = str(usere.get())
            main.update(site, user, passw)
            messagebox.showinfo("Success", "Username and password updated")
            winu.destroy()
        elif userval == 0 and passval == 0:
            messagebox.showinfo("Error", "Please check a box")

    updatebtn = tkinter.Button(winu, text="Update", command=updatebt)
    updatebtn.grid(row=4, column=0)

    winu.mainloop()


def choicefn():
    ch = int(choice.get())
    if ch == 1:
        entrygui()
    elif ch == 2:
        searchgui()
    elif ch == 3:
        updategui()
    else:
        messagebox.showinfo("ERROR", "Please enter a valid choice")


submit = tkinter.Button(win1, text="Submit", command=choicefn).grid(row=5, column=1)
win1.mainloop()

There is a problem in the updategui() function. The checkboxes values are not updating.

The output is always 0,0 and the corresponding error box showing up. I have no such problems in a parallel code that I wrote:

import tkinter
from tkinter import Checkbutton
win = tkinter.Tk()
v1 = tkinter.IntVar()
v1.set(0)
v2 = tkinter.IntVar()
v2.set(0)
c1 = tkinter.Checkbutton(win, text="mf", variable=v1)
c1.grid(row=0,column=0)
c2 = tkinter.Checkbutton(win, text="yeet", variable=v2)
c2.grid(row=1,column=0)
def btfn():
    i1 = (v1.get())
    i2 = (v2.get())
    print(i1,i2)
bt = tkinter.Button(win, text="Display",command=btfn)
bt.grid(row=2,column=0)
win.mainloop()

Any help would be appreciated! (P.S. I put 'e' at the end of a variable name to denote Entry, 'l' for Label, etc)

Upvotes: 0

Views: 3489

Answers (1)

Kevin
Kevin

Reputation: 76194

I'm not 100% sure why this is happening, but here's my best guess based on my experiments.

IntVar's constructor takes an optional argument, which should be a Tk instance if it is provided. If you don't supply a value, it will use whatever Tk was created first. In your case, the win1 object.

The IntVar will update itself whenever the Tk instance gets a chance to clear out its event queue. But this is a problem -- when your winu window is running, your win1 window hangs, and has no chance to update your IntVars.

Or possibly the window is not hanging, but it simply ignores changes made to its IntVars by widgets that don't belong to it. userr and passr are owned by winu, so win1 chooses not to (or can't) listen to them.

One possible solution is to provide winu to your IntVars, so they don't use your win1 object by default.

userv = tkinter.IntVar(winu)
userr = tkinter.Checkbutton(winu, text="New Username: ", variable=userv)
passv = tkinter.IntVar(winu)
passr = tkinter.Checkbutton(winu, text="New Password: ", variable=passv)

I can't find official documentation that completely supports this, but here's a snippet from effbot that mentions the possibility in passing:

To create a Tkinter variable, call the corresponding constructor:

var = StringVar()

Note that the constructor takes an optional widget argument, but no value argument; to set the value, call the set method:

var = StringVar() var.set("hello")

The constructor argument is only relevant if you’re running Tkinter with multiple Tk instances (which you shouldn’t do, unless you really know what you’re doing).

Upvotes: 4

Related Questions