Drop down list dependent from another drop down tkinter - python

I have one list with car brands in it and a second list with model names from these brands. I want to have two dropdown lists. First you select the brand and in the second dropdown you can select the model. But just models from the selected brand. I got the following code.
import tkinter as tk
brands = ["Bugatti","VW","Opel","Porsche"]
models = [["Veyron","Chiron"],
["Golf","Passat","Polo","Caddy"],
["Insignia","Corsa","Astra"],
["Taycan","Cayenne","911"]]
root = tk.Tk()
canvas = tk.Canvas(root, height=500, width= 500, bg="white")
canvas.pack()
tkvar = tk.StringVar(root)
tkvar.set('Choose')
popupMenu1 = OptionMenu(canvas, tkvar, *brands)
popupMenu1.pack()
def change_dropdown(*args):
print("Chosen brand " + tkvar.get())
for i in range(len(brands)):
if tkvar.get() == brands[i]:
print(models[i])
tkvar.trace('w', change_dropdown)
root.mainloop()
How do i now create a second dropdown with the information from the list models. Thanks for your help.

You can use Combobox to make dependent dropdown list
import tkinter
from tkinter import ttk
root = tkinter.Tk()
'''
widgets are added here
'''
brands = ["Bugatti","VW","Opel","Porsche"]
models = [["Veyron","Chiron"],
["Golf","Passat","Polo","Caddy"],
["Insignia","Corsa","Astra"],
["Taycan","Cayenne","911"]]
car_brand = ttk.Combobox(root, width=37, value=(brands))
car_brand.grid(row=3, column=1, columnspan=2, padx=10, pady=2, sticky='w')
def callback(eventObject):
abc = eventObject.widget.get()
car = car_brand.get()
index=brands.index(car)
car_model.config(values=models[index])
car_model = ttk.Combobox(root, width=37)
car_model.grid(row=4, column=1, columnspan=2, padx=10, pady=2, sticky='w')
car_model.bind('<Button-1>', callback)
root.mainloop()

import tkinter as tk
brands = ["Bugatti","VW","Opel","Porsche"]
models = [["Veyron","Chiron"],
["Golf","Passat","Polo","Caddy"],
["Insignia","Corsa","Astra"],
["Taycan","Cayenne","911"]]
root = tk.Tk()
canvas = tk.Canvas(root, height=500, width= 500, bg="white")
canvas.pack()
tkvar = tk.StringVar(root)
tkvar.set('Choose')
tkvar2 = tk.StringVar(root)
tkvar2.set('Model')
popupMenu1 = tk.OptionMenu(canvas, tkvar, *brands)
popupMenu1.pack()
popupMenu2 = tk.OptionMenu(canvas, tkvar2, [])
popupMenu2.pack()
def change_dropdown(*args):
print("Chosen brand " + tkvar.get())
for i in range(len(brands)):
if tkvar.get() == brands[i]:
popupMenu2["menu"].delete(0, "end")
for item in models[i]:
popupMenu2['menu'].add_command(label=item, command=tk._setit(tkvar2, item))
tkvar.trace('w', change_dropdown)
root.mainloop()

Related

How to change the theme of my tkinter application in Python?

I'm trying to change my Tkinter theme but when I change s.theme_use('classic') to s.theme_use('calm') or s.theme_use('winnative') nothing changes.
Here is my code:
from tkinter import *
import tkinter.ttk as ttk
window = Tk()
window.title("Running Python Script") # Create window
window.geometry('550x300') # geo of the window
s=ttk.Style()
list_themes = s.theme_names()
current_theme = s.theme_use()
s.theme_use('classic')
print(list_themes)
def run():
if dd_owner.get() == "Spain":
print("spain")
# These are the option menus
dd_owner = StringVar(window)
dd_owner.set(owner[0]) # the first value
w = OptionMenu(window, dd_owner, *owner)
w.grid(row=0, column=1)
#The run button
run_button = Button(window, text="Run application {}".format(dd_owner.get()), bg="blue", fg="white",command=run)
run_button.grid(column=0, row=2)
# These are the titles
l1 = Label(window, text='Select Owner', width=15)
l1.grid(row=0, column=0)
mainloop()
Below is an modified example using ttk widgets based on your code:
from tkinter import *
import tkinter.ttk as ttk
import random
window = Tk()
window.title("Running Python Script") # Create window
window.geometry('550x300') # geo of the window
s=ttk.Style()
s.configure("TButton", foreground="red", background="blue")
list_themes = s.theme_names()
current_theme = s.theme_use()
#s.theme_use('classic')
print(list_themes)
def run():
if dd_owner.get() == "Spain":
print("spain")
# choose a theme randomly
theme = random.choice(list_themes)
print("theme:", theme)
s.theme_use(theme)
# These are the option menus
owner = ("Spain", "France", "Germany")
dd_owner = StringVar(window)
dd_owner.set(owner[0]) # the first value
#w = OptionMenu(window, dd_owner, *owner)
# use ttk.Combobox instead of OptionMenu
w = ttk.Combobox(window, textvariable=dd_owner, values=owner)
w.grid(row=0, column=1)
#The run button
#run_button = Button(window, text="Run application {}".format(dd_owner.get()), bg="blue", fg="white",command=run)
# use ttk.Button
run_button = ttk.Button(window, text="Run application {}".format(dd_owner.get()), command=run)
run_button.grid(column=0, row=2)
# These are the titles
l1 = ttk.Label(window, text='Select Owner', width=15)
l1.grid(row=0, column=0)
mainloop()
When you click the button, it will change the theme randomly.

