Primary relevant code is in class EntryForm (around line 190) and class BookmarkAccess (around line 246)
I am sharing the global user_id as a means of querying specific rows of data from the database, after the login is completed.
My current workaround is to use a button on the final page, to populate the listbox (self.title.select) with the queries using the user_id generated post-launch.
I have attempted the following to no avail: inherit BookmarkAccess in EntryForm and pass the widget creation in a button command here. Also tried to parse a complete query on app launch with no user_id restriction and then populate listbox with only relevant user_id, which I also could not get working.
What I would like to do is on some prior screen (such as, immediately upon login and passing updated global user_id), populate the final listbox (self.title_select) so when I access that page the listbox is already full of the intended query rows.
Any assistance or guidance would be much appreicated.
import sqlite3 as sql
import tkinter as tk
import tkinter.ttk as ttk
BASE_FONT = ("Bookman Old Style", 10)
user_id = None
class Database:
def __init__(self, *args, **kwargs):
self.connection = sql.connect("testing.db")
self.cursor = self.connection.cursor()
try:
self.cursor.execute(
"""CREATE TABLE IF NOT EXISTS users
(username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL)
;"""
)
self.connection.commit()
except sql.OperationalError:
pass
try:
self.cursor.execute(
"""CREATE TABLE IF NOT EXISTS bookmarks
(OwnerID INTEGER NOT NULL,
Title TEXT NOT NULL,
Link TEXT NOT NULL)
;"""
)
self.connection.commit()
except sql.OperationalError:
pass
def add_account(self, username, password):
self.cursor.execute("""INSERT INTO users VALUES (?,?)""", (username, password))
self.connection.commit()
def login_func(self, username, password):
self.cursor.execute("SELECT password FROM users WHERE username = (?)", (username,))
result = str(self.cursor.fetchone()).strip("'(),")
print(result)
if result == password:
print("true")
return True
else:
print("false")
return False
def get_user_id(self, username):
self.cursor.execute("SELECT rowid FROM users WHERE username = (?)", (username,))
cleaned_id = str(self.cursor.fetchone()).strip(" ( , ) ")
return int(cleaned_id)
def commit_bookmark(self, active_id, title, link):
if len(title) and len(link) != 0:
self.cursor.execute("""INSERT INTO bookmarks (OwnerID,Title,Link)
VALUES (?,?,?)""", (active_id, title, link,))
self.connection.commit()
else:
print("nothing to bookmark")
def title_populate(self, active_id):
self.cursor.execute("SELECT Title FROM bookmarks WHERE OwnerID = (?)", (active_id,))
return self.cursor.fetchall()
def bookmarks_by_title(self, param, active_id):
self.cursor.execute("SELECT Title FROM bookmarks WHERE Title LIKE (?) AND OwnerID=(?)",
('%' param '%', active_id,))
return self.cursor.fetchall()
db = Database()
# complete
class LoginInterface(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
button_styling = ttk.Style()
button_styling.configure("my.TButton", font=BASE_FONT)
label_styling = ttk.Style()
label_styling.configure("my.TLabel", font=BASE_FONT)
tk.Tk.wm_title(self, "Login Screen")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (Login,
CreateNew,
EntryForm,
BookmarkAccess):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(Login)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
# complete
class Login(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.label1 = ttk.Label(self, text="Username: ", style="my.TLabel")
self.label1.grid(row=1, column=1)
self.username = ttk.Entry(self)
self.username.grid(row=1, column=2)
self.label2 = ttk.Label(self, text="Password: ", style="my.TLabel")
self.label2.grid(row=2, column=1, pady=10)
self.password = ttk.Entry(self, show="*")
self.password.grid(row=2, column=2, pady=10)
def login_call(event):
if db.login_func(self.username.get(), self.password.get()) is False:
print("failed validation")
else:
print("validation passed")
global user_id
user_id = db.get_user_id(self.username.get())
controller.show_frame(EntryForm)
self.login = ttk.Button(
self, text="Login", style="my.TButton", command=lambda: login_call(Login))
self.login.grid(row=3, column=2)
self.create_new = ttk.Button(
self,
text="Create New Account",
style="my.TButton",
command=lambda: controller.show_frame(CreateNew),
)
self.create_new.grid(row=4, column=2, pady=10)
# complete
class CreateNew(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.label1 = ttk.Label(self, text="Set Username:", style="my.TLabel")
self.label1.grid(row=1, column=1)
self.username = ttk.Entry(self)
self.username.grid(row=1, column=2)
self.label2 = ttk.Label(self, text="Set Password:", style="my.TLabel")
self.label2.grid(row=2, column=1, padx=5, pady=5)
self.password = ttk.Entry(self)
self.password.grid(row=2, column=2)
self.create_button = ttk.Button(
self,
text="Complete New Account",
style="my.TButton",
command=lambda: db.add_account(self.username.get(), self.password.get()),
)
self.create_button.grid(row=3, column=2, padx=5, pady=5)
self.home = ttk.Button(
self,
text="Go to Login",
style="my.TButton",
command=lambda: controller.show_frame(Login),
)
self.home.grid(row=5, column=2, padx=5, pady=5)
# functional
class EntryForm(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# FIXME
def view_bookmarks(event):
print(user_id)
# BookmarkAccess.title_query = db.title_populate(user_id)
# BookmarkAccess.title_choices = tk.StringVar(value=BookmarkAccess.title_query)
# BookmarkAccess.title_select = tk.Listbox(self, listvariable=BookmarkAccess.title_choices)
# BookmarkAccess.title_select.grid(row=2, column=0, padx=5, pady=10)
controller.show_frame(BookmarkAccess)
def add_bookmark(event):
print(user_id)
db.commit_bookmark(user_id, self.title.get(), self.link.get(), )
self.title.delete(0, tk.END)
self.link.delete(0, tk.END)
self.title_label = ttk.Label(self, text="Title: ")
self.title_label.grid(row=0, column=0)
self.link_label = ttk.Label(self, text="Link: ")
self.link_label.grid(row=0, column=1)
self.title = ttk.Entry(self)
self.title.grid(row=1, column=0, padx=5, pady=10)
self.link = ttk.Entry(self)
self.link.grid(row=1, column=1, padx=5, pady=10)
self.view_bookmarks = ttk.Button(
self,
text="View Bookmarks",
style="my.TButton",
command=lambda: view_bookmarks(Login),
)
self.view_bookmarks.grid(row=5, column=1)
self.commit_new_bookmark = ttk.Button(
self,
text="Add Bookmark",
style="my.TButton",
command=lambda: add_bookmark(Login),
)
self.commit_new_bookmark.grid(row=2, column=1)
# functional
class BookmarkAccess(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.title_label = ttk.Label(self, text="Filter by Title: ")
self.title_label.grid(row=0, column=0)
# title filter: entry box
self.title_filter = ttk.Entry(self)
self.title_filter.grid(row=1, column=0, padx=5, pady=10)
# FIXME
self.title_select = tk.Listbox(self)
self.title_select.grid(row=3, column=0, padx=5, pady=10)
# title filter
def title_filtering(event):
self.title_select.destroy()
self.title_query = db.bookmarks_by_title(self.title_filter.get(), user_id)
self.title_choices = tk.StringVar(value=self.title_query)
self.title_select = tk.Listbox(self, listvariable=self.title_choices)
self.title_select.grid(row=3, column=0, padx=5, pady=10)
self.title_filter.bind('<Return>', title_filtering)
self.title_button = ttk.Button(self, style='my.TButton', text="Filter Title",
command=lambda: title_filtering(Login))
self.title_button.grid(row=2, column=0, padx=5, pady=10)
app = LoginInterface()
app.mainloop()
CodePudding user response:
Suggest to notify raised frame using tkinter virtual event, so that the frame can perform some action upon receiving that virtual event:
class LoginInterface(tk.Tk):
...
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
frame.event_generate('<<Raised>>') # notify frame
Then modify BookmarkAccess
to populate the listbox upon receiving the virtual event:
class BookmarkAccess(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.title_label = ttk.Label(self, text="Filter by Title: ")
self.title_label.grid(row=0, column=0)
# title filter: entry box
self.title_filter = ttk.Entry(self)
self.title_filter.grid(row=1, column=0, padx=5, pady=10)
self.title_choices = tk.StringVar()
self.title_select = tk.Listbox(self, listvariable=self.title_choices)
self.title_select.grid(row=3, column=0, padx=5, pady=10)
self.title_filter.bind('<Return>', self.title_filtering)
self.title_button = ttk.Button(self, style='my.TButton', text="Filter Title",
command=self.title_filtering)
self.title_button.grid(row=2, column=0, padx=5, pady=10)
self.bind('<<Raised>>', self.title_filtering) # respond virtual event
# title filter
def title_filtering(self, event=None):
self.title_query = db.bookmarks_by_title(self.title_filter.get(), user_id)
self.title_choices.set(self.title_query)
Note that I have changed nested function title_filtering()
to class method id order to be used in different situations. Also change to update the list box instead of destroy it and recreate new list box.