Python Forum
Linking Comboboxes
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Linking Comboboxes
#1
I have 2 comboboxes. Selection from first is supposed to trigger the second to populate. The first is populated from a sqlite3 database and it works just fine but the trigger for the second does not work even though it is grabbing the correct information. I am NOT getting any ERRORs. My print statement to the output confirms this. but for some reason that information is not getting into the second box. I have tried for days to figure it out and have started validating the definition of insanity. Doing the same thing over and over and expecting a different result. I have read the documentation and have searched the web but I have not found a solution. Here is the code that I have written:

from tkinter import *
from tkcalendar import Calendar, DateEntry
from tkinter import ttk
import tkinter.messagebox
import sqlite3



class work:
    
    
    def __init__(self, root):
        self.root = root
        self.root.title("Service Ticket")
        self.root.iconbitmap('Securitas.ico')
        WIDTH=1024
        HEIGHT=768
        # center the form to the user's screen
        sc_width = self.root.winfo_screenwidth()
        sc_height = self.root.winfo_screenheight()
        x_coordinate = (sc_width/2)-(WIDTH/2)
        y_coordinate = (sc_height/2)-(HEIGHT/2)        
        self.root.geometry("%dx%d+%d+%d"%(WIDTH, HEIGHT, x_coordinate, y_coordinate))
        
        
        MainFrame = Frame(self.root, bd=10, width = WIDTH, height=HEIGHT, relief=RIDGE)
        MainFrame.place(relwidth=1, relheight=1)
        
        frame1 = Frame(MainFrame, highlightbackground='sky blue', highlightcolor='sky blue', highlightthickness=2
        frame1.place(relx=0.5, relwidth=1, relheight=0.435, anchor='n')
        frame2 = Frame(MainFrame, highlightbackground='sky blue', highlightcolor='sky blue', highlightthickness=2)   # Buttons
        frame2['relief'] = 'ridge'
        frame2.place(relx=0.5, rely=0.44, relwidth=0.95, relheight=0.075, anchor='n')
        
        frame3 = Frame(MainFrame, highlightbackground='sky blue', highlightcolor='sky blue', highlightthickness=2)   # DataGrid
        frame3['relief'] = 'ridge'
        frame3.place(relx=0.5, rely=0.52, relwidth=0.95, relheight=0.3, anchor='n')
        
        def connect_db():
            conn = sqlite3.connect("service.db")
            cur = conn.cursor()
            cur.execute("CREATE TABLE IF NOT EXISTS ticket (id INTEGER PRIMARY KEY, date TEXT, tr TEXT, wo TEXT, cust TEXT, addr TEXT, misc TEXT, issue TEXT, notes TEXT)")
            conn.commit()
            conn.close()
            
        def iExit():
            iExit = tkinter.messagebox.askyesno("Service Ticket", "Confirm that you want to Exit")
            if iExit > 0:
                root.destroy()
            return
        
        def Reset():
            self.txtTR.delete(0, END)
            self.txtWO.delete(0, END)
            self.cboCust.delete(0, END)
            self.cboAddr.delete(0, END)
            self.txtMisc.delete(0, END)
            self.txtIssue.delete(0, END)
            self.txtNotes.delete("1.0", END)
            
            
            
            
        def fill_verify():
            if(len(self.txtTR.get()) !=0):
                pass
            else:
                tkinter.messagebox.showwarning('', "The TR number must be entered")
                self.txtTR.focus()
                
            if(len(self.cboCust.get()) !=0):
                pass
            else:
                tkinter.messagebox.showwarning('', "Must have a Customer Selected")
                self.cboCust.focus()
                
            if(len(self.cboAddr.get()) !=0):
                pass
            else:
                tkinter.messagebox.showwarning('', "Must have a Customer's Address Selected")
                self.cboAddr.focus()
                
            if(len(self.txtIssue.get()) !=0):
                pass
            else:
                tkinter.messagebox.showwarning('', "There must be an Issue entered")
                self.txtIssue.focus()
                
            if(len(self.txtNotes.get("1.0", END)) !=0):
                pass
            else:
                tkinter.messagebox.showwarning('', "There must be Notes entered")
                self.txtNotes.focus()        
            
        def SaveRec():
            fill_verify()
            
            conn = sqlite3.connect("service.db")
            cur = conn.cursor()
            cur.execute("INSERT INTO ticket VALUES(NULL,?,?,?,?,?,?,?,?)", (
                self.txtCal.get(), self.txtTR.get(), self.txtWO.get(), self.cboCust.get(), self.cboAddr.get(),
                self.txtMisc.get(), self.txtIssue.get(), self.txtNotes.get('1.0', END)))
            conn.commit()
            DisplayData()
            conn.close()
           
        def DisplayData():
            conn = sqlite3.connect("service.db")
            cur = conn.cursor()
            cur.execute("SELECT * FROM ticket")
            result = cur.fetchall()
            if len(result) !=0:
                self.tree1.delete(*self.tree1.get_children())
                for row in result:
                    self.tree1.insert('', END, values=row)
            conn.commit()
            conn.close()
           
        def UpdateRec():            
            conn = sqlite3.connect("service.db")
            cur = conn.cursor()
            cur.execute("UPDATE ticket SET date=?, tr=?, wo=?, cust=?, addr=?, misc=?, issue=?, notes=? WHERE id=?", \
                        (self.txtCal.get(), self.txtTR.get(), self.txtWO.get(), self.cboCust.get(), self.cboAddr.get(),
                         self.txtMisc.get(), self.txtIssue.get(), self.txtNotes.get('1.0', END), rec_id,))
            conn.commit()            
            conn.close()    
            DisplayData()
            
        def RecSelected(ev):
            Reset()
            viewInfo = self.tree1.focus()
            selected_data = self.tree1.item(viewInfo)
            row = selected_data['values']
            
            global rec_id
            
            
            
            self.txtCal.delete(0, END)      # this is a tkcalender DateEntry Box and it doesn't use the set method
            self.txtCal.insert(0, row[1])   # but it does use some of the same methods as a standard Entry box             
            self.txtTR.insert(0, row[2])            
            self.txtWO.insert(0, row[3])
            self.cboCust.insert(0, row[4])
            self.cboAddr.insert(0, row[5])
            self.txtMisc.insert(0, row[6])
            self.txtIssue.insert(0, row[7])           
            self.txtNotes.insert(END, (row[8])) # this is a multi line Text box and it doesn't use the set method
            
            rec_id = format(row[0])     # must be formatted to a string so the update function can use it
            self.tree1.selection_set('')
        def fill_custbox():   # THIS WORKS
            conn = sqlite3.connect("service.db")
            cur = conn.cursor()
            
            cur.execute("SELECT DISTINCT cust FROM ticket Order BY cust")
            data = []
            for row in cur.fetchall():
                data.append(row[0])
            return data
                
            conn.commit()
            conn.close()
            
            
        def fill_addrbox():   # THIS DOES NOT WORK
            
            conn = sqlite3.connect("service.db")
            cur = conn.cursor()
            
            cur.execute("SELECT distinct addr FROM ticket WHERE cust = '%s'" % (self.cboCust.get(),))
            self.cboAddr.delete(0, END)
            data = []
            for row in cur.fetchall():
                data.append(row[0])
                #self.cboAddr.insert('', row[0],)
                print(row)
            return data
            
            
            conn.commit()
            conn.close()
        
        self.lblDate = Label(frame1, text="Date: ", font=40)
        self.lblDate.place(relwidth=0.1, relheight=0.125)
        self.lblTR = Label(frame1, text="TR #: ", font=40)
        self.lblTR.place(relx=0.2, relwidth=0.1, relheight=0.125)
        self.lblWO = Label(frame1, text="WO/PO: ", font=40)
        self.lblWO.place(relx=0.6, relwidth=0.1, relheight=0.125)
        
        self.txtCal = DateEntry(frame1, font=40, year=2021)
        self.txtCal.place(relx=0.025, rely=0.12, relwidth=0.1, relheight=0.125)
        self.txtTR = Entry(frame1, font=40)
        self.txtTR.place(relx=0.23, rely=0.12, relwidth=0.3, relheight=0.125)
        self.txtWO = Entry(frame1, font=40)
        self.txtWO.place(relx=0.62, rely=0.12, relwidth=0.355, relheight=0.125)
        
        self.lblCust = Label(frame1, text="Customer: ", font=40)
        self.lblCust.place(rely=0.24, relwidth=0.13, relheight=0.125)
        self.lblAddr = Label(frame1, text="Address: ", font=40)
        self.lblAddr.place(relx=0.485, rely=0.24, relwidth=0.1, relheight=0.125)
        
        self.cboCust = ttk.Combobox(frame1, font=40)
        self.cboCust.place(relx=0.025, rely=0.36, relwidth=0.425, relheight=0.125)
        self.cboAddr = ttk.Combobox(frame1, font=40, postcommand=fill_addrbox)
        self.cboAddr.place(relx=0.5, rely=0.36, relwidth=0.475, relheight=0.125)
        
        self.cboCust['values'] = (fill_custbox())
        self.cboCust.bind('<<ComboboxSelected>>', fill_addrbox)
        self.cboAddr['values'] = (fill_addrbox())
        
        
        self.lblMisc = Label(frame1, text="Misc: ", font=40)
        self.lblMisc.place(relwidth=0.1, rely=0.49, relheight=0.12)
        self.lblIssue = Label(frame1, text="Issue: ", font=40)
        self.lblIssue.place(relx=0.475, rely=0.49, relwidth=0.1, relheight=0.12)
        
        self.txtMisc = Entry(frame1, font=40)
        self.txtMisc.place(relx=0.025, rely=0.6, relwidth=0.425, relheight=0.125)
        self.txtIssue = Entry(frame1, font=40)
        self.txtIssue.place(relx=0.5, rely=0.6, relwidth=0.475, relheight=0.125)
        
        self.lblNotes = Label(frame1, text="Notes: ", font=40)
        self.lblNotes.place(rely=0.73, relwidth=0.1, relheight=0.125)
        
        self.txtNotes = Text(frame1, font=40)
        self.txtNotes.place(relx=0.025, rely=0.84, relwidth=0.95, relheight=0.125)              
        
        #=====frame2 Button widgets============================
        self.btn_save = Button(frame2, text="SAVE", font=40, bd=2, command=SaveRec)
        self.btn_save.place(relx=0.03, rely=0.1, relwidth=0.1, relheight=0.8)
        self.btn_update = Button(frame2, text="UPDATE", font=40, bd=2, command=UpdateRec)
        self.btn_update.place(relx=0.14, rely=0.1, relwidth=0.1, relheight=0.8)
        self.btn_reset = Button(frame2, text="RESET", font=40, bd=2, command=Reset)
        self.btn_reset.place(relx=0.25, rely=0.1, relwidth=0.1, relheight=0.8) 
        self.btn_delete = Button(frame2, text="DELETE", font=40, bd=2)
        self.btn_delete.place(relx=0.36, rely=0.1, relwidth=0.1, relheight=0.8)
        self.btn_exit = Button(frame2, text="EXIT", font=40, bd=2,command=iExit)
        self.btn_exit.place(relx=0.47, rely=0.1, relwidth=0.1, relheight=0.8)
        self.btn_parts = Button(frame2, text="PARTS USED ", font=40)
        self.btn_parts.place(relx=0.84, rely=0.1, relwidth=0.13, relheight=0.8)
        
        #=====frame3 Treeview widget============================
        scroll_y = Scrollbar(frame3, orient=VERTICAL)
        
        self.tree1 = ttk.Treeview(frame3, yscrollcommand=scroll_y.set,
                                  columns=("ID","Date", "TR", "WO", "Cust", "Addr", "Misc", "Issue", "Notes"))
        scroll_y.pack(side=RIGHT, fill=Y)
        
        self.tree1.heading("ID", text="ID", anchor=W)
        self.tree1.heading("Date", text="Date", anchor=W)
        self.tree1.heading("TR", text="TR #", anchor=W)
        self.tree1.heading("WO", text="WO/PO #", anchor=W)
        self.tree1.heading("Cust", text="Cust", anchor=W) 
        self.tree1.heading("Addr", text="Addr", anchor=W) 
        self.tree1.heading("Misc", text="Misc", anchor=W) 
        self.tree1.heading("Issue", text="Issue", anchor=W) 
        self.tree1.heading("Notes", text="Notes", anchor=W)
        
        self.tree1['show'] = 'headings'
        
        self.tree1.column("ID", width=30)
        self.tree1.column("Date", width=50)
        self.tree1.column("TR", width=50)
        self.tree1.column("WO", width=50)
        self.tree1.column("Cust", width=100)
        self.tree1.column("Addr", width=100)
        self.tree1.column("Misc", width=75)
        self.tree1.column("Issue", width=100)
        self.tree1.column("Notes", width=200)        
        
        self.tree1.pack(fill=BOTH, expand=1)
        self.tree1.bind("<ButtonRelease-1>", RecSelected)
        
        connect_db()
        DisplayData()
        
        
if __name__=='__main__':
    root = Tk()
    application = work(root)
    root.mainloop()
        
Reply
#2
It would be most helpful is you could supply enough code, so that it can be run and diagnosed through debugger.
Reply
#3
(Jan-24-2021, 06:49 PM)Larz60+ Wrote: It would be most helpful is you could supply enough code, so that it can be run and diagnosed through debugger.

hopefully that's enough code to run it. if not let me know and I can add some more
Reply
#4
I've got it running, and will report back after stepping through the code.
Reply
#5
(Jan-24-2021, 09:31 PM)Larz60+ Wrote: I've got it running, and will report back after stepping through the code.
what is wrong with the code that it has been a week to go through it.
Reply
#6
What about this doesn't work?
        def fill_addrbox():   # THIS DOES NOT WORK
             
            conn = sqlite3.connect("service.db")
            cur = conn.cursor()
             
            cur.execute("SELECT distinct addr FROM ticket WHERE cust = '%s'" % (self.cboCust.get(),))
            self.cboAddr.delete(0, END)
            data = []
            for row in cur.fetchall():
                data.append(row[0])
                #self.cboAddr.insert('', row[0],)
                print(row)
            return data
Have you printed out the "SELECT" command to see if it is correct?
Do you get anything from cur.fetchall?
What is row?

Since fill_custbox() works and the two functions are nearly identical, my guess is the SELECT command is improperly formatted in fill_addrbox().
Reply
#7
if I bind it to the first combobox selection
self.cboCust.bind('<<ComboboxSelected>>', fill_addrbox) self.cboAddr['values'] = (fill_addrbox())
and set the "def fill_addrbox(event):" I get this error: "
builtins.TypeError: fill_addrbox() missing 1 required positional argument: 'Event'" and if I change the %s to a placeholder(?) without the binding I get NO errors and NO addresses in the combobox
Reply
#8
What do you get if you just call fill_addrbox?
Reply
#9
self.cboAddr['values'] = (fill_addrbox())without the bind, nothing happens. ..Now I can fill this combobox selecting all the addresses from the db but I'm trying to filter by customer.
Reply
#10
I am trying to determine if the problem is the query. If you execute this code what do you get? Does it return an empty list? If there are items in the list, what are the items? Are they tuples or lists?
def fill_addrbox():   # THIS DOES NOT WORK
              
    conn = sqlite3.connect("service.db")
    cur = conn.cursor()
              
    cur.execute("SELECT distinct addr FROM ticket WHERE cust = '%s'" % (self.cboCust.get(),))
    # self.cboAddr.delete(0, END)
    data = []
    for row in cur.fetchall():
        data.append(row[0])
        # self.cboAddr.insert('', row[0],)
        # print(row)
    return data
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Can't get tkinter database aware cascading comboboxes to update properly dford 6 3,613 Jan-11-2022, 08:37 PM
Last Post: deanhystad
  Print Values from a Sequence of Entries / ComboBoxes MC2020 4 2,797 Mar-28-2020, 10:05 PM
Last Post: MC2020
  [PyQt] making dependant comboBoxes Hitsugaya 3 5,007 May-23-2019, 06:05 PM
Last Post: Alfalfa

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020