Tkinter RadioButton printing previous result in the list box - python

I am fairly new to Python. I have a simple program that has 3 products, 3 milk options and 3 sizes and an add button, all as radio buttons. The user selects the product, the size, the milk and presses add. The radio-button has values associated to them, e.g. my cappuccino button has value="cappuccino" and my small button has value="small". Upon adding, the values are written to a database and the databases contents are updated to a list-box tkinter widget; so it looks like an order.
My problem is that if i select a certain product, size, and milk type, it writes these details to the database and prints to the list-box, but if select a completely different order it may and add it, it'll write the previous order a couple times to the database as i press add, and then it'll write the correct order.
Any way to fix this so each order is printed as it is. Could it possibly be to the variables storing the previous values. Please can someone provide a solution.
The code below is not everything but gives you a jist of the structure.
def view_command():
self.orderList.delete(0,END) #listbox on screen 2
for row in backend.view():
self.orderList.insert(END,row)
def addItem():
view_command()
choice = v.get()
size = s.get()
milkOptions = m.get()
backend.customerOrders(choice,size,milkOptions)
self.orderList = tk.Listbox(self,width=112)
self.orderList.place(x=0,y=680)
#Scrollbar for Order Listbox
self.scrollbar = tk.Scrollbar(self)
self.scrollbar.place(x=700,y=685)
#Scroll bar to list box configure
self.orderList.config(yscrollcommand=self.scrollbar.set)
self.scrollbar.config(command=self.orderList.yview)
#Americano Button
self.americanoImage = tk.PhotoImage(file="ResizedItemImages/HotDrinks/americanoResized.png")
#self.americanoButton = tk.Radiobutton(self,image=self.americanoImage, command=lambda: product("Americano"),variable=v)
self.americanoButton = tk.Radiobutton(self,image=self.americanoImage,variable=v, value="Americano")
#Cappucino Button
self.cappucinoImage = tk.PhotoImage(file="ResizedItemImages/HotDrinks/cappucinoResized.png")
#self.cappucinoButton = tk.Radiobutton(self,image=self.cappucinoImage, command=lambda: product("Cappucino"),variable=v)
self.cappucinoButton = tk.Radiobutton(self,image=self.cappucinoImage,variable=v, value="Cappucino")
#Espresso Button
self.espressoImage = tk.PhotoImage(file="ResizedItemImages/HotDrinks/espressoResized.png")
#self.espressoButton = tk.Radiobutton(self,image=self.espressoImage, command=lambda: product("Cappucino"),variable=v)
self.espressoButton = tk.Radiobutton(self,image=self.espressoImage,variable=v, value="Espresso")
#Add button
self.addImage = PhotoImage(file="ResizedItemImages/Function/addResized.png")
self.addButton = Button(self,image=self.addImage,command=addItem)
self.addButton.place(y=550,x=440)
#Small button
self.smallImage = tk.PhotoImage(file="ResizedItemImages/Function/smallResized.png")
self.smallButton = tk.Radiobutton(self,image=self.smallImage,
variable=s, value="Small")
self.smallButton.place(y=550,x=0)
#Medium Button
self.mediumImage = tk.PhotoImage(file="ResizedItemImages/Function/medium_Resized.png")
self.mediumButton = tk.Radiobutton(self,image=self.mediumImage,
variable=s, value="Medium")
self.mediumButton.place(y=550,x=140)
#Large button
self.largeImage = tk.PhotoImage(file="ResizedItemImages/Function/largeResized.png")
self.largeButton = tk.Radiobutton(self,image=self.largeImage,
variable=s, value="Large")
self.largeButton.place(y=550,x=290)
#ALL MILK OPTION BUTTONS
#Soya Milk Button
self.soyaMilkImage = tk.PhotoImage(file="ResizedItemImages/MilkOptions/soyaMilkResized.png")
self.soyaMilkButton = tk.Radiobutton(self, image=self.soyaMilkImage,variable=m, value="Soya")
#Cocounut Milk Button
self.coconutMilkImage = tk.PhotoImage(file="ResizedItemImages/MilkOptions/coconutMilkResized.png")
self.coconutMilkButton = tk.Radiobutton(self, image=self.coconutMilkImage,variable=m, value="Coconut")
#Whole Milk
self.wholeMilkImage = tk.PhotoImage(file="ResizedItemImages/MilkOptions/wholeMilkResized.png")
self.wholeMilkButton = tk.Radiobutton(self, image=self.wholeMilkImage,variable=m, value="Whole")

