Tkinter button command doesn't work when clicked - python

I am making a program that searches a list of stock numbers(the first 8 digit int in the list) and then returns the rest of the values in the list inside the entry boxes but when I click the search button, it does not perform its function. Any advice? (I'm also new to coding, is there any place where I could've shortened my code anywhere to make it more efficient?)
root = Tk()
#lists
car = [19225735, '611926', '2018', 'Hyundai', 'Sonata', 'White', 'Recon', '$25,000',
'Sedan',32,123]
#funtion
def search():
x = stockNumber.get()
if (x == car[0]):
vinNumber.insert(car[1])
make.insert(car[3])
model.insert(car[4])
color.insert(car[5])
status.inset(car[6])
price.insert(car[7])
size.insert(car[8])
mileage.insert(car[9])
#text boxes --------------------------------------------
stockNumber = Entry(root, width=30)
stockNumber.grid(row=0, column=1, padx=20)
vinNumber = Entry(root, width=30)
vinNumber.grid(row=1, column=1, padx=20
year = Entry(root, width=30)
year.grid(row=2, column=1, padx=20)
make = Entry(root, width=30)
make.grid(row=3, column=1, padx=20)
model = Entry(root, width=30)
model.grid(row=4, column=1, padx=20)
color = Entry(root, width=30)
color.grid(row=5, column=1, padx=20)
status = Entry(root, width=30)
status.grid(row=6, column=1, padx=20)
price = Entry(root, width=30)
price.grid(row=7, column=1, padx=20)
size = Entry(root, width=30)
size.grid(row=8, column=1, padx=20)
mileage = Entry(root, width=30)
mileage.grid(row=8, column=1, padx=20)
#button command-------------------------------
enter = Button(root, text = "Search", padx=40, pady=20, command=search)
enter.grid(row=9, column=0)
#labels ------------------------------------------------
snLabel = Label(root, text="Stock Number")
snLabel.grid(row=0, column=0)
vnLabel = Label(root, text="Vin Number")
vnLabel.grid(row=1, column=0)
yearLabel = Label(root, text="Year")
yearLabel.grid(row=2, column=0)
makeLabel = Label(root, text="Make")
makeLabel.grid(row=3, column=0)
modelLabel = Label(root, text="Model")
modelLabel.grid(row=4, column=0)
colorLabel = Label(root, text="Color")
colorLabel.grid(row=5, column=0)
statusLabel = Label(root, text="Status")
statusLabel.grid(row=6, column=0)
sizeLabel = Label(root, text="Size")
sizeLabel.grid(row=7, column=0)
mileLabel = Label(root, text="Mileage")
mileLabel.grid(row=8, column=0)

The Button was working fine, your function was the problem:
def search():
x = int(stockNumber.get())
if (x == car[0]):
vinNumber.insert(0,str(car[1]))
make.insert(0,str(car[3]))
model.insert(0,str(car[4]))
color.insert(0,str(car[5]))
status.insert(0,str(car[6]))
price.insert(0,str(car[7]))
size.insert(0,str(car[8]))
mileage.insert(0,str(car[9]))
This is what i fixed:
stockNumber.get() returns a string, you compare it with an integer, if you do that, it will always be false -> convert it to int with int()
.insert needs an index aswell, not just insert(data) but insert(index, data)

Here is a hint!!!
You need to take a look at each point of data and understand the kind of data you are wanting your function to pull. Yes, you want a number! But is it an "int", a float, what is it???
Take a look at your function for search(). The only reason why it is not grabbing the data is that you need to make sure the function is looking for the right kind of data. Since "stock number" is probably an integer, you would need to specify that in your function.
Get a basic understanding of Python data types:
int
float
string

Related

Can't extract information from the database in to the tkinter window

I get error messages like
_tkinter.TclError: bad listbox index "": must be active, anchor, end, #x,y, or a number
init__.py", line 3187, in get
return self.tk.call(self._w, 'get', first)
and I have no clue how to fix this, tried looking online but I'm just lost
def vindu_2():
def hent_eksamner():
sok_eksam = lst_eksamen.get(lst_eksamen.curselection())
data_eksamen = mindatabase.cursor()
data_eksamen.execute('SELECT * FROM Eksamen')
for row in data_eksamen:
if sok_eksam == row[1]:
emnekode.get(row[0])
romnr.get(row[2])
data_eksamen.close()
eksamen = []
vindu2=Toplevel()
vindu2.title('Eksamner dag')
y_scroll = Scrollbar(vindu2, orient=VERTICAL)
y_scroll.grid(row=0, column=2, rowspan=10, padx=(0,100), pady=5, sticky=NS)
innhold_i_lst_eksamen=StringVar()
lst_eksamen = Listbox(vindu2, width=50, height=10, listvariable=innhold_i_lst_eksamen, yscrollcommand=y_scroll.set)
lst_eksamen.grid(row=0, column=1, rowspan=10, padx=(100,0), pady=5, sticky=E)
innhold_i_lst_eksamen.set(tuple(eksamen))
y_scroll['command']=lst_eksamen.yview
lbl_emnekode = Label(vindu2, text='Emnekode: ')
lbl_emnekode.grid(row=0, column=3, padx=5, pady=5, sticky=E)
lbl_dato = Label(vindu2, text='Dato: ')
lbl_dato.grid(row=1, column=3, padx=5, pady=5, sticky=E)
emnekode = StringVar()
ent_emnekode = Entry(vindu2, width=10, state='readonly', textvariable = emnekode)
ent_emnekode.grid(row=0, column=4, padx=5, pady=5, sticky=W)
dato = StringVar()
ent_dato = Entry(vindu2, width=10, state='readonly', textvariable = dato)
ent_dato.grid(row=1, column=4, padx=5, pady=5, sticky=W)
romnr = StringVar()
ent_romnr = Entry(vindu2, width=10, state='readonly', textvariable = romnr)
ent_romnr.grid(row=2, column=4, padx=5, pady=5, sticky=W)
sok_eksam = StringVar()
ent_sok_eksam = Entry(vindu2, width=10, textvariable = sok_eksam)
ent_sok_eksam.grid(row=3, column=4, padx=5, pady=5, sticky=W)
btn_sok_eksam = Button(vindu2, width=5, text='Søk', command = hent_eksamner)
btn_sok_eksam.grid(row=4, column=4, padx=5, pady=5, sticky=W)
lst_eksamen.bind('<<ListboxSelect>>', hent_eksamner)
btn_tilbake2 = Button(vindu2, text='Tilbake til meny', command = vindu2.destroy)
btn_tilbake2.grid(row=6, column=4, padx=5, pady=25, sticky=E)
lst_eksamen.curselection() returns a list of all the indices in the current listbox selection so the bad index is this list - not an index.
print(lst_eksamen.curselection()) will make this clear and will show which index in the curselection you are wanting. It is done this way for when there is more than one item in the listbox selected.
If there is only one selection then
sok_eksam = lst_eksamen.get(lst_eksamen.curselection()[0]) should work. The index is the first item in the curselection list.
Personally I would place the selection index into a separate variable for readability if performance is not an issue.eg
lst_index = lst_eksamen.curselection()[0]
sok_eksam = lst_eksamen.get(lst_index)
It is because lst_eksamen.curselection() returns a empty tuple due to no item is selected. You need to check whether item is selected to determine whether to proceed or not.
Also there is another issue that hent_eksamner() is used as the callback for both a button command and an event binding. When it is called by the event binding, exception will be raised because it is expected that the function should accept an argument, the Event object.
Below is the modified hent_eksamner() to fix the above issues:
# added the event argument with default value to support
# button command and event binding
def hent_eksamner(event=None):
selection = lst_eksamen.curselection()
# check whether there is item selected
if selection:
sok_eksam = lst_eksamen.get(selection)
data_eksamen = mindatabase.cursor()
data_eksamen.execute('SELECT * FROM Eksamen')
for row in data_eksamen:
if sok_eksam == row[1]:
emnekode.get(row[0])
romnr.get(row[2])
data_eksamen.close()

How to get only a corresponding entry box regardless of how many times I change radiobutton?

from tkinter import *
win=Tk()
var = StringVar()
l = Label(win, bg='white', width=15)
l.grid(row=17,column=1,padx=10, pady=10, sticky='w')
def print1_selection():
if var.get()=="Number":
lab1= Label(win, text="Enter a number").grid(row=4, column=0)
ent1=Entry(win).grid(row=4, column=1)
l.config(text='you have selected ' + var.get())
elif var.get()=="Alphabet":
lab21= Label(win, text="Enter an alphabet").grid(row=5, column=0)
ent21=Entry(win).grid(row=5, column=1)
l.config(text='you have selected ' + var.get())
lbl4=Label(win, text="Select One", bg="crimson", fg="white", font=("times new
roman",15,"bold")).grid(row=1, column=0, padx=10, pady=10, sticky='w')
r1 = Radiobutton(win, text='Number',variable=var, value='Number', command=print1_selection, width=22)
r1.grid(row=2,column=0,padx=10, pady=10)
r2 = Radiobutton(win, text='Alphabet', variable=var, value='Alphabet', command=print1_selection, width=22)
r2.grid(row=2,column=1,padx=10, pady=10)
win.mainloop()
In this code I want that when I select radiobutton number, only enter a number should appear and same for the other.
But the problem is that when I select number after selecting alphabet, it shows both. I need only the selected one and eliminate the other instantly.
This is how I would approach this issue:
from tkinter import Tk, StringVar, Label, Frame, Entry, Radiobutton
def print1_selection():
for widget in entry_frame.winfo_children():
widget.destroy()
value = var.get()
lbl.config(text='You have selected ' + value)
if value == "Number":
Label(entry_frame, text="Enter a number").grid(row=0, column=0)
Entry(entry_frame).grid(row=0, column=1)
elif value == "Alphabet":
Label(entry_frame, text="Enter an alphabet").grid(row=0, column=0)
Entry(entry_frame).grid(row=0, column=1)
win = Tk()
var = StringVar(value=0)
entry_frame = Frame(win)
entry_frame.grid(row=2, column=0, columnspan=2)
lbl = Label(win, bg='white', width=20)
lbl.grid(row=3, column=0, columnspan=2, padx=10, pady=10, sticky='w')
Label(win, text="Select One", bg="crimson", fg="white", font=("times new roman", 15, "bold")).grid(row=0, column=0, padx=10, pady=10, sticky='w')
Radiobutton(win, text='Number', variable=var, value='Number', command=print1_selection, width=22).grid(row=1, column=0, padx=10, pady=10)
Radiobutton(win, text='Alphabet', variable=var, value='Alphabet', command=print1_selection, width=22).grid(row=1, column=1, padx=10, pady=10)
win.mainloop()
As You can see if You don't plan on using the widgets instance anywhere You don't have to assign it to a variable. Also no need to configure label in both statements since that will be done anyways so just do it at the beginning, also rows start from 0 too. Frames help with organizing widgets. Also if You want neither of the radiobuttons selected set the variable to 0.

Add labels to the top of a tkinter grid?

The point of this is to press a button and have new rows appear but currently, titles appear above each new row that is added. Instead, I would like to have one row at the top of the grid with column titles. Is there a way to modify this code I already have? Later, I will be incorporating this into a larger tkinter GUI.
from tkinter import *
#------------------------------------
def addbox():
frame =Frame(root)
frame.pack()
#Item
Label(frame, text="Item").grid(row=0, column=0)
ent1 = Entry(frame, width=10)
ent1.grid(row=2, column=0)
#Day
Label(frame, text="Day").grid(row=0, column=1)
ent2 = Entry(frame, width=10)
ent2.grid(row=2, column=1)
#Code
ent3 = Entry(frame, width=10)
ent3.grid(row=2, column=2)
#Factor
ent4 = Entry(frame, width=10)
ent4.grid(row=2, column=3)
all_entries.append( (ent1, ent2, ent3, ent4) )
#Buttons.
showButton = Button(frame, text='Print', command=refresh)
addboxButton = Button(frame, text='Add Item', fg="Red", command=addbox)
#------------------------------------
def refresh():
for number, (ent1, ent2, ent3, ent4) in enumerate(all_entries):
print (number, ent1.get(), ent2.get(), ent3.get(),ent4.get())
#------------------------------------
all_entries = []
root = Tk()
addboxButton = Button(root, text='Add Instrument', fg="Red", command=addbox)
addboxButton.pack()
root.mainloop()
You can check the row count before you add the label:
if len(all_entries) < 1:
Label(frame, text="Item").grid(row=0, column=0)

Is it possible to overwrite an entry field with label in tkinter?

I have a simple label and entry field that would:
1) Create a static label and clear the entry field after confirmation button click
2) Clear static label after reset button click
Is there any way to overwrite the entry field with a static label of the user input on the confirmation click instead of creating a new static label? And overwriting the static label with an empty entry field on the reset click?
Thank you for the help in advance.
from tkinter import *
root = Tk()
frame1 = Frame(root)
frame1.pack()
def reset():
set_cname.destroy()
cbtn['state'] = NORMAL
def confirm():
global set_cname
text1="Customer Name: " + entry1.get()
set_cname = Label(frame1, text=text1)
set_cname.grid(row=3, column=0, columnspan=1)
entry1.delete(0, 'end')
cbtn['state'] = DISABLED
cname = Label(frame1, text="Customer Name: ").grid(padx=5, pady=5, columnspan=2, sticky=W)
entry1 = Entry(frame1)
entry1.grid(row=0, column=2, padx=5)
cbtn = Button(frame1, text="Confirm", command=confirm, width=20)
cbtn.grid(row=1, column=4, padx=5, pady=5)
rbtn = Button(frame1, text="Reset Names", command=reset, width=20)
rbtn.grid(row=2, column=4, padx=5, pady=5)
root.mainloop()
You can replace the Entry with a Label by first creating both and then using pack() to switch between them. The trick is to not let their different sizes affect the application layout, which can be accomplished by disabling size propagation.
In my example I create a new frame (entry_frame) with a fixed size and then disable size propagation (.pack_propagate(False)). Then I use this new frame to contain the Entry/Label. Im giving the entry_frame the bg color khaki to let you see exactly where it is.
I fiddled a bit with the column numbers also.
from tkinter import *
root = Tk()
frame1 = Frame(root)
frame1.pack()
def reset():
text_label.pack_forget()
entry1.pack()
cbtn['state'] = NORMAL
def confirm():
global set_cname
entry1.pack_forget()
text_label.config(text=entry1.get())
text_label.pack(side='left')
entry1.delete(0, 'end')
cbtn['state'] = DISABLED
cname = Label(frame1, text="Customer Name: ")
cname.grid(row=0, column=0, padx=5, pady=5, sticky=W)
entry_frame = Frame(frame1, width=130, height=20, bg='khaki')
entry_frame.grid(row=0, column=1, padx=5, pady=5, sticky='nsew')
entry_frame.pack_propagate(False) # Disable size propagation
entry1 = Entry(entry_frame) # Customer name entry
entry1.pack()
text_label = Label(entry_frame) # Label to hold customer name
cbtn = Button(frame1, text="Confirm", command=confirm, width=20)
cbtn.grid(row=1, column=2, padx=5, pady=5)
rbtn = Button(frame1, text="Reset Names", command=reset, width=20)
rbtn.grid(row=2, column=2, padx=5, pady=5)
root.mainloop()
Be aware that this solution will be sensitive to font size changes.

My labels aren't moving to the column and rows I want them to

I want my labels and entry widgets and different rows but they automatically move to the top. What do I do to do that? Is there a simple function I could use?
from tkinter import *
root = Tk()
root.resizable(width = False, height = False)
label_1 = Label(root, text="Text")
label_2 = Label(root, text="Text2")
entry1 = Entry(root)
entry2 = Entry(root)
label_1.grid(row=4, column=2, sticky=E)
label_2.grid(row=5, column=2, sticky=E)
entry1.grid(row=4, column=3, sticky=E)
entry2.grid(row=5, column=3, sticky=E)
checkbox = Checkbutton(root, text="Check me")
checkbox.grid(columnspan=2)
Also do you know how to add sub frames? I searched but the examples were all with classes and I was left confused. I of course also want it to be in a specific column and row without automatically getting moved somewhere else.
Empty rows and columns have size 0. Blank labels can be used to create blank space.
from tkinter import *
root = Tk()
dummy = Label(root, text='\n')
label_1 = Label(root, text="Text")
label_2 = Label(root, text="Text2")
entry1 = Entry(root)
entry2 = Entry(root)
dummy.grid()
label_1.grid(row=4, column=2, sticky=E)
label_2.grid(row=5, column=2, sticky=E)
entry1.grid(row=4, column=3, sticky=E)
entry2.grid(row=5, column=3, sticky=E)
checkbox = Checkbutton(root, text="Check me")
checkbox.grid(columnspan=2)

Categories