I am a newbie to python and tkinter and I ran into a problem as I was practicing on Combobox. I wrote this code with two dependent combobox. If in the first combobox, 'Jan' is selected, the second one will be enabled and automatically give 'J' as the only choice to choose from.
When I ran my code and selected 'Jan' in Combobox1, the combobox 2 was enabled, but it didn't have any value (in this case 'J').
Can someone help me with this?
import ttk
root = Tk()
root.geometry("400x400")
month = StringVar()
combobox1 = ttk.Combobox(root, textvariable = month)
combobox1.config(values = ('Jan', 'Feb', 'August'))
combobox1.pack()
date = StringVar()
global comb2
comb2 = ttk.Combobox(root, textvariable = date)
comb2.pack()
comb2.config(state=DISABLED)
def comb1_selected(*args):
if (combobox1.current() != -1 ):
comb2.config(state='normal')
if combobox1.current() == "Jan":
comb2.config(values=('J'))
combobox1.bind("<<ComboboxSelected>>", comb1_selected)
root.mainloop()```
Combobox.current() returns the index of the selected item. In your case it is 0.
If you want to get the value of the selected item, you should use Combobox.get().
def comb1_selected(*args):
if (combobox1.current() != -1 ):
print('current: ' + str(combobox1.current())) #current: 0
print('get: ' + combobox1.get()) #get: Jan
comb2.config(state='normal')
if combobox1.get() == 'Jan':
comb2.config(values=('J'))
Related
Dears,
I am looking for a PysimpleGUI way to create dropdown menus which includes range of dates ( only years) , instead of writting the whole list in sg.combo () function or instaed of Choosing Sg.CalendarButton, which are both not useful in my case :
I want something like the below :
import PySimpleGui as sg
sg.Combo([range(Date1 To Date2)], size=(6, 1), font=("Helvetica", 10), key='Dates'),)
Thanks in advance
[range(Date1 To Date2)] is a list with only one item which is is a class of immutable iterable objects.
Example Code
import datetime
import PySimpleGUI as sg
def date(year, month=1, day=1):
return datetime.date(year, month=month, day=day)
def get_years(start, stop):
return list(range(start.year, stop.year+1))
start = date(2022)
stop = date(2030)
dates = get_years(start, stop)
layout = [[sg.Combo(dates, font=("Helvetica", 10), size=(5, 5), enable_events=True, key='Dates')]]
window = sg.Window('Title', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
item = values['Dates']
print(item, ":", type(item))
window.close()
2024 : <class 'int'>
i have written a code for that its working and window popped up with two label but values are not incremented::i am quite new to python ,please help me out to resolve ...
thanks in advance..
import Tkinter
import time
root = Tkinter.Tk()
var = Tkinter.IntVar()
var1 = Tkinter.IntVar()
label1 = Tkinter.Label(root, textvariable=var)
label2 = Tkinter.Label(root, textvariable=var1)
root.geometry("200x200")
label1.pack()
label2.pack()
def function():
while 1:
i=0
j=0
i += 1
var.set(i)
#time.sleep(1)
var1.set(j)
j += 1
root.update()
#time.sleep(1)
root.after(10, function)
root.update()
root.mainloop()
Do you want your counters to be automatically incremented as time goes by? If yes, the easiest solution is to reuse the after method at the end of your function():
import Tkinter as tk
def function():
var1.set(var1.get()+1)
var2.set(var2.get()+1)
root.after(100, function)
root = tk.Tk()
root.geometry("200x200")
var1 = tk.IntVar()
var2 = tk.IntVar()
label1 = tk.Label(root, textvariable=var1)
label2 = tk.Label(root, textvariable=var2)
label1.pack()
label2.pack()
root.after(10, function)
root.mainloop()
Is it possible to create a multi label widget like a tabular column ? For, example as shown in the snapshot attached ?
Kindly let me know or provide some comments if there is any option to create widgets with multi label option ?
Thanks !
There is no built-in way to do that, but it's relatively easy to write your own using a canvas. For example, put one label in the upper-right corner and the other in the lower-left. Then, draw a line from upper-left to lower-right.
Example:
import tkinter as tk
class CustomLabel(tk.Frame):
def __init__(self, parent, label1, label2, **kwargs):
tk.Frame.__init__(self, parent, **kwargs)
self.canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0, background=self.cget("background"))
self.canvas.pack(fill="both", expand=True)
l1 = tk.Label(self.canvas, text=label1, background=self.cget("background"))
l2 = tk.Label(self.canvas, text=label2, background=self.cget("background"))
l1.place(relx=.75, rely=.25, anchor="c")
l2.place(relx=.25, rely=.75, anchor="c")
# arrange for the line to be redrawn whenever the canvas
# changes size
self.canvas.bind("<Configure>", self.handle_configure)
# set the default size to be relative to the requested size
# of the labels plus some margin
width = l1.winfo_reqwidth() + l2.winfo_reqwidth() + 4
height = l1.winfo_reqheight() + l2.winfo_reqheight() + 4
self.canvas.configure(width=width, height=height)
def handle_configure(self, event):
self.canvas.delete("line")
self.canvas.create_line(0,0,event.width, event.height, tags=("line",))
Example usage:
root = tk.Tk()
colors = ("SteelBlue4", "SteelBlue3", "SkyBlue1")
for row in range(3):
for column in range(4):
if row == 0 and column == 0:
widget = CustomLabel(root, "Place", "Name", background=colors[row])
else:
widget = tk.Label(root, text="", background=colors[row])
widget.grid(row=row, column=column, sticky="nsew", padx=1, pady=1)
for row in range(3):
root.grid_rowconfigure(row, uniform="row")
for column in range(4):
root.grid_columnconfigure(column, uniform="column")
Screenshot:
I am writing a script to simplify a tedious task when using Vray, but I am stuck with the intFields that are supposed to allow the user to type in a int value that triggers an certain action when hitting the button. I simplified the code to only the necessary parts. No matter what I change the value to, it is always 0 in the Script Editor output.
import maya.cmds as cmds
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (300,500))
cmds.columnLayout(adj = True)
cmds.text (l = 'type in MultimatteID to select matching shaders \n or specify ObjectID to select matching objects \n __________________________________________ \n')
cmds.text (l = 'MultimatteID: \n')
cmds.intField( "MultimatteID", editable = True)
MultimatteIdButton = cmds.button(l = 'Go!', w = 30, h = 50, c = 'multimatteChecker()')
cmds.text (l = '\n')
cmds.showWindow(idManagerUI)
MultimatteIdInput = cmds.intField( "MultimatteID", q = True, v = True)
def multimatteChecker():
print MultimatteIdInput
Three things:
First, as written you can't be sure that the intField MultimatteID is actually getting the name you think it should have. Maya widget names are unique, like maya object names -- you may name it MultimatteID but actually get back a widget named MultimatteID2 because you have an undeleted window somewhere (visible or not) with a similarly named control.
Second, the code you pasted queries the value of the control immediately after the window is created. It should always print out the value you gave it on creation.
Finally -- don't use the string version of command assignment in your button. It's unreliable when you move from code in the listener to working scripts.
This should do what you want:
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (300,500))
cmds.columnLayout(adj = True)
cmds.text (l = 'type in MultimatteID to select matching shaders \n or specify ObjectID to select matching objects \n __________________________________________ \n')
cmds.text (l = 'MultimatteID: \n')
# store the intField name
intfield = cmds.intField( "MultimatteID", editable = True)
cmds.text (l = '\n')
# define the function before assigning it.
# at this point in the code it knows what 'intfield' is....
def multimatteChecker(_):
print cmds.intField( intfield, q = True, v = True)
#assign using the function object directly
MultimatteIdButton = cmds.button(l = 'Go!', w = 30, h = 50, c = multimatteChecker)
Why are these two functions different?
def other_entry1(self, selection, row, el, var):
if selection == "Other":
var = StringVar()
el = Entry(self.frame1, textvariable=var)
el.grid(row=row, column=6)
#Calling it as part of an optionMenu
self.e33 = OptionMenu(self.frame1, self.ea_tf, *fixtures, command= lambda selection:self.other_entry1(selection,15, self.e33, self.ea_tf))
The other one:
def other_entry2(self, selection):
if selection == "Other":
self.ea_tf = StringVar()
self.e33 = Entry(self.frame1, textvariable=self.ea_tf)
self.e33.grid(row=15, column=6)
#Calling it in an optionMenu
self.e33 = OptionMenu(self.frame1, self.ea_tf, *fixtures, command=self.other_entry2)
I would like to be able to call the first function several times and just tell it what entry box to create instead of making several separate functions.
Edit: Isn't the second function just skipping the step of substituting in the arguments?
self.s33 is reference to OptionMenu
Second function overwrite self.e33 by reference to Entry and you can't use self.e33 to get access to OptionMenu.
First function copy reference from self.s33 to el then overwrites el by reference to Entry but you can still use self.s33 to get access to OptionMenu
See simple example using "Visual Execution" on PythonTutor.com:
Use link to open page with example, click "Visual Execution" and then you can use "Forward" button to see step by step how example works
function 1
function 2
You can use first function to create several Entry but you don't need to send self.e33 and self.ea_tf because function will not use it.
You get the same result as
def other_entry1(self, selection, row):
if selection == "Other":
var = StringVar()
Entry(self.frame1, textvariable=var).grid(row=row, column=6)
#Calling it as part of an optionMenu
self.e33 = OptionMenu(self.frame1, self.ea_tf, *fixtures, command=lambda selection:self.other_entry1(selection,15))
problem is with access to Entry or StringVar() to get value from Entry
self.all_vars = {} # dictionary
def other_entry1(self, selection, row):
if selection == "Other":
self.all_vars[row] = StringVar()
Entry(self.frame1, textvariable=self.all_vars[row]).grid(row=row, column=6)
#Calling it as part of an optionMenu
self.e33 = OptionMenu(self.frame1, self.ea_tf, *fixtures, command=lambda selection:self.other_entry1(selection,15))
# another place
row = 15
print "row:", row
print "value in Entry:", self.all_vars[row].get()
EDIT: working example
#!/usr/bin/env python
from Tkinter import *
class App():
def __init__(self, master):
self.master = master
self.all_entries = {} # empty dictionary
self.all_entries_vars = {} # empty dictionary
self.all_optionmenus = {} # empty dictionary
self.all_optionmenus_vars = {} # empty dictionary
fixtures = ["One", "Two", "Tree", "Other"]
# create 5 options menu
for i in range(5):
self.all_optionmenus_vars[i] = StringVar()
self.all_optionmenus_vars[i].set("One")
self.all_optionmenus[i] = OptionMenu(self.master, self.all_optionmenus_vars[i], *fixtures, command=lambda selection, col=i:self.addEntry(selection, col))
self.all_optionmenus[i].grid(row=1, column=i)
Button(master, text="Print OptionMenus Vars", command=self.printOptionMenus).grid(row=2, column=0, columnspan=5)
Button(master, text="Print Entries Vars", command=self.printEntries).grid(row=3, column=0, columnspan=5)
def run(self):
self.master.mainloop()
def addEntry(self, selection, col):
if selection == "Other":
# if Entry was created before
if col in self.all_entries:
# show existing Entry
self.all_entries[col].grid(row=0, column=col)
else:
# create new Entry
self.all_entries_vars[col] = StringVar()
self.all_entries[col] = Entry(self.master, textvariable=self.all_entries_vars[col])
self.all_entries[col].grid(row=0, column=col)
# if Entry was created before
elif col in self.all_entries:
# hide Entry
self.all_entries[col].grid_forget()
def printEntries(self):
print "-"*30
for key in self.all_entries_vars:
print "Entry #%d: %s" % ( key, self.all_entries_vars[key].get() )
def printOptionMenus(self):
print "-"*30
for key in self.all_optionmenus_vars:
print "OptionMenu #%d: %s" % ( key, self.all_optionmenus_vars[key].get() )
#----------------------------------------------------------------------
if __name__ == '__main__':
App(Tk()).run()