I want to use a combox widget to display a list of vehicles which are populated by querying an access DB. Heres relevant code
from O365 import *
import tkinter as tk
from tkinter import ttk
from tkcalendar import *
import pyodbc
root = tk.Tk()
root.title('Loan Car Manager')
root.geometry('800x1200')
style = ttk.Style(root)
load_loan_vehicle_list_button = tk.Button(root, command = get_active_loan_cars, text = "Load / Refresh")
load_loan_vehicle_list_button.place(x=50 , y=50)
conn = pyodbc.connect(r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};UID=admin;UserCommitSync=Yes;Threads=3;SafeTransactions=0;PageTimeout=5;MaxScanRows=8;MaxBufferSize=2048;{FIL=MS Access};DriverId=25;DefaultDir=C:\Users\James\Documents;DBQ=C:\Users\James\Documents\Database1.accdb;')
cursor = conn.cursor()
def get_active_loan_cars():
global loan_list
cursor.execute("SELECT Loan_make , Loan_model , Loan_rego FROM Loan_vehicle_data WHERE is_active = True")
for row in cursor.fetchall():
loan_list = []
loan_list.append(row)
loan_car_drop_down = ttk.Combobox(root)
loan_car_drop_down.place(x=50 , y=70)
loan_car_drop_down['values'] = loan_list
print(loan_list)
root.mainloop()
When I run this, it queries the DB as expected and returns the vehicles into a list loan_list
.. When I insert the list into to combobox
using loan_car_drop_down['values'] = loan_list
it displays the list but the records are displayed on 1 line.. Eg:
When I print(loan_list)
it returns:
[('Hyundai', 'Elantra', 'TEST123')] [('Hyundai', 'I30', 'ABC123')]
My question is how can I get these records to display on seperate lines of the combobox
widget.
Heres a picture referancing my goal.. Ignoring the months displayed in this example I would like to replace those with :
Hyundai', 'Elantra', 'TEST123' 'Hyundai', 'I30', 'ABC123'
to load records on a combobox I use a dictionary.
I coupling the index of the combo with the primary key of the records to load in a dict.
Below a full example, commented.
The example loads a recordset, I have add some items and an integer primary key, when you select an item from the combo the says it the pk value retrieved from the dict.
At the opening it is also positioned on a records you choose using pk.
I hope you’ll find it useful
#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class Main(ttk.Frame):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.init_ui()
def init_ui(self):
self.pack(fill=tk.BOTH, expand=1)
f = ttk.Frame(padding = 8)
ttk.Label(f, text = "Combobox").pack()
self.cbCombo = ttk.Combobox(f,)
self.cbCombo.bind("<<ComboboxSelected>>", self.on_selected)
self.cbCombo.pack()
f.pack(fill=tk.BOTH, expand=1)
def on_open(self,):
self.set_combos()
self.on_set_combo()
def set_combos(self):
index = 0
self.dict_cars = {}
voices = []
#here your recordset, I've add some items and even a supposed primary key.....1,2,3,4,5
rs = [(1, 'Hyundai', 'Elantra', 'TEST123'),
(2, 'Hyundai', 'I30', 'ABC123'),
(3, 'Hyundai', 'Azera', 'ABC123'),
(4, 'Hyundai', 'Sonata', 'ABC123'),
(5, 'Hyundai', 'I30 Fastback N', 'ABC123')]
#here we coupling self.dict_cars with the combo index...
for i in rs:
self.dict_cars[index] = i[0]
index += 1
record = "{0} {1}".format(i[1], i[2])
voices.append(record)
self.cbCombo["values"] = voices
def on_selected(self, evt=None):
#when you select an item on the combo it get the relative pk record from the dict
index = self.cbCombo.current()
pk = self.dict_cars[index]
msg = ("You have selected index {0} pk {1}".format(index, pk))
messagebox.showinfo(self.master.title(),msg, parent=self)
def on_set_combo(self):
#it'use to select, on open a specific record, in that case the 5
try:
key = next(key
for key, value
in self.dict_cars.items()
if value == 5)
self.cbCombo.current(key)
except:
pass
def on_close(self):
self.parent.on_exit()
class App(tk.Tk):
"""Start here"""
def __init__(self):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_exit)
self.set_title()
self.set_style()
frame = Main(self,)
frame.on_open()
frame.pack(fill=tk.BOTH, expand=1)
def set_style(self):
self.style = ttk.Style()
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
self.style.theme_use("clam")
def set_title(self):
s = "{0}".format('Simple App')
self.title(s)
def on_exit(self):
"""Close all"""
if messagebox.askokcancel("Simple App", "Do you want to quit?", parent=self):
self.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()