tkinter can't change radiobutton appearance after clicking it - python

I have read through a number of samples and my code seems similar, but when I click on the radio button it does not turn green as expected.
the code expects a csv file with the following line
ref, Lang1, Lang2, Lang3, Lang4
I know the code is executing correctly, with the use of debugging print statements through out the code- many removed to simplify the code
import tkinter as tk
import csv as csv
root = tk.Tk()
Sel_Lang = tk.StringVar()
def radioselect():
global lasthit
temp = int(Sel_Lang.get()) -1
buttonlist[temp].config(bg='green')
buttonlist[temp].grid(row=temp, column=1)
if lasthit != temp:
print('last hit greater then 0')
buttonlist[lasthit].config(bg='white')
buttonlist[lasthit].grid(row=lasthit, column=1)
lasthit = temp
with open('Language.csv') as csvfile:
Langptr = csv.reader(csvfile, delimiter=',')
row1 = next(Langptr) #read the header row
langs = (len(row1))
lang=1
while lang < langs:
##print(row1[lang])
MODES.append((row1[lang], lang))
lang = lang + 1
MODES=[]
lasthit = 0
arraycntr = 0
buttonlist = [0] * len(MODES)
for text, mode in MODES:
''' display for the user to select Language
language choices are taken from the first row in the Language.csv file
'''
buttonlist[arraycntr] = tk.Radiobutton(root, height=2, width=15,
borderwidth=10, text=text, font=("Arial", 24, "bold"), bg='white',
variable=Sel_Lang, value=mode, indicatoron=0)
buttonlist[arraycntr].config(command = lambda :radioselect())
buttonlist[arraycntr].grid(row=mode, column=1)
print('In for loop ', arraycntr, text, mode,
len(MODES),buttonlist[arraycntr])
arraycntr += 1
root.mainloop()
no error messages, but the pressed button does not turn green as expected

You need to add option selectcolor
buttonlist[arraycntr] = tk.Radiobutton(root, height=2, width=15,
borderwidth=10, text=text, font=("Arial", 24, "bold"), bg='white',
variable=Sel_Lang, value=mode, indicatoron=0, selectcolor='green')

Related

How to create a counter for the number of times a button that was created was pressed in tkinter?