Related

Python Tkinter Listbox Back Forward Button

I have a listbox and I printed some contents with it. I want to put a back and forth button, as I press the button, it goes back and forth in the indexes and this selection appears in the listbox.
For example, 0 index is selected in the photo. When I press Forth, I want it to come to 1 index.
For this, I did research and analyzed the sample codes, but did not have the idea that I could not find the result.
import tkinter as tk
from tkinter import *
root = tk.Tk()
my_frame = Frame(root)
my_scrollbar = Scrollbar(my_frame, orient=VERTICAL)
list = Listbox(my_frame, width=85, height=20, yscrollcommand=my_scrollbar.set)
for i in range(50):
list.insert(END, str(i)+".index")
my_scrollbar.config(command=list.yview)
my_scrollbar.pack(side=RIGHT, fill=Y)
my_frame.pack()
list.pack()
So if I understand correctly, you'd like 2 buttons that allows you to cycle forward and backwards through the indexes.
So below is your code modified that allows you to visibly cycle through the listbox by using the GUI.
(EXPLANATION BELOW)
import tkinter as tk
from tkinter import *
root = tk.Tk()
my_frame = Frame(root)
my_frame.pack()
my_scrollbar = Scrollbar(my_frame)
my_scrollbar.pack(side=RIGHT, fill=Y)
listBox_0 = tk.Listbox(my_frame, width=85, height=20, yscrollcommand=my_scrollbar.set, selectmode='single')
listBox_0.pack()
my_scrollbar.config(command=listBox_0.yview)
def backButtonFN(my_frame):
curselection = listBox_0.curselection()
indexLB = curselection[0]
indexLB = indexLB - 1
if indexLB > 0 or indexLB == 0:
listBox_0.selection_clear(0, last='end')
listBox_0.selection_set(indexLB)
else:
None
pass
def forwardButtonFN(my_frame):
curselection = listBox_0.curselection() #current selection method
indexLB = curselection[0] #get value of index
indexLB = indexLB + 1 #add 1 to current value
listBox_0.selection_clear(0, last='end') #delete old selection
listBox_0.selection_set(indexLB) #select new index
pass
backButton = tk.Button(my_frame)
backButton.configure(text='BACK')
backButton.pack(anchor='s', side='left')
backButton.bind('<1>', backButtonFN, add='' )
forwardButton = tk.Button(my_frame)
forwardButton.configure(text='FOWARD')
forwardButton.pack(anchor='s', side='right')
forwardButton.bind('<1>', forwardButtonFN, add='' )
for i in range(50):
listBox_0.insert(END, str(i)+".index")
listBox_0.selection_set(0) #activate first index
Initially you called your listbox list, which is a big no-go as it can cause issues in terms of syntax later on down the line, so I changed the name of the Listbox to listBox_0, so this is your new Listbox as you originally intended.
once I did that, I created 2 functions for each of the forward and backwards buttons, I also had to rearrange the code to allow it to <bind> correctly.
I started off by making the first index active, that essentially will give me a value for curselection(), I then took that value, turned it into an integer I could play with, then each time you press the button, it will turn that extracted index, add one to it, then remove the previous selection and then add the new updated selection with indexLB
Then the same process for backButtonFN except this time, I am deducting 1 instead of adding, and then making sure it doesn't continue to go back once it hits 0.
I've also changed your configuration for listBox_0 to selectmode='single' to allow you to select one item at a row, you can disable this if you'd like to select multiple.
It can definitely use some tidying up as the pro's may immediately see, but I hope this answers your question

Tkinter - Creating multiple check boxes using a loop