How to define different styles/themes with tkinter

I am learning tkinter and have noticed something with using styles when trying to have different windows or frames with styles.
In the code example I provided, if I change the style attributes on frame2, they also show in frame1. If I change the order of execution then the reverse happens.
How can I define styles that are specific to each frame or window?
Thanks
Dan
from tkinter import *
import tkinter as tk
from tkinter import ttk
def showframe1():
f1_columns = ('#1', '#2')
f1_tree = ttk.Treeview(frame1, columns=f1_columns, show='headings')
f1_style = ttk.Style()
f1_style.theme_use("default")
f1_style.configure("Treeview",
background="white",
foreground="black",
rowheight=25 # Height of each row in tree
)
f1_tree.heading('#1', text='First Name')
f1_tree.heading('#2', text='Last Name')
f1_tree.column("#1", width=150)
f1_tree.column("#2", width=150)
# generate sample data
contacts = []
for n in range(1, 100):
contacts.append((f'first {n}', f'last {n}'))
# adding data to the frame1 tree
for contact in contacts:
f1_tree.insert('', tk.END, values=contact)
f1_tree.grid(row=0, column=0, sticky='nsew')
def showframe2():
f2_columns = ('#1', '#2', '#3')
f2_tree = ttk.Treeview(frame2, columns=f2_columns, show='headings')
f2_style = ttk.Style()
f2_style.theme_use("default")
f2_style.configure("Treeview",
background="lightblue",
foreground="black",
rowheight=25 # Height of each row in tree
)
f2_tree.heading('#1', text='First Name')
f2_tree.heading('#2', text='Last Name')
f2_tree.heading('#3', text='Email')
f2_tree.column("#1", width=150)
f2_tree.column("#2", width=150)
f2_tree.column("#3", width=250)
# generate sample data
contacts = []
for n in range(1, 100):
contacts.append((f'first {n}', f'last {n}', f'email{n}#example.com', f'email{n}#example.com'))
# adding data to the frame2 tree
for contact in contacts:
f2_tree.insert('', tk.END, values=contact)
f2_tree.grid(row=0, column=0, sticky='nsew')
def exit_root(event):
root.destroy()
root = tk.Tk()
root.title('Frame Styles Example')
root.geometry('600x800')
frame1 = Frame(root, bd=5, relief='sunken')
frame1.grid(row=0, column=0, padx=20, pady=10, sticky=N + W)
frame2 = Frame(root, bd=5, relief='sunken')
frame2.grid(row=1, column=0, padx=20, pady=10, sticky=N + W)
showframe1()
showframe2()
root.bind('<Return>', exit_root)
# run the app
root.mainloop()
I found a good tutorial at https://www.pythontutorial.net/tkinter/ttk-style/
I needed to create a custom Treeview style for the additional frame(s). I just created two custom styles.
f1_style.configure("f1.Treeview",....)
f2_style.configure("f2.Treeview",....)
Then assign the style to each Treeview definition.
ttk.Treeview(frame1, columns=f1_columns, show='headings',style='f1.Treeview')
ttk.Treeview(frame2, columns=f2_columns, show='headings',style='f2.Treeview')
With this, I can control the style of each frame.

How to position Layouts in tkinter?