So I have made a simple program that allows me to type a label for a button and have it created and clickable in the tkinter gui. Now all I need is to add a function that returns the number of times each individual button is clicked. The problem is that the buttons I created are not actually coded in the input so I've found it difficult to do this. I feel like I would have to use the lambda function but I have no experience at all with it. Help is appreciated, thank you.
Code:
import tkinter as tk
from tkinter import *
window = tk.Tk()
window.title("Tkinter FINAL")
window.geometry("600x400")
window.resizable(width=False, height=False)
WIDTH = 800
HEIGHT = 600
counter_name = tk.Label(window, text="Counter Word", width=20)
counter_name.place(x=460,y=318)
counter_entry = tk.Entry(window, width=20)
counter_entry.place(x=470,y=338)
position_x = 0
position_y = 0
word_dict = {}
def button_function():
word_dict[title] += 1
button_count = 0
def button_maker():
global position_x, position_y, button_count, title
button = tk.Button(window, text=counter_entry.get(), width=10, height=2, command = button_function, fg="red")
button.place(x=position_x,y=position_y)
position_x += 116
button_count += 1
if button_count % 6 == 0:
position_y += 50
position_x = 0
title = counter_entry.get()
word_dict[title] = 0
counter_entry.delete(0,'end')
btnmaker = tk.Button(window, text='Click to create counter', width=17, height=2, command = button_maker, fg="red")
btnmaker.place(x=470,y=358)
btnreset = tk.Button(window, text='RESET', width=10, height=2, command = window.destroy, fg="red")
btnreset.place(x=520,y=500)
window.mainloop()
You need to pass the word entered to button_function() using lambda:
word_dict = {}
def button_function(word):
word_dict[word] += 1
print(word, word_dict[word])
def button_maker():
# get the input word
word = counter_entry.get().strip()
# make sure the input word is unique in the dictionary
if word and word not in word_dict:
count = len(word_dict)
button = tk.Button(window, text=word, width=10, height=2, fg="red",
command=lambda w=word: button_function(w)) # pass the input word to button_function()
button.place(x=count%5*116, y=count//5*60)
word_dict[word] = 0 # init the counter for the input word
counter_entry.delete(0,'end')
Updated code with counter labels:
word_dict = {}
def button_function(word):
count = word_dict[word].get()
word_dict[word].set(count+1)
def button_maker():
word = counter_entry.get().strip()
if word and word not in word_dict:
count = len(word_dict)
row, col = count//5*2, count%5
# create the word button
button = tk.Button(window, text=word, width=10, height=2, fg="red",
command=lambda w=word: button_function(w))
button.grid(row=row, column=col, padx=10, pady=(10,0))
# create the corresponding counter label
var = tk.IntVar() # for the counter value
tk.Label(window, textvariable=var).grid(row=row+1, column=col)
word_dict[word] = var
counter_entry.delete(0, 'end')

ValueError: <tkinter.OptionMenu object .!optionmenu> is not in list

I am trying to print a corresponding value to the index of a list from another list like so:
print(safeDis[chem.index(self.drop2)])
but when doing this i get the above error. I believe i had this working in a previous iteration but i cannot find the one that was.
import tkinter as tk
from tkinter import ttk
safeDis = [4,88,18,50,12,100]
chem = ["HTP 50%","HTP 84%","HTP 90%","Kerosene","Benzene"]
class Page4:
def __init__(self,root):
self.root = root
self.toplbl = ttk.Label(root, text="Select firing point meterials ",font=("arial",12)) #lable for select meterial 1
self.lbl1 = ttk.Label(root, text="Meterial 1: ",font=("arial",10)) #lable for select meterial 1
self.lbl2 = ttk.Label(root, text = "Meterial 2: " ,font = ("arial",10)) #lable for meterial 2
self.masslbl = ttk.Label(root, text="Mass in Kg:",font=("arial",10))
self.masslbl2 = ttk.Label(root, text="Mass in Kg:",font=("arial",10))
self.typelbl = ttk.Label(root, text="Type:",font=("arial",10))
self.typelbl2 = ttk.Label(root, text="Type:",font=("arial",10))
self.Apply = ttk.Button(root, text="Apply", command = self.new_window) #button to confirm the meterial choices
self.Back = ttk.Button(root, text="Back", command = print("DONG"))
self.mass1 = ttk.Entry(root, width=8)
self.mass2 = tk.Entry(root,width=8)
self.clicked = tk.StringVar() #set the variable to a string value allowing the meterial names to apeer in it
self.clicked.set(chem[3]) #set the default meterial from the chem list
self.clicked2 = tk.StringVar()
self.clicked2.set(chem[3])
self.drop2 = tk.OptionMenu(root, self.clicked2, *chem) #setup the dropdown menue with optionmenue function set to the chem list
self.drop = tk.OptionMenu(root, self.clicked, *chem)
self.toplbl.grid(column=0, row=0,columnspan=3,sticky="w",padx=10,pady=10) #place meterial label 1
self.lbl1.grid(column=0, row=1,padx=10) #place meterial label 1
self.lbl2.grid(column=0, row=3,padx=10) #place meterial label 2
self.mass1.grid(column=2, row=2)
self.mass2.grid(column=2, row=4)
self.masslbl.grid(column=1, row=2)
self.masslbl2.grid(column=1, row=4)
self.typelbl.grid(column=1, row=1,sticky="w")
self.typelbl2.grid(column=1, row=3,sticky="w")
self.drop.grid(column=2, row=1) #place the dropdown menue
self.drop2.grid(column=2, row=3)
self.Apply.grid(column=2,row=5,pady=10,padx=10)
self.Back.grid(column=1,row=5,pady=10,padx=10)
print(safeDis[chem.index(self.drop2)])
def new_window(self):
#print(dongalong)
for widget in self.root.winfo_children():
widget.destroy()
self.app = Page3(self.root)
#class Page5:
def main():
root = tk.Tk()
app = Page4(root)
root.mainloop()
if __name__ == '__main__':
main()
The problem was that self.drop2 is an object of OptionMenu, not the value of it. To get the value returned by it, use the get() method on its variable defined (self.clicked2.get())
So it should be:
print(safeDis[chem.index(self.clicked2.get())])
Hope it solved the error, do let me know if any more doubts
Cheers

Get the index of a button (while pressing) which is in an array

I have saved some buttons in an array:
buttons = []
labels.append(tk.Label(fr2, text="", pady=15))
labels.append(tk.Label(fr3, text="", pady=15))
Later I access to a table of a database and loop this table with "for in" so I get all rows from the table in my program. For each row I activate a button with grid.
i = 0
if len(records) > 0:
for row in records:
print("current_date", ", target date")
print(current_date, row[2])
date = current_date - row[2]
labels[i] = tk.Label(fr2, text=row[1], pady=15)
labels[i].grid(row=i, column=0, sticky='we')
labels[i+1] = tk.Label(fr3, text=date, pady=15)
labels[i+1].grid(row=i, column=0, sticky='we')
buttons[i] = tk.Button(fr4, text="Restart", command=restart, pady=13)
buttons[i].grid(row=i, column=0, sticky='we')
buttons[i+1] = tk.Button(fr5, text="Delete", command=delete, pady=13)
buttons[i+1].grid(row=i, column=0, sticky='we')
i = i + 1
How can I get the index of the button I put on when the program is running?
you can pass argument to the function you use as command.
example:
def myButttonCommand(index):
print("this is the "+index+"th' button")
buttons = []
for i in range (0,10):
buttons[i] = tk.Button(command=myButtonCommand(i))

Text not being saved in text file on enter-key press using Tkinter

I am building a chat GUI. On enter-key press, I want the text fields to be shown on the text box as well as be saved in a file. I do not want to use separate button. It is being shown in the text box correctly but not getting saved in the file. Please tell me how can it be done. This is my first time using tkinter.
from Tkinter import *
root = Tk()
frame = Frame(root, width=300, height=1000)
frame.pack(side=BOTTOM)
#username entry
L1 = Label(frame, text="User Name")
L1.pack(side = LEFT)
input_username = StringVar()
input_field1 = Entry(frame, text=input_username, width=10)
input_field1.pack(side=LEFT, fill=X)
#addresee entry
L2 = Label(frame, text="#")
L2.pack(side = LEFT)
input_addresee = StringVar()
input_field2 = Entry(frame, text=input_addresee, width=10)
input_field2.pack(side=LEFT, fill=X)
#user comment entry
L3 = Label(frame, text="Comment")
L3.pack(side = LEFT)
input_usertext = StringVar()
input_field3 = Entry(frame, text=input_usertext, width=100)
input_field3.pack(side=LEFT, fill=X)
#write to a file
def save():
text = input_field1.get() + input_field2.get() + input_field3.get()
with open("test.txt", "w") as f:
f.write(text)
#chat box
chats = Text(root)
chats.pack()
def Enter_pressed(event):
input_get_name = input_field1.get()
print(input_get_name)
chats.insert(INSERT, '%s : ' % input_get_name)
input_username.set('')
input_get_add = input_field2.get()
print(input_get_add)
chats.insert(INSERT, '#%s : ' % input_get_add)
input_addresee.set('')
input_get_comment = input_field3.get()
print(input_get_comment)
chats.insert(INSERT, '%s\n' % input_get_comment)
input_usertext.set('')
save()
frame2 = Frame(root)
L2_1 = Label(frame2, text="All chats")
L2_1.pack(side = TOP)
input_field1.bind(Enter_pressed)
input_field2.bind(Enter_pressed)
input_field3.bind("<Return>", Enter_pressed)
frame2.pack()
root.mainloop()
As you said you are setting the input fields to blank
Here's the solution:
def save(text):
with open("test.txt", "w") as f:
f.write(text)
And when calling save:
save(input_get_name+": "+input_get_add+": "+input_get_comment)

How can I dynamically create ttk widgets depending on the value entered in a ttk.entry box?

I am trying to make a GUI where as soon as the user inputs an integer into a ttk.entry field, that many checkbuttons need to appear below it. For example, if they put "5" into the entry widget, 5 check buttons need to appear below the entry field.
Edit:
What I ended up using:
self.number_of_stages = tk.IntVar()
self.check_box_dict={}
self.num_of_stages={}
self.stagetempvar={}
self.equipment_widgets={}
def centrifugal_compressor_widgets(self):
self.equipment_widgets.clear()
self.equipment_widgets["NumOfStagesLabelCentComp"]=tk.Label(self.parent, text="Number of Stages:", bg="white")
self.equipment_widgets["NumOfStagesLabelCentComp"].place(relx=0.5, y=260, anchor="center")
self.equipment_widgets["NumOfStagesEntryCentComp"]=ttk.Entry(self.parent, textvariable=self.number_of_stages)
self.equipment_widgets["NumOfStagesEntryCentComp"].place(relx=0.5, y=290, anchor="center")
def OnTraceCentComp(self, varname, elementname, mode):
for key in self.check_box_dict:
self.check_box_dict[key].destroy()
try:
if self.number_of_stages.get() <=15 :
i=1
self.stagetempvar.clear()
while i <= self.number_of_stages.get():
self.stagetempvar[i]=tk.StringVar()
self.stagetempvar[i].set("Closed")
self.check_box_dict[i]=ttk.Checkbutton(self.parent, text=i, offvalue="Closed", onvalue="Open",variable=self.stagetempvar[i])
self.check_box_dict[i].place(relx=(i*(1/(self.number_of_stages.get()+1))), y=360, anchor="center")
i+=1
except:
pass
take a look at the below and let me know what you think...
A very ugly, super basic example:
from Tkinter import *
root = Tk()
root.geometry('200x200')
root.grid_rowconfigure(0, weight = 1)
root.grid_columnconfigure(0, weight = 1)
win1 = Frame(root, bg= 'blue')
win1.grid(row=0, column=0, sticky='news')
number = IntVar()
entry = Entry(win1, textvariable = number)
entry.pack()
confirm = Button(win1, text = 'Press to create widgets...', command = lambda:create_widgets(number.get()))
confirm.pack()
def create_widgets(number):
for n in range(0,number):
Checkbutton(win1, text = 'Checkbutton number : %s' % n).pack()
root.mainloop()

Categories