binding tkinter OptionsMenus by category - python

im struggling to bind tkinter options menus by category. ive made a simple to run version of the problem below. it seems to work at first. eg, in the image below you can see it succesfully categorizing by the name dave.
######## UPDATE
by passing a default value into my function i got it to work, now it only uses the default value. However, it always uses this default value. i assumed it would use the value i clicked on. but it always uses the default value.
from tkinter import *
data = {"names" :["dave" , "dave" , "dave" , "bob" , "sadie" , "jessica"] , "ages":[96,96,10,11,14,26] , "sexes":["m" , "f" , "m" , "m" , "f" , "f"]}
def age_selected_func(age_selected):
print("age selected " +str(age_selected))
sexes_object['menu'].delete(0, 'end')
good_sexes = []
for s, a in zip(data['sexes'], data['ages']):
if a == age_selected:
sexes_object['menu'].add_command(label=s, command=lambda s="none": sex_selected_func(s)) ## command=lambda a <- this is the problem it doesnt know what a is , but i need to pass a into it or its useless
ages_top_label_object.set(age_selected)
def name_selected_func(name_selected):
print("name selected")
ages_object['menu'].delete(0, 'end')
good_ages = []
for n, a in zip(data['names'], data['ages']):
if n == name_selected:
ages_object['menu'].add_command(label=a, command=lambda a="none": age_selected_func(a)) ## command=lambda a <- this is the problem it doesnt know what a is , but i need to pass a into it or its useless
names_top_label_object.set(name_selected)
window=Tk()
window.geometry("800x500+10+20")
names_top_label_object = StringVar(window)
names_top_label_object.set("choose a name")
names_object = OptionMenu(window, names_top_label_object, *data["names"] , command= lambda name_selected: name_selected_func(name_selected ))
names_object.pack();
names_object.place(x=25, y=100);
ages_top_label_object = StringVar(window)
ages_top_label_object.set("choose an age")
ages_object = OptionMenu(window, ages_top_label_object, *data["ages"] , command= lambda model_c: model_selected(model_c ))
ages_object.pack();
ages_object.place(x=25, y=150);
sexes_top_label_object = StringVar(window)
sexes_top_label_object.set("choose an sex")
sexes_object = OptionMenu(window, sexes_top_label_object , *data["sexes"] , command= lambda make_c: make_selected(make_c ))# , model_top_label_object, deriv_object , deriv_top_label_object ))
sexes_object.pack();
sexes_object.place(x=25, y=200);
how can i bind these 3 drop down boxes?

Related

Quiz listbox items displaying in one line

I am trying to show the options for quiz questions in a listbox. The value will later be retrieved with a button. They show as one line instead of different listed items. I think it has something to do with the list and how it is formatted, but I am not sure how to fix this. How can I fix this?
from tkinter import *
from random import randint
import random
from string import ascii_lowercase
QuizFrame = Tk()
NUM_QUESTIONS_PER_QUIZ = 4
QUESTIONS = {
"What day of the week is it?": [
"Monday",
"Tuesday",
"Wednesday",
"Thursday"
],
"What is the first state?": [
"Delaware",
"Maryland",
"Texas",
"Maine"
],
}
num_questions = min(NUM_QUESTIONS_PER_QUIZ, len(QUESTIONS))
questions = random.sample(list(QUESTIONS.items()), k=num_questions)
Question_Label = Label(QuizFrame, text="", font=("Helvetica", 20))
Question_Label.grid(row=3, column=1)
for num, (question, alternatives) in enumerate(questions, start=1):
Question_Label.config(text=question)
correct_answer = alternatives[0]
labeled_alternatives = dict(
zip(ascii_lowercase, random.sample(alternatives, k=len(alternatives)))
)
my_listbox=Listbox(QuizFrame)
my_listbox.grid(row=6, column=1)
my_list=[labeled_alternatives]
for item in my_list:
my_listbox.insert(END,item)
QuizFrame.mainloop()
my_list only contains one item, labeled_alternative, so when you iterate it in the for loop, the entire dictionary gets inserted. Instead, you want to iterate labeled_alternatives.items() to get the keys and values for each item in your dictionary. Change the for loop to
for k, v in labeled_alternatives.items():
my_listbox.insert(END, k + ": " + v)

