I am writing a personal finance application in Python using a SQLite3 database and tkinter as my GUI generator. For brevity, I am just including the problematic block of code:
import tkinter as tk
import tkinter.ttk as ttk
import sqlite3
def select_item(event):
db_name = 'portfolio.db'
db_conn = sqlite3.connect(db_name)
db_cursor = db_conn.cursor()
# get information from currently selected Account in tree
tree_item_id = accts_tree.focus()
tree_item = accts_tree.item(tree_item_id)
# get Account ID from record selected in Treeview
accts_acctID = tree_item['values'][0] # save Account ID for selected Account in tree
# get Account information from database for selected Account ID
db_cursor.execute('''SELECT acct_id, acct_name FROM accounts WHERE acct_id = ''' +
str(accts_acctID) + ";")
db_result = db_cursor.fetchone()
# db_result[0] is the Account ID
# db_result[1] is the Account Name
accts_name.set(db_result[1])
db_conn.close() # close the connection to the database
def createAccountsPage(topicPage_frame, topicPages, graphics_path, db_name):
# create main frame for containing both the frame for the Accounts tree view and the frame
# for displaying specific Account information
accts_frame = tk.Frame(topicPage_frame, width=1810, height=960)
accts_frame.place(x=0, y=0)
# create a top frame inside main Frame for displaying Accounts tree view
accts_tree_frame = tk.Frame(accts_frame, width=1516, height=630)
accts_tree_frame.place(x=156, y=90)
accts_tree_frame.pack_propagate(0)
# create Accounts tree view widget
accts_columns = ['id', 'Name']
accts_tree_style = ttk.Style()
accts_tree_style.configure('mystyle.Treeview', font=('Times', 14))
accts_tree = ttk.Treeview(accts_tree_frame, selectmode='browse', columns=accts_columns,
style='mystyle.Treeview', show='tree')
accts_tree.pack(fill='y', side='left')
# create label for the Account Name column directly above the Accounts tree view
accts_tree_name_lbl = tk.Label(accts_frame, text='Name')
accts_tree_name_lbl.place(x=401, y=65)
accts_tree.tag_configure('TreeFont', font=('Times', '14'))
accts_tree.column('id', width=40)
accts_tree.heading('id', text=' ID', anchor='w')
accts_tree.column('Name', width=564)
accts_tree.heading('Name', text=' Name', anchor='w')
# Level 1 of tree = Assets
accts_tree_assets = accts_tree.insert('', 1, 1000, text='Assets', values=('', ''),
tags='TreeFont')
accts_tree_liabilities = accts_tree.insert('', 1, 1001, text='Liabilities', values=('', ''),
tags='TreeFont')
# load all defined Accounts from 'accounts' table of SQLite3 database into a list
db_conn = sqlite3.connect(db_name)
db_cursor = db_conn.cursor()
db_cursor.execute('''SELECT acct_id, acct_name FROM accounts ORDER BY acct__name;''')
accts_data = db_cursor.fetchall()
db_conn.close() # close the connection to the database
# display all Accounts in the 'Assets' or 'Liabilities' (whichever is applicable)
for acct_record in accts_data:
if acct_record[1] == 'Asset':
accts_tree.insert(accts_tree_assets, 'end', values=acct_record, tags='TreeFont')
else:
accts_tree.insert(accts_tree_liabilities, 'end', values=acct_record, tags='TreeFont')
# create lower frame for displaying information from selected Account
accts_acct_frame = tk.Frame(accts_frame, width=1516, height=215, bg='floral white')
accts_acct_frame.place(x=156, y=735)
accts_acctID_lbl = tk.Label(accts_acct_frame, text='Acct ID:', anchor='e', width=8)
accts_acctID_lbl.place(x=1334, y=10)
accts_acctID = tk.StringVar()
accts_acctID.set('')
accts_acctID_ent = tk.Entry(accts_acct_frame, textvariable=accts_acctID, width=10)
accts_acctID_ent.place(x=1414, y=10)
# add Label and Entry widgets in the lower frame for the Account Name field
accts_acctname_lbl = tk.Label(accts_acct_frame, text='Account Name:', anchor='e', width=14)
accts_acctname_lbl.place(x=5, y=90)
accts_name = tk.StringVar()
accts_name.set('')
accts_acctname_ent = tk.Entry(accts_acct_frame, textvariable=accts_name, width=40)
accts_acctname_ent.place(x=140, y=90)
# bind <Key Release> event on Accounts tree to react to when user selects an Account in the tree
accts_tree.bind('<ButtonRelease-1>', select_item)
The last line is where I bind the button release to the tree view such that, when a displayed in the Account tree view is selected, it does a callback to select_item()
. In order for select_item()
to work properly, I must pass the values for db_name, accts_tree, accts_acctID, and accts_name from createAccountsPage()
. This has proven to be quite a challenge. I have tried using lambda in the bind statement, but with no success. The only thing that has worked is that I made these variables GLOBAL inside createAccountsPage()
; I am afraid, however, that this will cause problems later with other functions & methods. I really do just want to pass the values to select_item()
from createAccountsPage()
whenever a different Account entry is selected from the tree view.
Also, I tried, without success, to pass db_conn and db_cursor from the method that calls createAccountsPage()
and then to pass them again to select_item()
to avoid having to open a connection, get data from the database, then immediately close the database again - over and over again. I was able do this (albeit how I did it is not shown in the code below) as far as into createAccountsPage()
, but it fell apart when I tried to pass these two SQLite3-related values into select_item()
. This is why you see me opening and closing the sqlite3 connection repeatedly.
Any help will be most appreciated.
Thank you in advance.