I am trying to create a program that allows the user to select any number of check boxes and hit a button to return a random result from those check boxes. Since I am basing my list off the roster of Smash bros ultimate, I am trying to avoid creating 70+ variables just to place check boxes. However, I am unable to figure out how to iterate this. The various values set for rows are just placeholders until I can figure this out. I would also like to have a reset button at the top that allows the user to automatically uncheck every box. This code is what I have so far. Any help would be greatly appreciated.
#!/usr/bin/python3
from tkinter import *
window = Tk()
#window name and header
window.title("Custom Random SSBU")
lbl = Label(window, text="Select the fighters you would like to include:")
lbl.grid(column=1, row=0)
f = [] #check boxes
ft = open("Fighters.txt").readlines() #list of all the character names
fv=[0]*78 #list for tracking what boxes are checked
ff=[] #list to place final character strings
def reset():
for i in fv:
fv[i]=0
rst = Button(window, text="Reset", command=reset)
rst.grid(column=0, row=3)
for y in range (0,77):
f[y] = Checkbutton(window, text = ft[y], variable = fv[y])
f[y].grid(column=0, row=4+y)
def done():
for j in fv:
if fv[j] == 1:
ff.append(fv[j])
result = random.choice(ff)
r=Label(window, text=result)
d = Button(window, text="Done", command=done)
d.grid(column=0, row = 80)
window.mainloop()
Unfortunately I'm afraid you are going to have to create variables for each checkbox.
tkinter has special purpose Variable Classes for holding different types of values, and if you specify an instance of one as the variable= option when you create widgets like Checkbutton, it will automatically set or reset its value whenever the user changes it, so all your program has to do is check its current value by calling its get() method.
Here's an example of the modifications to your code needed to create them in a loop (and use them in the done() callback function):
import random
from tkinter import *
window = Tk()
#window name and header
window.title("Custom Random SSBU")
lbl = Label(window, text="Select the fighters you would like to include:")
lbl.grid(column=1, row=0)
with open("Fighters.txt") as fighters:
ft = fighters.read().splitlines() # List of all the character names.
fv = [BooleanVar(value=False) for _ in ft] # List to track which boxes are checked.
ff = [] # List to place final character strings.
def reset():
for var in fv:
var.set(False)
rst = Button(window, text="Reset", command=reset)
rst.grid(column=0, row=3)
for i, (name, var) in enumerate(zip(ft, fv)):
chk_btn = Checkbutton(window, text=name, variable=var)
chk_btn.grid(column=0, row=i+4, sticky=W)
def done():
global ff
ff = [name for name, var in zip(ft, fv) if var.get()] # List of checked names.
# Randomly select one of them.
choice.configure(text=random.choice(ff) if ff else "None")
d = Button(window, text="Done", command=done)
d.grid(column=0, row=len(ft)+4)
choice = Label(window, text="None")
choice.grid(column=1, row=3)
window.mainloop()
I wasn't sure where you wanted the Label containing the result to go, so I just put it to the right of the Reset button.
variable = fv[y]
This looks up the value of fv[y] - i.e, the integer 0 - at the time the Checkbutton is created, and uses that for the variable argument.
You need to use an instance of one of the value-tracking classes provided by TKinter, instead. In this case we want BooleanVar since we are tracking a boolean state. We can still create these in a list ahead of time:
text = open("Fighters.txt").readlines()
# Let's not hard-code the number of lines - we'll find it out automatically,
# and just make one for each line.
trackers = [BooleanVar() for line in text]
# And we'll iterate over those pair-wise to make the buttons:
buttons = [
Checkbutton(window, text = line, variable = tracker)
for line, tracker in zip(text, trackers)
]
(but we can not do, for example trackers = [BooleanVar()] * len(text), because that gives us the same tracker 78 times, and thus every checkbox will share that tracker; we need to track each separately.)
When you click the checkbox, TKinter will automatically update the internal state of the corresponding BooleanVar(), which we can check using its .get() method. Also, when we set up our options for random.choice, we want to choose the corresponding text for the button, not the tracker. We can do this with the zip trick again.
So we want something more like:
result_label = Label(window) # create it ahead of time
def done():
result_label.text = random.choice(
label
for label, tracker in zip(text, trackers)
if tracker.get()
)

How can I delete/forget/destroy a set of radio buttons that were generated with a for loop from a list?