I would like to make the following GUI.. each python class was made and working well with the name suggested below.
For example, elements_structure related class is looking like
class Elements_Structure():
def __init__(self, root):
super(Elements_Structure, self).__init__(root)
self.create_GUI()
def create_GUI(self):
label = Label(self, text="Elements Structure", font=("Arial",12)).grid(row=0, sticky=W)
cols = ('L#', 'Layer Name', 'Material', 'Refractive Index', 'Thickness', 'Unit')
listBox = Treeview(self, columns=cols, show='headings')
and the main entry code is looking like,
from tkinter import *
from components.elements_structure import *
from components.emission_layer import *
from components.emission_zone_setting import *
from components.file_tab import *
from components.logo_image import *
def main(root):
top_frame = Frame(root, width=1980, height=780).grid(rowspan=4, columnspan=4)
bottom_frame = Frame(root, width=1980, height=230).grid(columnspan=4)
elements_structure_graph = Frame(top_frame, width=480, height=780).grid(row=0, column=0, rowspan=4)
elements_structure = Frame(top_frame, width=960, height=690).grid(row=0, column=1, rowspan=3, columnspan=2)
logo_image = Frame(top_frame, width=480, height=230).grid(row=0, column=2)
logo_properties = Frame(top_frame, width=480, height=230).grid(row=1, column=2)
logo_execute = Frame(top_frame, width=480, height=230).grid(row=2, column=2)
emission_layer = Frame(top_frame, width=1440, height=100).grid(row=2, column=2, colspan=3)
emission_layer_graph = Frame(bottom_frame, width=480, height=290).grid(row=0, column=0)
emission_zone_setting = Frame(bottom_frame, width=480, height=290).grid(row=0, column=2)
emission_zone_setting_graph = Frame(bottom_frame, width=480, height=290).grid(row=0, column=1)
logo_project_info = Frame(bottom_frame, width=480, height=290).grid(row=0, column=3)
root.title("JooAm Simulator")
root.geometry('{}x{}'.format(1920, 1080))
root.mainloop()
if __name__ == '__main__':
root = Tk()
File_Tab(root)
main(root)
But I seemed to miss the link between the class and the tkinter window object.
How can I make the above structure with the library tkinter?
Thank you in advance~!!
Lot to deal with here. Can't work on the code without the components file.
Most on what is in main should be in create_GUI.
I like to start with something like:
class OLED_Display:
def init(self, master):
self.master = master
self.frame = tk.Frame(self.master)
bg_color='light green'
self.button1 = tk.Button(self.frame, text = 'Constants',
width = 35, command = 'ANY USER FUNCTION', bg=bg_color)
You can try from there or provide more info.

Tkinter - set label for listbox

I'm trying to do a simple GUI in Tkinter. I have a Listbox there and I want the user to know what kind of data is in the Listbox so I want to set a label for it (upper).
The problem is that when I set a label, this Listbox disappears.
l = Label(multiple_choose_days_listbox, textvariable=label_day_listbox , anchor=NW, justify='center')
l.pack()
The solution is probably obvious but I'm new in Tkinter.
Do you have any advices?
import Tkinter
import tkSimpleDialog
from Tkinter import *
import db
import ttkcalendar
class CalendarDialog(tkSimpleDialog.Dialog):
"""Dialog box that displays a calendar and returns the selected date"""
def __init__(self, master):
self.calendar = ttkcalendar.Calendar(master)
# self.calendar.pack()
#property
def result(self):
return self.calendar.selection
def pack(self,**kwargs):
self.calendar.pack(**kwargs)
states_list = db.get_states()
bought_days_before_list = db.get_bought_days_before()
multiple_choose_length_of_trips_list = db.get_lengths_of_trips()
def main():
root = Tkinter.Tk()
root.wm_title("CalendarDialog Demo")
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.geometry("1000x500")
top = Frame(root)
bottom = Frame(root)
top.pack(side=TOP)
bottom.pack(side=BOTTOM, fill=BOTH, expand=True)
cd_1 = CalendarDialog(root)
cd_2 = CalendarDialog(root)
cd_1.pack(in_=top, side=LEFT)
cd_2.pack(in_=top, side=LEFT)
multiple_choose_states_listbox = Listbox(root, selectmode=EXTENDED)
multiple_choose_states_listbox.grid(row=20, columns=1)
multiple_choose_days_listbox = Listbox(root, selectmode=EXTENDED)
multiple_choose_length_of_trips_list_listbox = Listbox(root, selectmode=EXTENDED)
label_day_listbox = StringVar()
label_day_listbox.set("LABEL")
l = Label(multiple_choose_days_listbox, textvariable=label_day_listbox , anchor=NW, justify='center')
l.pack()
multiple_choose_days_listbox.pack(in_=top,side=LEFT)
multiple_choose_states_listbox.pack()
multiple_choose_length_of_trips_list_listbox.pack()
for item in states_list:
multiple_choose_states_listbox.insert(END, item)
for item in bought_days_before_list:
multiple_choose_days_listbox.insert(END, item)
def get_result_dict():
date_from = cd_1.result
date_to = cd_2.result
states = [states_list[i] for i in multiple_choose_states_listbox.curselection()]
bought_days_before = [bought_days_before_list[i] for i in multiple_choose_days_listbox.curselection()]
length_of_trip = [states_list[i] for i in multiple_choose_length_of_trips_list.curselection()]
res_dict = {
'date_from': date_from,
'date_to': date_to,
'states': states,
'bought_days_before': bought_days_before,
'length_of_trip': length_of_trip,
}
return res_dict
button = Tkinter.Button(root, text="Generate", command=get_result_dict)
button.pack()
root.update()
root.mainloop()
if __name__ == "__main__":
main()
It should be
l = Tkinter.Label(root, text="Label")

