Reputation: 69
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
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