I am a teacher making a basic mini Steam client as a learning exercise for my programming class. We are using Python and tkinter.
The program generates two sets of radio buttons. The first is the users "game library" where they can select a game to play(when selecting a radio button nothing happens other than a label informs the user the game is about to be launched). The second set of radio buttons lets users select a new game to "purchase". Both sets of radio buttons are generated with a for loop and a list.
Problem:
What I want to do is have it so if you select a game to "purchase" it is added to the user_library list, then destroy/forget the original set of game library radio buttons, then regenerate the radiobuttons with a for loop. This should now also make a button for the newly added game.
The "forget" code I have tried only hides/removes the last raido button generated by the for loop.
Note: radio buttons are being used for demonstration purposes, I understand that a drop down menu would be better.
I planned to do this with a method that was connected to the purchase button.
The method would first append the user_library list with the new game title. 2.Then destroy/forget the user library radio buttons that were generated by the for loop when the program first started. 3. Use another for loop to recreate the user library radio buttons.
When I run the program the "forget" code I have tried only hides/removes the last raidobutton generated by the for loop.
The below code is abbreviated, but should show what I'm trying to do. I am comfortable with appending the lists, but don't understand why only the last radio button is being forgotten.
I am open to better ways of achieving the problem
libraryGames=["The Witcher 3: Wild Hunt GOTE", "Jurassic World: Evolution", "Red Dead Redemption 2","Mass Effect Trilogy","Subnautica",]
saleGames=["SteamPunk 2077", 29.99, "Fallout 3", 3.99, "Warcraft 4: About dam time", 69.99, "Lego: Terminator", 19.99, "Homework simulator", 14.99]
def __init__(self, parent):
#list that created the library game buttons
for games in range (0, len (libraryGames)):
rb = Radiobutton(frame1, variable = self.library_game, bg =
"#000000",fg="#ffffff", value = games, text =
libraryGames[games],command = self.library_choice)
rb.grid(row = libraryrow, column=0, columnspan = 2,padx=25,
sticky=W,)
libraryrow+=1
#list that created the sale game buttons
for items in range (0, len (saleGames),2):
rb2 = Radiobutton(frame2, variable = self.sale_game, bg =
"#000000",fg="#ffffff",value = items, text =
saleGames[items],command = self.sale_choice)
rb2.grid(row = salerow, column=0, columnspan = 2,padx=25,
sticky=W,)
salerow+=1
#method that removes the radio buttons generated by the first loop when a purchase button is clicked.
def purchase(self):
rb.grid_forget()
# I would then add the loop code to create the radio buttons again
First create a list to hold the radio buttons, and then loop through the list to grid_forget them when required.
import tkinter as tk
root = tk.Tk()
libraryGames=["The Witcher 3: Wild Hunt GOTE", "Jurassic World: Evolution", "Red Dead Redemption 2","Mass Effect Trilogy","Subnautica",]
class GUI:
def __init__(self, parent):
frame1 = tk.Frame(parent)
frame1.pack()
self.holder_list = []
for num,game in enumerate(libraryGames):
rb = tk.Radiobutton(frame1, bg="#000000",fg="#ffffff",
value=game, text=game,command= "",selectcolor="grey")
rb.grid(row = num, column=0, columnspan = 2,padx=25,sticky=tk.W,)
self.holder_list.append(rb)
frame2 = tk.Frame(parent)
frame2.pack()
tk.Button(frame2,text="Purchased",command=self.purchase).pack()
def purchase(self):
print (self.holder_list)
for widget in self.holder_list:
widget.grid_forget()
GUI(root)
root.mainloop()

Connecting button to run function to add labels