Problem with Messagebox it runs only that

i dont know why i cannot put all of my code
i created a function w3 and i add some checkbuttons the problem is that if the user clicks "< Υποβολή >" the function listokouti only recognizes the messagebox and its like i never put elif,can anyone help?
i1=IntVar()
i2=IntVar()
i3=IntVar()
i4=IntVar()
i5=IntVar()
#i6=IntVar()
#i7=IntVar()
# checkbuttons
check1 = tk.Checkbutton(rain,text="Τίτλος",font=('',13),variable=i1,onvalue=1,offvalue=0).pack(expand=1,anchor="nw")
check2 = tk.Checkbutton(rain,text="Tίτλος(Μετάφραση)",font=('',13),variable=i2,onvalue=1,offvalue=0).pack(expand=1,anchor="nw")
check3 = tk.Checkbutton(rain,text="Συγγραφέας",font=('',13),variable=i3,onvalue=1,offvalue=0).pack(expand=1,anchor="nw")
check4 = tk.Checkbutton(rain,text="Λέξεις κλειδιά",font=('',13),variable=i4,onvalue=1,offvalue=0).pack(expand=1,anchor="nw")
check5 = tk.Checkbutton(rain,text="Λέξεις κλειδιά(Μετάφραση)",font=('',13),variable=i5,onvalue=1,offvalue=0).pack(expand=1,anchor="nw")
def listokouti():
if i1.get()==0 and i2.get()==0 and i3.get()==0 and i4.get()==0 and i5.get()==0 :
vsause=messagebox.showwarning("team.33","Παρακαλώ επιλέξτε φίλτρα")
elif i1.get()==1 or i2.get()==1 or i3.get()==1 or i4.get()==1 or i5.get()==1 :
money=tk.Tk()
money.title("team.33")
money.iconbitmap('C:\Program Files (x86)\icon.ico')
# money.config(bg="#000000")
frame=tk.Frame(money)
scrollarw1=ttk.Scrollbar(frame,orient=VERTICAL)
my_listbox= tk.Listbox(frame,yscrollcommand=scrollarw1.set,width=50)
scrollarw1.config(command=my_listbox.yview)
scrollarw1.pack(side=RIGHT,fill= Y)
scrollarw2=ttk.Scrollbar(frame,orient=HORIZONTAL)
scrollarw2.config(command=my_listbox.xview)
scrollarw2.pack(side=BOTTOM,fill= X)
frame.pack()
my_listbox.pack(pady=20)
# to item einai akyro to evala mono gia na leitoyrgei to scrollbar
for item in range(1,101):
my_listbox.insert(END,item)
butt =tk.Button(money,text="< Υποβολή >",font=("",10,'bold'),command=ergasia).pack()
money.mainloop()
b1 = tk.Button(rain,text="< Υποβολή >",font=("",10,"bold"),command= listokouti).pack(expand=1)
rain.mainloop()
w3()

Binding one combobox to another combobox in while loop in tkinter