How can I add a tkinter combobox widget to a gui that also has text entry widgets?

I am developing a gui with text entry widgets that regenerate based on the number of a records in a table. I am using a list of fields that are each created as an entry widget. For at least one of these fields, I want to set up a combobox with values for the user to choose from. I've been playing around with adding a combobox to the root (I've just inserted a sample one for now) but it doesn't show up when I run the script. I don't get an error, the gui shows up with all the entry boxes, but not the combobox. Does anyone have any ideas: Here is some of the code:
import arcpy, tkMessageBox, ctypes, ttk
from Tkinter import *
mosaicD = r'C:\temp\temp.gdb\mapIndex_MD_test'
mapIndexTbl = r'C:\temp\temp.gdb\mapIndexTestTable'
formFields = ['County', 'Route', 'PMB', 'PME', 'Map_Sheet_Desc', 'HangingFileGroup', 'MapSubSet', 'MapSubSetStatus', 'Shtext', 'Status',
'SubStatus', 'MapDatum', 'Geo_Referenced_Datum', 'MapScale', 'CAD', 'DrawingDate', 'FileExtention','Original_MrSID_Filename']
fields = arcpy.ListFields(mapIndexTbl)
with arcpy.da.SearchCursor(mosaicD,'name') as cursorB:
for rowB in cursorB:
inputValues = []
def fetch(entries):
for entry in entries:
field = entry[0]
text = entry[1].get()
inputValues.append(text)
root.destroy()
def makeform(root, fields):
entries = []
for field in fields:
row = Frame(root)
lab = Label(row, width=20, text=field, anchor='w')
ent = Entry(row)
row.pack(side=TOP, fill=X, padx=5, pady=5)
lab.pack(side=LEFT)
ent.pack(side=RIGHT, expand=YES, fill=X)
entries.append((field, ent))
return entries
if __name__ == '__main__':
root = Tk()
root.iconbitmap(r'\\sv04docifs5\data5\vol2\Records\GIS\Logos\CT.ico')
root.geometry('375x650')
root.wm_title('Enter values for '+rowB[0])
cities = ('Toronto', 'Ottawa', 'Montreal', 'Vancouver', 'St. John')
cblist = Frame(root)
cbp3 = ttk.Labelframe(cblist, text='Pre-defined List')
cb3 = ttk.Combobox(cbp3, values=cities, state='readonly')
cb3.current(1) # set selection
cb3.pack(side=LEFT, expand=YES, fill=X)
# position and display
cbp3.pack(in_=cblist, side=TOP, pady=5, padx=10)
ents = makeform(root, formFields)
root.bind('<Return>', (lambda event, e=ents: fetch(e)))
b1 = Button(root, text='Submit',
command=(lambda e=ents: fetch(e)))
b1.pack(padx=5, pady=5,anchor=CENTER)
#b2 = Button(root, text='Quit', command=root.quit)
#b2.pack(side=LEFT, padx=5, pady=5)
root.mainloop()
The combobox cb3 is packed in the frame cbp3. That frame is packed in frame cblist. Nowhere do you call pack or grid on cblist. Since cblist is invisible, so are its children.

Categories

Resources