Tkinter python dependent combobox - python

I am a python and arcpy user and I have a problem about dependent combobox. Actually I have asked the same topic on here, but no one answer yet. I've got the answer from here and here. But I think I am too newbie on python programming and I don't get the answer clearly.
I try my code like this below, base on the answer that I've got before:
import Tkinter
from Tkinter import *
root = Tkinter.Tk()
bu = StringVar()
bu.set("")
businessunit = ["DUM", "IND", "KAM", "RAP"]
bu_menu = OptionMenu(root, bu, *businessunit, command=Combobox_1)
bu_menu.config(bg="white", fg="dark blue", width=3, relief=GROOVE)
bu_menu.place(x=95, y=110)
sec = StringVar()
sec.set("")
sector = {"DUM":['GRG', 'KBU', 'LBO', 'PLS', 'PLU', 'PPR', 'RPT', 'SBI', 'SKB'],
"IND":['BYS','MER','NGD','PER','SJG','SLJ'],
"KAM":['RSG','SRG','SRY','TSK'],
"RAP":['BAS','CER','LGB','LON','LOS','MDU','MRE','MRW','PEN','PES','PPD','TEE','TEW','TSB','UKU']}
sec_menu = OptionMenu(root, sec, *sector, command=Combobox_2)
sec_menu.config(bg="white", fg="dark blue", width=3, relief=GROOVE)
sec_menu.place(x=155, y=110)
def __init__(self):
def Combobox_1(businessunit):
print bu.get()
def Combobox_2(sector):
print sec.get()
self.Combobox_1.activated[str].connect(self.on_combo_activated)
def on_combo_activated(self, text):
self.Combobox_2.clear()
self.Combobox_2.addItems(self.sector[text])
root.pack()
root.mainloop()
root.destroy()
Please anyone help me on this. Thank you so much for your answer.
edited:
in this case, dependent combobox means:
If DUM is selected in Combobox_1, Combobox_2 will only show GRG,KBU,LBO, etc.
If IND is selected in Combobox_1, Combobox_2 will only show BYS,MER,PER, etc.
If KAM is selected in Combobox_1, Combobox_2 will only show RSG,SRG,SRY, etc.
If RAP is selected in Combobox_1, Combobox_2 will only show BAS,CER,LGB, etc.

