In my code I have a spin box that the user uses to select the number of teams they want, then in a separate frame columns are created to match the number of teams they chose, and when they use the spin box to change this value it also changes the number of columns
frame=Frame(root)
frame.pack(anchor=CENTER)
Label(frame,text='Team selection').grid(row=0,column=0,columnspan=5)
NumTeams=StringVar()
Spinbox(frame,values=(1,2,3,4,5),textvariable=NumTeams).grid(row=2,column=0,columnspan=5)
frame2=Frame(root)
frame2.pack()
for i in range(int(NumTeams.get())):
Label(frame2,text=str(i)).grid(row=0,column=i)
frame2.update()
The above code is an attempt at achieving this, does anyone know a way that this can be done?
You can use the command argument to specify a method to be run whenever your spinbox changes values. I'm not entirely sure what type of columns you mean, but hopefully you can work with this.
from Tkinter import *
def on_spin():
num_teams.set("New text")
root = Tk()
frame = Frame(root)
frame.pack(anchor=CENTER)
frame2 = Frame(root)
frame2.pack()
num_teams = StringVar()
label = Label(frame2, textvariable=num_teams)
label.pack()
spin = Spinbox(frame, from_=1, to=5, command=on_spin)
spin.pack()
root.mainloop()
Related
I'm trying to make a table with Entry widgets in Tkinter, so I made a list with them. The problem is that I need to know in which box did the user press Enter to perform certain actions, for example if someone erases the content of the first cell of a row and press Enter, I want to erase the content of all the other cells in that row, or if someone writes the product code in the first cell of that row, the product description should appear on the cell in front.
I've tried with the methodology suggested here: Tkinter binding a function with arguments to a widget by unutbu but it doesn't seem to be working with my list of entry widgets.
Here is what I've tried:
from tkinter import *
root = Tk()
root.configure(background='gray')
item_list_fr = Frame(root, bg='gray', width=450, height=108, padx=3, pady=3)
item_list_fr.grid(row=2, column=0, rowspan=2)
info_tupple=[]
def show(eff=None, row_2=0, column_2=0):
print(str(row_2), str(column_2))
for row in range(15):
info_list=[None]*5
for column in range(5):
info_list[column]=Entry(item_list_fr)
info_list[column].bind('<Return>', lambda eff: show(eff, row_2=row, column_2=column))
info_list[column].grid(row=row+1, column=column)
info_tupple.append(info_list)
root.mainloop()
How can I rewrite my code to make it work?
You can use functools.partial like this:
from tkinter import *
import functools
root = Tk()
root.configure(background='gray')
item_list_fr = Frame(root, bg='gray', width=450, height=108, padx=3, pady=3)
item_list_fr.grid(row=2, column=0, rowspan=2)
info_tupple=[]
def show(eff=None, row_2=0, column_2=0, event=None):
print(str(row_2), str(column_2))
for row in range(15):
info_list=[None]*5
for column in range(5):
info_list[column]=Entry(item_list_fr)
command = functools.partial(show, row_2=row, column_2=column)
info_list[column].bind('<Return>', command)
info_list[column].grid(row=row+1, column=column)
info_tupple.append(info_list)
root.mainloop()
For more answers look here.
I have categories saved in a database on table Geo_Cat. I know my geo_list is getting populated correctly, because I was able to make an OptionMenu earlier. I also printed the list and it worked. So the query is good. However, I need to be able to select more than one option at a time and need to use a MenuButton instead. The options that I need are none and the categories in the table. I've been able to add the "None" checkbutton, but I haven't been able to add the geo_list. Below is a code excerpt:
from Tkinter import *
root = Tk()
location_frame = Frame(root)
location_frame.grid(column=0, row=0, sticky=(N, W, E, S))
location_frame.columnconfigure(0, weight=1)
location_frame.rowconfigure(0, weight=1)
location_frame.pack(pady=25, padx=50)
geo_list= ["geo1","geo2","geo3","geo4"]
amb = Menubutton(location_frame,text="Geo Category", relief=RAISED)
amb.grid(sticky="ew", row=1,column=0)
amb.menu = Menu(amb,tearoff=0)
amb['menu'] = amb.menu
Item0 = IntVar()
amb.menu.add_checkbutton(label="None", variable=Item0)
location_vars = {}
for category in geo_list:
location_vars["Item{0}".format(category)] = IntVar()
amb.menu.add_checkbutton(label=geo_list[category])
amb.pack()
root.mainloop()
I also tried this:
location_vars["Item{0}".format(category)] = IntVar()
amb.menu.add_checkbutton(label=geo_list[category],
variable=location_vars["Item{0}".format(category)])
How can I add my geo_list to the checkbuttons? Any advice would be greatly appreciated.
If you want the items in the geo_list for menu labels, why not just set them; you are already looping over them:
amb.menu.add_checkbutton(label=category)
Also, don't pack amb at the very end; you have already gridded it earlier.
I'm adding an example of how to trace changes associated with each menu item. I have changed the code slightly but I think you will have no problem to get the general idea.
I'm using a BooleanVar() instead of an IntVar(), then each var is saved in location_vars with the key "Item{0}".format(category). Finally I'm setting up a trace for changes in each menu item to to a callback function which will inspect the selections.
Is this what you are after?
from tkinter import *
root = Tk()
amb = Menubutton(root, text="Geo Category", relief=RAISED)
amb.pack(padx=50, pady=25)
amb.menu = Menu(amb, tearoff=0)
amb['menu'] = amb.menu
def callback(*args):
# Callvack function is called when menu items are changed
for key, value in location_vars.items():
print(key, value.get())
print() # To make the printout more readable
geo_list= ["None","geo1","geo2","geo3","geo4"]
location_vars = {}
for category in geo_list:
location_vars["Item{0}".format(category)] = BooleanVar()
# Set "variable" for every menu item
amb.menu.add_checkbutton(label=category,
variable=location_vars["Item{0}".format(category)])
# Trace changes in the variables
location_vars["Item{0}".format(category)].trace("w", callback)
root.mainloop()
Python 3.4.0.
Could you help me understand what is going on here:
from tkinter import *
root = Tk()
f = Frame(root, borderwidth=2) #
for relief in [RAISED, SUNKEN, FLAT, RIDGE, GROOVE, SOLID]:
Label(f, text=relief, width=10, relief = relief).pack(side=LEFT) #
#f = Frame(root, borderwidth=2, relief = relief)
#Label(f, text=relief, width=10).pack(side=LEFT)
f.pack(side=LEFT, padx=5, pady=5)
root.mainloop()
If I uncomment now commented lines and comment the lines that hafe '#' mark at the end, the result is the same.
First case: the present situation. It is understandable to me. Before the loop we create a frame. Then pack method places each label in the parent widget (which is f). In this case f expands and contains several labels.
Well, the second case: if I switch the comment marks.
A frame f is always new. Label is also always new. A label is always placed on a separate frame. I would suggest that 5 frames would be displayed with a different label in each frame.
Could you help me understand why the result is the same?
Sounds like you want five separate windows, each of which can be moved, closed, etc.
If so, you should use the Toplevel widget instead of Frame.
from tkinter import *
root = Tk()
for relief in [RAISED, SUNKEN, FLAT, RIDGE, GROOVE, SOLID]:
t = Toplevel(root, borderwidth=2, relief = relief)
Label(t, text=relief, width=10).pack(side=LEFT)
root.mainloop()
I have written the following code:
from Tkinter import *
root = Tk()
root.title("Power Method")
labeltext1 = StringVar()
labeltext2 = StringVar()
labeltext1.set('Parameters') # Set start value
labeltext2.set('Epsilon')
label1 = Label (root, textvariable = labeltext1, height = 4)
label1.pack()
Entry(root, textvariable = labeltext1). pack()
label2 = Label (root, textvariable = labeltext2)
label2.pack()
Entry(root, textvariable = labeltext2). pack()
checkBox1 = Checkbutton(root, text = "NumPy")
checkBox1.pack()
checkBox2 = Checkbutton(root, text = "Not NumPy")
checkBox2.pack()
Button(root, text = "Exit").pack(side = RIGHT)
Button(root, text = "Compute").pack(side = RIGHT)
root.mainloop()
This code, when run, creates a window that contains Parameters, Epsilon as two places that you could enter value and NumPy and Not NumPy as checkboxes and finally a compute and exit button.
I am trying to format the code, in a way that Parameters and Epsilon appear on the left of the window, Numpy and Not Numpy infront of them on the right and Compute and Exit stay in their current positions.
Any help regarding the formatting would be appreciated.
Alright you need to google .grid() and .pack() and .place() for tkinter to learn more about what each is good for. For your case you could use any of them, but .grid() is probably the best and easiest for you to use.
To do this you must change .pack() to .grid() everywhere you have it, then you should use the row and column options to put your widgets where you want them. E.G.
label1.grid(row = 1, column = 1)
label2.grid(row = 1, column = 2)
this will put label2 on the right side of label1. The way .grid() works is that the columns are as wide as the largest (widest) widget in that column, same applies for rows.
if you need anything else just ask, but please do look at the documentations as Bryan said.
I am using a tkinter Scale widget and I have two scales next to each other. I want the numbers on one of them to go to the other side.
This is the code I am using:
#IMPORTS
from tkinter import *
import time
#USER INPUT
user = input("Please Enter Your Username")
time.sleep(0.4)
pass_ = imput("Please Enter Your Password")
time.sleep(0.6)
#DEFINITIONS
#STUFF
master = Tk()
#LEFT
left = Scale(master,from_=0,to=249,length=550,width=25,tickinterval=152,sliderlength=30)
left.pack()
left.set(152)
left.grid(row=0, column=3)
#RIGHT
right = Scale(master,from_=0,to=249,length=550,width=25,tickinterval=152,sliderlength=30)
right.pack()
right.set(152)
right.grid(row=0, column=6)
#BUTTONS
send = Button(master,text="Send To Bot",command=send)
send.pack()
send.grid(row=15, column=4)
#RUN CANVAS
mainloop()
I want the right scale to have the numbers on the right side and the left scale to have the numbers on the left side (set by default).
(By the way this coding isn't finished which is why the definitions aren't done.)
I don't think there's a way to specify to the widget which side the number appears on. However, you can customize the widget's showvalue attribute to turn off the default label, and assign an IntVar() to the scale's variable attribute to monitor the value of the slider externally, and update a Label widget that you can place anywhere as the value of the slider changes:
master = Tk()
leftValue = IntVar() # IntVars to hold
rightValue = IntVar() # values of scales
leftScale = Scale(master, from_=0, to=249, variable=leftValue, showvalue=0)
leftScale.set(152)
rightScale = Scale(master, from_=0, to=249, variable=rightValue, showvalue=0)
rightScale.set(152)
leftLabel = Label(master, textvariable=leftValue) # labels that will update
rightLabel = Label(master, textvariable=rightValue) # with IntVars as slider moves
leftLabel.grid(row=0, column=0)
leftScale.grid(row=0, column=1)
rightLabel.grid(row=0, column=3)
rightScale.grid(row=0, column=2)
mainloop()
Of course, the labels won't move as the slider changes, but if you really need that functionality, you could look into creating a subclass of Frame, and finding a way to change the geometry of the Label as the slider's value changes.
Edit: Just as a note, you shouldn't mix pack and grid in your code. All of those widgets should be handled by just one geometry manager.