I just finished reading a Python book called Practical Programming 2nd ed. and thought I'd challenge myself to apply what I learned to make my first small program for work (convenience store) to create a list of chips I need to order using tkinter as the interface.
I would input how many of each brand of chips I have in stock, and after pressing the 'Order' button, it would return the number of each brand of chips needed to order.
Here is the code I've got so far:
import tkinter as tk
# Initiate tkinter
window = tk.Tk()
# Create a dictionary of brand of chips with a value of how many chips should be in stock
chips = {'Miss Vickies Original': 4, 'Miss Vikies Salt & Vinegar': 4}
# Start counting rows
row_num = 0
for brand in chips:
# Create label describing the brand of chips
label = tk.Label(window, text=brand)
label.grid(row=row_num, column=1)
# Create an entry box to input number of chips in stock
entry = tk.Entry(window)
entry.grid(row=row_num, column=2)
# Add one; To start at next row
row_num += 1
# Return number of chips to order
def order(entry_data, stock_required):
# Subtract how much is in stock from how much should be in stock
order_quantity = int(stock_required) - int(entry_data)
# Create label to the left of each chip with how many should be ordered
order_label = tk.Label(window, text="'Order: ', order_quantity")
order_label.pack(side='left')
# Order button
button = tk.Button(window, text='Order', command=lambda: order(entry.get(), chips[1]))
button.pack(side='bottom')
window.mainloop()
I think I've confused myself with my own code lol. I'm having great difficulty figuring out how to make the button(placed at the bottom) trigger the calculation to occur and show the order_label to the left of each chips label.
A problem I see with my code that I'm not sure how to fix is the label would only be called once, as the function doesn't contain a loop. What's the recommended way to solve this?
I've checked: Tkinter: Link an Entry Widget to a Button to a Function.
But not a related problem, as I have the lambda: order function already in.
Here is how it should look like:
This is my first program, so any constructive criticism is encouraged!
I added the functionality needed to make your code work as you intended; You will need to keep track of the current level of stock to make this something useful though.
import tkinter as tk
def generate_order_quantities():
for brand, datafields in chips_entry_fields.items():
entry, quantity_to_order, label = datafields
recommended_stock_level = chips_stock_levels[brand]
try:
quantity_sold = int(entry.get())
except ValueError:
quantity_sold = 0
quantity_to_order.set(min(quantity_sold, recommended_stock_level))
if __name__ == '__main__':
# Initiate tkinter
window = tk.Tk()
# Create a dictionary of brand of chips_stock_levels with a value of how many chips_stock_levels should be in stock
chips_stock_levels = {'Miss Vickies Original': 4, 'Miss Vikies Salt & Vinegar': 4}
chips_quantities_sold = {'Miss Vickies Original': 0, 'Miss Vikies Salt & Vinegar': 0}
chips_entry_fields = {}
# Start counting rows
row_num = 0
for row, brand in enumerate(chips_stock_levels):
# Create label describing the brand of chips_stock_levels
label = tk.Label(window, text=brand)
label.grid(row=row, column=1)
# Create an entry box to input number of chips_stock_levels in stock
entry = tk.Entry(window)
chips_entry_fields[brand] = [entry]
entry.grid(row=row, column=2)
# Create label to the left of each chip with how many should be ordered
quantity_to_order = tk.IntVar()
chips_entry_fields[brand].append(quantity_to_order)
# quantity_to_order.set()
order_label = tk.Label(window, textvariable=quantity_to_order)
chips_entry_fields[brand].append(order_label)
order_label.grid(row=row, column=3)
# Order button
button = tk.Button(window, text='Order', command=generate_order_quantities)
button.grid(row=3, column=3)
window.mainloop()

Tkinter set value of Button's corresponding Entry box

I've been stuck on this for a little while. I'm basically trying to make an app that will allow me to load multiple files. At the moment, the app has 6 "browse" buttons, and next to those a corresponding Entry box. I'm trying to make the browse button send the file location string to the Entry box next to it. Unfortunately at the moment it appends the file name string to the bottom Entry box only. How can I get it to output to the box on the corresponding row?
Hopefully the solution will help me to understand how to get the correct values back when I press execute, too!
What i've got so far is below.
Thanks in advance
r=3
for i in range(6):
#CREATE A TEXTBOX
self.filelocation = Entry(self.master)
self.filelocation["width"] = 60
self.filelocation.focus_set()
self.filelocation.grid(row=r,column=1)
#CREATE A BUTTON WITH "ASK TO OPEN A FILE"
self.open_file = Button(self.master, text="Browse...", command=lambda i=i: self.browse_file(i))
self.open_file.grid(row=r, column=0) #put it beside the filelocation textbox
#CREATE A TEXT ENTRY FOR HELICOPTER ROUTE NAME
self.heliday = Entry(self.master)
self.heliday["width"] = 20
self.heliday.grid(row=r,column=2)
r = r+1
#now for a button
self.submit = Button(self.master, text="Execute!", command=self.start_processing, fg="red")
self.submit.grid(row=r+1, column=0)
def start_processing(self):
#more code here
print "processing"
def browse_file(self, i):
#put the result in self.filename
self.filename = tkFileDialog.askopenfilename(title="Open a file...")
#this will set the text of the self.filelocation
self.filelocation.insert(0,self.filename)
You have to keep references to all the Entry boxes. To do this you can change your entry creation to:
self.filelocation = []
for i in range(6):
#CREATE A TEXTBOX
self.filelocation.append(Entry(self.master))
self.filelocation[i]["width"] = 60
self.filelocation[i].focus_set()
self.filelocation[i].grid(row=r,column=1)
This way you keep references to all Entry boxes in a list. You can then make sure the filename gets in the correct Entry by using:
self.filelocation[i].insert(0,self.filename)

Categories

Resources