*I wanted to bind platform_id drop combobox to teh combobox_b so taht if cpu is selected in platform_id_drop, then cpu frequencies must be listed otherwise gpu frequencies must be listed. I am using while loop to create a number of rows based on input we are giving and used dictionary to store respective columns. I am able to get only fo rone set of row i.e frequencies are display oly for one row but not for other rows. Having Problem with bind function. Please help me with this.
'''
import pandas as pd
from tkinter import filedialog
from tkinter import ttk
from tkinter.filedialog import asksaveasfile
import collections
app=Tk()
app.title("trace")
app.geometry("1000x500")
global z
required=2
z=required
global global_id
global_id=0
global text_file_3
global text_file_4
a_dict = collections.defaultdict(list)
a_dict['global_id']={}
a_dict['unique_dag_id']={}
a_dict['platform_id']={}
a_dict['deadline']={}
a_dict['wcet_cpu']={}
a_dict['wcet_gpu']={}
a_dict['input_arrival_time']={}
a_dict['hyper_period_entry']={}
a_dict['input_task_period']={}
a_dict['frequency']={}
unique_dag_id = StringVar()
wcet_cpu = StringVar()
wcet_gpu = StringVar()
deadline = StringVar()
input_arrival_time = StringVar()
hyper_period_entry = StringVar()
input_task_period=StringVar()
frequency=StringVar()
last_county=StringVar()
v=[]
dict1={'gpu':['177000000' ,'266000000' ,'350000000' ,'420000000' ,'480000000', '543000000' , '600000000'],'cpu':['200000000', '300000000', '400000000', '500000000', '600000000', '700000000', '800000000', '900000000', '1000000000' ,'1100000000', '1200000000', '1300000000', '1400000000', '1500000000' ,'1600000000', '1700000000', '1800000000', '1900000000', '2000000000']}
def save_trace1():
global global_id
global_id_info=global_id_entry
if(platform_id_drop.get()=='cpu'):
platform_id_info=0
else:
platform_id_info=1
unique_dag_id_info=unique_dag_id_entry
wcet_cpu_info=wcet_cpu_entry.get()
wcet_gpu_info=wcet_gpu_entry.get()
deadline_info=deadline_entry.get()
input_arrival_time_info=input_arrival_time_entry.get()
hyper_period_entry_info=hyper_period_entry_entry.get()
input_task_period_info=input_task_period_entry.get()
combobox_b_info=combobox_b.get()
for i in range(required):
print(a_dict['platform_id'][i].get())
global_id_label=Label(text="global_id ")
platform_id_label=Label(text='platform_id')
unique_dag_id_label=Label(text='unique_dag-id')
wcet_cpu_label=Label(text='wcet_cpu')
wcet_gpu_label=Label(text='wcet_gpu')
deadline_label=Label(text='deadline')
input_arrival_time_label=Label(text='input-arrival time')
hyper_period_entry_label=Label(text='hyper_period_entry')
input_task_period_label=Label(text='input_task_period')
freq_label=Label(text='Frequency')
platform_id_options=[
'cpu','gpu',
]
global_id_label.place(x=50,y=50)
platform_id_label.place(x=150,y=50)
unique_dag_id_label.place(x=330,y=50)
wcet_cpu_label.place(x=450,y=50)
wcet_gpu_label.place(x=600,y=50)
deadline_label.place(x=750,y=50)
input_arrival_time_label.place(x=900,y=50)
hyper_period_entry_label.place(x=1050,y=50)
input_task_period_label.place(x=1200,y=50)
freq_label.place(x=1350,y=50)
trace_entries=[]
dag_entries=[]
while(z>0):
#platform_id_drop.pack(pady=20)
def selo(eventobj):
v=[]
if(platform_id_drop.get()=='cpu'):
print("a")
v=['200000000', '300000000', '400000000', '500000000', '600000000',
'700000000', '800000000', '900000000', '1000000000' ,'1100000000', '1200000000', '1300000000', '1400000000', '1500000000' ,'1600000000', '1700000000', '1800000000', '1900000000', '2000000000']
elif(platform_id_drop.get()=='gpu'):
print("m")
v=['177000000' ,'266000000' ,'350000000' ,'420000000' ,'480000000', '543000000' , '600000000']
global_id_entry=Label(text=str(global_id))
global_id_entry.place(x=50,y=50+60*(global_id+1))
a_dict['global_id'][global_id]=global_id
unique_dag_id_entry=Label(text=str(global_id))
unique_dag_id_entry.place(x=330,y=50+60*(global_id+1))
a_dict['unique_dag_id'][global_id]=unique_dag_id_entry
wcet_cpu_entry=Entry(app)
wcet_cpu_entry.place(x=450,y=50+60*(global_id+1))
a_dict['wcet_cpu'][global_id]=wcet_cpu_entry
wcet_gpu_entry=Entry(app)
wcet_gpu_entry.place(x=600,y=50+60*(global_id+1))
a_dict['wcet_gpu'][global_id]=wcet_gpu_entry
deadline_entry=Entry(app)
deadline_entry.place(x=750,y=50+60*(global_id+1))
a_dict['deadline'][global_id]=(deadline_entry)
input_arrival_time_entry=Entry(app)
input_arrival_time_entry.place(x=900,y=50+60*(global_id+1))
a_dict['input_arrival_time'][global_id]=(input_arrival_time_entry)
hyper_period_entry_entry=Entry(app)
hyper_period_entry_entry.place(x=1050,y=50+60*(global_id+1))
a_dict['hyper_period_entry'][global_id]=(hyper_period_entry_entry)
input_task_period_entry=Entry(app)
input_task_period_entry.place(x=1200,y=50+60*(global_id+1))
a_dict['input_task_period'][global_id]=( input_task_period_entry)
platform_id_drop=ttk.Combobox(app,values=platform_id_options)
platform_id_drop.bind("<<ComboboxSelected>>",selo)
platform_id_drop.place(x=150,y=50+60*(global_id+1))
a_dict['platform_id'][global_id]=platform_id_drop
combobox_b = ttk.Combobox(app,values=v)
combobox_b.place(x=1350,y=50+60*(global_id+1))
a_dict['frequency'][global_id]=( combobox_b )
v.clear()
global_id=global_id+1
z=z-1
button=Button(app,text="save_info",command=save_trace1)
button.place(x=0,y=0)
app.mainloop()
'''

