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()
Advertisement
Answer
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([x[0] for x in self.title_query])
Note that I have changed nested function title_filtering()
to class method in order to be used in different situations. Also change to update the list box instead of destroy it and recreate new list box.