I would advise looking at: Change OptionMenu based on what is selected in another OptionMenu
Just change the values as you need them in your menu.
(Also, you don't need to import Tkinter twice, just use "import Tkinter" or "import Tkinter as tk")

Thank you for your contribution. Actually I've got the answer of this question in my question before. Please see this link Graded combobox Menu Python Tkinter

This is called a cascade combo box. Basically in your command (action) you then create the second box with the data based on the selected value of the first. This is easy with a database i dont know of other ways but some sort of array or dictionary should also work fine.
I do it in a class that I call from my app so this is a little over complicated but can be easily simplified if you dont want to bother with the class vals is a dictionary that looks like {'value1':number,'value2':number2} to keep the index needed fro a database call to get more values or whatever. I am using .grid you can use pack or whatever suits you.
def ebox(self, index=None, row=None, column=None, vals=None):
self.value[index] = tk.StringVar()
lis = []
for item in vals:
lis.append(item)
self.combos[index] = ttk.Combobox(self.win, values=lis, textvariable=self.value[index])
self.combos[index].bind("<<ComboboxSelected>>", lambda event, y=vals: self.eboxclk(event, y))
self.combos[index].grid(row=row, column=column)
return
def eboxclk(self, event=None, index=None):
print(event.widget.get(), " widget get ")
print(index[event.widget.get()], " this should be your index")
return
I initialize a dictionary for my widgets, but you could just skip it and just
mycombo = ttk.Combobox(master,values=alist, textvariable=tk.StringVar)
mycombo.bind('<<ComboboxSelected>>', lambda event, dict: dosomething(event, dict)

Related

is there a way to jump from one entry field to another entry field in tkinter?

I was trying to make billing software with multiple entries in python, so it's hard to move from one entry field to another entry field using a mouse, I just wanted it to jump from the customer name field to customer phone no entry was filed when I press "enter" key but it's not working how can I make it work
from Tkinter import*
root = Tk()
root.geometry('1350x700+0+0')
root.resizable(width=False,height=False)
root.title('Billing App')
def jump_cursor(event):
customer_PhoneNo_entry.icursor(0)
customer_detail_frame=Frame(root,bd=10,highlightbackground="blue", highlightthickness=2)
customer_detail_frame.place(x=0,y=10,width=1350,height=100)
customer_detail_lbl=Label(customer_detail_frame,text="customer detail",font=('verdana',10,'bold'))
customer_detail_lbl.grid(row=0,column=0,pady=10,padx=20)
customer_name_lbl=Label(customer_detail_frame,text="customer name",font=('verdana',10,'bold'))
customer_name_lbl.grid(row=1,column=0,pady=10,padx=20)
customer_name_entry=Entry(customer_detail_frame,width=20,textvariable = Customer_Name)
customer_name_entry.grid(row=1,column=1,pady=10,padx=20)
customer_phoneno_lbl=Label(customer_detail_frame,text="phone no.",font=('verdana',10,'bold'))
customer_phoneno_lbl.grid(row=1,column=2,pady=10,padx=20)
customer_PhoneNo_entry=Entry(customer_detail_frame,width=20,textvariable = Customer_Ph_No)
customer_PhoneNo_entry.grid(row=1,column=3,pady=10,padx=20)
customer_PhoneNo_entry.bind("<Return>",jump_cursor)
This answer helped me with the same problem.
First, get all children of customer_detail_frame which are Entry,
using winfo_children()
Second, bind each child to <Return>, (in which lambda can be used
to create another function).
Last, define the jump_cursor function, such that it switches the
focus to the desired widget, using focus_set().
Here is what changes in your code would look like:
from tkinter import*
root = Tk()
root.geometry('1350x700+0+0')
root.resizable(width=False,height=False)
root.title('Billing App')
Customer_Name, Customer_Ph_No = StringVar(), StringVar()
customer_detail_frame=Frame(root,bd=10,highlightbackground="blue", highlightthickness=2)
customer_detail_frame.place(x=0,y=10,width=1350,height=100)
customer_detail_lbl=Label(customer_detail_frame,text="customer detail",font=('verdana',10,'bold'))
customer_detail_lbl.grid(row=0,column=0,pady=10,padx=20)
customer_name_lbl=Label(customer_detail_frame,text="customer name",font=('verdana',10,'bold'))
customer_name_lbl.grid(row=1,column=0,pady=10,padx=20)
customer_name_entry=Entry(customer_detail_frame,width=20,textvariable = Customer_Name)
customer_name_entry.grid(row=1,column=1,pady=10,padx=20)
customer_phoneno_lbl=Label(customer_detail_frame,text="phone no.",font=('verdana',10,'bold'))
customer_phoneno_lbl.grid(row=1,column=2,pady=10,padx=20)
customer_PhoneNo_entry=Entry(customer_detail_frame,width=20,textvariable = Customer_Ph_No)
customer_PhoneNo_entry.grid(row=1,column=3,pady=10,padx=20)
def jump_cursor(event, entry_list, this_index):
next_index = (this_index + 1) % len(entry_list)
entry_list[next_index].focus_set()
entries = [child for child in customer_detail_frame.winfo_children() if isinstance(child, Entry)]
for idx, entry in enumerate(entries):
entry.bind('<Return>', lambda e, idx=idx: jump_cursor(e, entries, idx))
root.mainloop()

Button command doesn't updates my Label textvariable

I have this very easy program which I want to display one random line from a file each time I click on the Button.
Problem is a new line is display at startup of the program, but nothing happens when I click the button, can someone explain me why ?
from random import randrange
from tkinter import *
def entree():
n=randrange(251)
fs = open('lexique','r')
liste = fs.readlines()
return liste[n]
fen = Tk()
fen.title("lexique anglais politique")
defi = StringVar()
defi.set(entree())
lab = Label(fen, textvariable=defi).pack()
Button(fen, text='Beste Bat', command=entree).pack()
fen.mainloop()
As stated in one of the comments (by #matszwecja), your entree() function doesn't really do anything appart from returning a value.
Nothing in your code updates the actual label. Try something like this :
from random import randrange
from tkinter import *
def entree():
n=randrange(251)
fs = open('lexique','r')
liste = fs.readlines()
return liste[n]
def update_label():
lab.config(text=entree())
fen = Tk()
fen.title("lexique anglais politique")
lab = Label(fen, text=entree())
lab.pack()
Button(fen, text='Beste Bat', command=update_label).pack()
fen.mainloop()
In this example, the entree() function is used to go get a line from your file, and the update_label() function is used to actually update the label.
Also, if you want to be able to update a label, you'll have to pack it after assigning it to a variable.
On a side note, it could be worth noting that hardcoding values that could change in the future is generally considered bad practice. In that regard, I think coding the entree() function this way might be a better idea :
def entree():
fs = open('lexique','r')
liste = fs.readlines()
n=randrange(len(liste))
return liste[n]
This way, if you ever add or remove lines to your "lexique" file, you will not have to change the code.

How to create a letter counter with Tkinker?

I just started to learn Python and I'm trying to create a mineral counter by only using letters for microscopic petrography, but I am having problems passing my python code to Tkinker. Can you guys give tips about how to get my output to work? I'm finding it challenging to use theget() method even with online tutorials.
Can you guys teach this noob? Thank you!
My original code:
# define sample
sample = "qreqqwer"
# mineral q:
mineralq= "q"
countq = sample.count(mineralq)
# print count of q
print("The quantity of q is: ", countq)
The structure I made with Tkinker:
from tkinter import *
import tkinter as tk
# Window
window=tk.Tk()
window.title("Mineral Counter")
window.geometry("800x1000")
window.configure(bg="#00090F")
inputUser=tk.Text(window,width=225,height=5,font=("Arial bold",12),wrap="word", bg="#00090F", fg="white")
inputUser.pack()
# define sample
# mineral q:
countq = inputUser.count("q")
# print count of q
output.insert(tk.INSERT,countq)
output=tk.Text(window,width=20,height=2,font=("Arial bold",12), bg="#00090F", fg="white")
output.pack()
window.mainloop()
You need a button to update your code, becuase initially the Text boxes are empty and hence there is no occurence for q so nothing can be inserted.
Try this out:
First create a button with a function to click onto after the data is entered
b = tk.Button(window, text='Click Me', command=click)
b.pack()
Then now define the function that the button calls when is clicked onto
def click():
sample = inputUser.get('1.0', 'end-1c') #getting value from text box 1
mineralq = 'q' #letter to be counted
countq = sample.count(mineralq) #counting the letter
output.insert('1.0', f'The quantity of q is: {countq}') #inserting the output to text box 2
Hope it cleared your doubt, if any errors do let me know
Cheers

Change the color of a single word in a tk option menu?

So I'm grabbing links of events off a website and putting them into a drop down menu to be selected. My code for the menu:
import Tkinter as tk
from Tkinter import StringVar
selectMenu = tk.Tk()
# #-> this is what I have
# Followed by what you can use
#var = Vars()
#events = var.GetVars('Event')
events = " "
options = []
links = []
#forms = (driver.find_elements_by_class_name("with-cats")) #This is what I have
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
for x in forms:
#info = x.text
info = x #Again, this is so you can try it for yourself
if events in info.lower():
links.append(x)
for link in range(0,len(links)):
#options.append(links[link].text)
options.append(links[link])
list(set(options))
selection = []
for link in range(0,len(options)):
selection.append(options[link])
select = StringVar(selectMenu)
select.set("--None Selected--")
menu = tk.OptionMenu(selectMenu, select, *(selection))
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menu.pack(side="top", pady=10)
selectMenu.attributes('-topmost', True)
selectMenu.mainloop()
So this works fine and dandy, but I would like to improve the look to make it more obvious which events are open. To clarify, an event found that is open and put into the menu may look like "This is a cool event", but one that is closed would be read as "This is a cool event Closed". My aim is to be able to make the foreground red of either just the word Closed or the string containing Closed, whichever is possible if any (And I'm not sure if it's possible because menus and buttons on osx are usually defaulted to system settings, maybe there is a way around this?).
Current: Desired:
According to the documentation for OptionMenu here and here I don't think there is a way to set the color of text.
You might be able to get something close to what you want by using a listBox instead. See post here for the listBox example.
Found a solution! Using a Menu inside of a MenuButton the same way Tkinter creates MenuOptions, I was able to create a custom MenuOption. If you want to add more options, you can use the menbutton.configure() option to edit the button, and menbutton.menu to edit the menu items.
import Tkinter as tk
from Tkinter import Menu, Menubutton
class Vars():
global vari
vari = {}
def GetVars(self, var):
return vari.get(str(var))
def SendVars(self, var, val):
vari[str(var)] = val
class App():
def buttselect(self, link, menbutton, selectMenu):
var = Vars()
var.SendVars("Selection", link) # Store selected event
menbutton.configure(text=link) # Set menu text to the selected event
def prnt(self, link):
var = Vars()
print var.GetVars("Selection") # Print event
def __init__(self, selectMenu):
events = " "
options = []
links = []
forms = ["Yolo ","Dad? Closed","Anotha One","Normies! Closed"] #This is so you can try it for yourself
menbutton = Menubutton (selectMenu, text="--None Selected--", relief="raised")
menbutton.grid()
menbutton.menu = Menu (menbutton, tearoff=0)
menbutton["menu"] = menbutton.menu
#Get a list of event names
for x in forms:
info = x #Again, this is so you can try it for yourself
#If desired event keyword is in an event name, add it to the correct links
if events in info.lower():
links.append(x)
#Remove duplicates
for link in range(0,len(links)):
options.append(links[link])
list(set(options))
#Final list of event names turned into menu commands
for link in options:
if "Closed" in link:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu), foreground='red')
else:
menbutton.menu.add_command( label= link, command= lambda link=link: self.buttselect(link, menbutton, selectMenu))
b = tk.Button(selectMenu, text="Selection", command= lambda link=link: self.prnt(link)) #Print selected event
b.pack()
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menbutton.pack(side="top", pady=10)
selectMenu = tk.Tk()
selectMenu.attributes('-topmost', True)
app = App(selectMenu)
selectMenu.mainloop()
This results in exactly the result desired:
I found a way!
Let's say x is an optionmenu with options:
options=['Red','Blue','Green']
defopt=tk.StringVar(options[0]) #StringVariable to hold the selected option.
x=tk.OptionMenu(self.optmenuframe,defopt,*options)
Now, get the menu object from the optionmenu and use entryconfig method. That's it!
x.children['menu'].entryconfig(0,foreground='red')
x.children['menu'].entryconfig(1,foreground='blue')
x.children['menu'].entryconfig(2,foreground='green')
#0 is the index of the option you want to apply the configurations to.

Python Tkinter/GUI Not Updating/Working Correctly

I'm wondering if anyone can give me a quick simple fix for my issue.
I'm trying to make a program (as a gcse mock) that will obtain the position of words in a sentence.
I have the sentence bit working great in the text however I want to go above and beyond to get the highest possible marks so I'm creating it again with a gui!
So far I have the following code and it's not working correctly, it's not updating the 'sentence' variable and I'm looking for a simple way around fixing this Instead of updating. I get some random number which I'm not sure where it has come from. Any help will be much appreciated. :)
#MY CODE:
#GCSE MOCK TASK WITH GUI
import tkinter
from tkinter import *
sentence = ("Default")
window = tkinter.Tk()
window.resizable(width=FALSE, height=FALSE)
window.title("Sentence")
window.geometry("400x300")
#Add custom logo here later on
def findword():
print ("")
sentencetext = tkinter.Label(window, text="Enter Sentence: ")
sentence = tkinter.Entry(window)
sentencebutton = tkinter.Button(text="Submit")
findword = tkinter.Label(window, text="Enter Word To Find: ")
wordtofind = tkinter.Entry(window)
findwordbutton = tkinter.Button(text="Find!", command = findword)
usersentence = sentence.get()
usersentence = tkinter.Label(window,text=sentence)
shape = Canvas (bg="grey", cursor="arrow", width="400", height="8")
shape2 = Canvas (bg="grey", cursor="arrow", width="400", height="8")
#Packing & Ordering Modules
sentencetext.pack()
sentence.pack()
sentencebutton.pack()
shape.pack()
findword.pack()
wordtofind.pack()
findwordbutton.pack()
usersentence.pack()
shape2.pack()
window.mainloop()
Currently your sentence's 'submit' button doesn't actually have a command bound, and the two 'sentence' references are likely to conflict:
sentencebutton = tkinter.Button(text="Submit")
sentence = ("Default")
sentence = tkinter.Entry(window)
I can see that what you've tried to do is set it so that the variable sentence changes from "Default" to whatever one enters in the Entry window - this will not work, all you've done is set it so that sentence becomes the entry widget itself, not whatever is entered.
I would recommend creating a function called something like 'update_sentence', and rename your initial 'sentence' variable to distinguish it from the label:
var_sentence = "default"
def update_sentence:
var_sentence = sentence.get()
And then change your button so it has a command, like so:
sentencebutton = tkinter.Button(text="Submit", command = update_sentence)
Hope this helps!

Categories