_tkinter.TclError: Item 1 already exists with tkinter treeview

I creating GUI interacting with treeview and I want to get all the value inside the list and show it in treeview window. I have a add button and once I click it, it will work fine. But on the second time, it shows an error Item 1 already exists. It also does not added to the list.
This is my code:
from tkinter import *
from tkinter import ttk
root = Tk()
def add1():
global count
for i in tree_table.get_children():
tree_table.delete(i)
get_name = txt_name.get()
get_ref = txt_ref.get()
get_age = txt_age.get()
get_email = txt_email.get()
data_list.append((get_name, get_ref, get_age, get_email))
for item in data_list:
tree_table.insert(parent='', index='end', iid=count, text=f'{count + 1}', values=(item))
txt_name.delete(0, END)
txt_ref.delete(0, END)
txt_age.delete(0, END)
txt_email.delete(0, END)
count += 1
print(data_list)
tree_table = ttk.Treeview(root)
global count
count = 0
data_list = []
tree_table['columns'] = ("Name", "Reference No.", "Age", "Email Address")
tree_table.column("#0", width=30)
tree_table.column("Name", width=120, anchor=W)
tree_table.column("Reference No.", width=120, anchor=W)
tree_table.column("Age", width=120, anchor=W)
tree_table.column("Email Address", width=120, anchor=W)
headings = ["#0", "Name", "Reference No.", "Age", "Email Address"]
txt_headings = ["No.", "Name", "Reference No.", "Age", "Email Address"]
for i in range(len(headings)):
tree_table.heading(headings[i], text=txt_headings[i], anchor=W)
txt_name = Entry(root, width=20)
txt_name.pack()
txt_ref = Entry(root, width=20)
txt_ref.pack()
txt_age = Entry(root, width=20)
txt_age.pack()
txt_email = Entry(root, width=20)
txt_email.pack()
btn_enter = Button(root, text="Add", width=20, command=add1)
btn_enter.pack()
tree_table.pack()
root.mainloop()
Traceback:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python\Python385\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "d:/Code/Cpet5/new.py", line 32, in add1
tree_table.insert(parent='', index='end', iid=count, text=f'{count + 1}', values=(item))
File "C:\Python\Python385\lib\tkinter\ttk.py", line 1366, in insert
res = self.tk.call(self._w, "insert", parent, index,
_tkinter.TclError: Item 1 already exists
How do I refresh the treeview to reflect the changes made in the list?
Quick fix:
Get rid of the iid argument:
tree_table.insert(parent='', index='end', text=f'{count + 1}', values=(item))
But that will create an issue of the No. column getting same value always.
Actual fix:
So the actual problem is your list contains alot of values, you should get rid of those values once you insert it, so the code should be something like:
def add1():
global count
get_name = txt_name.get()
get_ref = txt_ref.get()
get_age = txt_age.get()
get_email = txt_email.get()
data_list.clear() #clear the list
data_list.append((get_name, get_ref, get_age, get_email)) #append to the empty list
for item in data_list:
tree_table.insert(parent='', index='end',iid=count, text=f'{count + 1}', values=(item))
txt_name.delete(0, END)
txt_ref.delete(0, END)
txt_age.delete(0, END)
txt_email.delete(0, END)
count += 1
print(data_list)
This way your clearing whats inside of the list each time and appending new values to list.
With your older code you can see that first time the the list is [('1', '1', '1', '1')] and when the next set of values is appended it becomes [('1', '1', '1', '1'), ('2', '2', '2', '2')] so there is not enough space accommodate all this value in? Anyway this fixes it. Or you could also make a tuple of those inputs and then pass that tuple as the values for treeview without looping, like acw1668 did.
You don't need to clear the treeview before adding new row to it:
def add1():
global count
get_name = txt_name.get()
get_ref = txt_ref.get()
get_age = txt_age.get()
get_email = txt_email.get()
row = (get_name, get_ref, get_age, get_email)
data_list.append(row)
count += 1
tree_table.insert(parent='', index='end', iid=count, text=f'{count}', values=row)
txt_name.delete(0, END)
txt_ref.delete(0, END)
txt_age.delete(0, END)
txt_email.delete(0, END)
print(data_list)

Python tkinter: Getting the number of entries in an OptionMenu dropdown list

The function below creates a nicely formatted list of all attributes of an OptionMenu widget. However a kludge is needed because OptionMenu does not having a "Menu size"' attribute (that holds the number of elements inside the dropdown list).
How do I extract this value from the widget so I can eliminate the kludge (and show the attributes of EVERY entry in the drop-down menu) ?
BTW, The function does not list the contents of the (non-standard) Optionmenu "command" option. For info on this option see the accepted answer to tkinter OptionMenu issue (bug?): GUI and program values not kept in lockstep (python 3.x) )
def OptionMenuConfigLister( OptionMenuWidget ) :
'''
Uncomment this block to see ALL attributes of the widget
#
# Gets the main attributes of the widget (EXCLUDING the attributes for
# the dropdown list and the values in the list)
#
print( " \nOptionMenuWidget.config()\n" )
for i, j in enumerate( sorted( OptionMenuWidget.config().items() ) ) :
print( " {0:<19} |{1}|".format( j[ 0 ], j[ 1 ][ -1 ] ), flush = True )
#
# Gets the attributes of the list portion of the widget (but NOT the entries)
#
print( "\nOptionMenuWidget[ 'menu' ].config().items() :\n" )
for i, j in enumerate( sorted( OptionMenuWidget[ 'menu' ].config().items() ) ) :
print( " {0:<18} |{1}|".format( j[ 0 ], j[ 1 ][ -1 ] ), flush = True )
'''
#
# Get the attributes of each/every entry in the dropdown list
#
# TODO: Determine how to get # of items in list
#
for i in range( 0, 1 ) : ''' <======== KLUDGE '''
print( "\nOptionMenuWidget[ 'menu' ].entryconfig(" + str( i ) + ").items()) :\n" )
for _, j in enumerate( sorted(
OptionMenuWidget[ 'menu' ].entryconfig( i ).items() ) ) :
print( " {0:<16} |{1}|".format( j[ 0 ], j[ 1 ][ -1 ] ), flush = True )
print()
return
EDIT 20180117: Here's the fix, based on the answer by #nae - replace the kludge line with:
ElementCount = OptionMenuWidget[ 'menu' ].index( 'end' ) + 1
for i in range( 0, ElementCount ) :
And as per comment by #furas, sample code now uses [ -1 ] in the formatted print statements.
Based on Menu total index counts and from the source code, the fact that OptionMenu's *values are stored as Menu items:
class OptionMenu(Menubutton):
"""OptionMenu which allows the user to select a value from a menu."""
def __init__(self, master, variable, value, *values, **kwargs):
...
menu.add_command(label=value,
command=_setit(variable, value, callback))
for v in values:
menu.add_command(label=v,
command=_setit(variable, v, callback))
self["menu"] = menu
One can extract the 'Menu Size' using .index('end') for OptionMenu's menu option like the following:
import tkinter as tk
root = tk.Tk()
opt_var = tk.IntVar()
opt = tk.OptionMenu(root, opt_var, 3, 2, 3, 5, 4)
opt.pack()
print(opt['menu'].index('end') + 1) # basically len(*values) + len(value)
root.mainloop()

Categories

Resources