I tried creating a widget for loop that would only allow one letter input, but I'm running into an issue where it creates text for every widget. I assume the issue lies with the "len" I used.
from tkinter import *
from pynput.keyboard import Key, Controller
root = Tk()
height = 6
width = 5
delta=0
entries = []
def limitSizeDay(*args):
value = dayValue.get()
if len(value) > 1: dayValue.set(value[:1])
dayValue = StringVar()
dayValue.trace('w', limitSizeDay)
for i in range(height): #Rows
newrow = []
for j in range(width): #Columns
b = Entry(root, text="",width=2,font=('Arial', 40, 'bold'), textvariable=dayValue)
b.grid(row=i, column=j)
newrow.append(b)
entries.append(newrow)
def getword(event):
global b
ass = b.get()
print(ass)
keyboard = Controller()
keyboard.press(Key.tab)
keyboard.release(Key.tab)
root.bind('<Return>', getword)
mainloop()
No. The problem is that you have bound every Entry box to the same textvariable (dayValue). When you change that one variable, all of the boxes respond. I can't tell what you are really trying to achieve with this. If you want each box to have its own variable, then you need to create a LIST of StringVars, probably inside the loop so you get the same size.
As Tim said the cause of your problem is binding the same StringVar to all of the Entry widgets. To make this work, you need to create a StringVar for each Entry in a loop:
for i in range(height): #Rows
newrow = []
for j in range(width): #Columns
dayValue = StringVar()
dayValue.trace('w', limitSizeDay)
b = Entry(root, text="",width=2,font=('Arial', 40, 'bold'), textvariable=dayValue)
b.var = dayValue # Prevent garbage collection (I think)
b.grid(row=i, column=j)
newrow.append(b)
entries.append(newrow)
Then you need to change limitSizeDay to access the variable.
def limitSizeDay(var, *args):
value = root.globalgetvar(var)
if len(value) > 1: root.globalsetvar(var, value[:1])
The globalgetvar and globalsetvar methods allow you to get and set the variable respectively as the usual getvar and setvar don't work in this case.
Related
I want to change a number from a matrix and then display it in the same tk window, but I find it hard to work with variables from an input. The r[][] should be the matrix formed with the user's input. And after all I have to display the matrix with the modification: r[0][1] += 5, in the same tk window.
from tkinter import *
import numpy as np
root = Tk()
def process():
values = [e1.get(),e2.get(),e3.get(),e4.get()]
a = np.zeros((2,2),dtype=np.int64)
for i in range(2):
for j in range(2):
a[i][j] = values[i*2+j]
print(a)
e1 = Entry(root)
e2 = Entry(root)
e3 = Entry(root)
e4 = Entry(root)
e1.grid(row=0,column=0,padx=10,pady=10)
e2.grid(row=0,column=1)
e3.grid(row=1,column=0,padx=10,pady=10)
e4.grid(row=1,column=1)
b = Button(root,text='Process',command=process)
b.grid(row=2,column=0,columnspan=4,sticky=E+W)
root.mainloop()
r=[[e1.get(),e2.get()],[e3.get(),e4.get()]]
r[0][1] += 5
Tkinter GUI programs are event-driven which requires using a different programming paradigm than the one you're probably familiar with which is called imperative programming. In other words, just about everything that happens is done in response to something the user has done, like typing on the keyboard, clicking on a graphical button, moving the mouse, etc.
I think the code below will give you a good idea of how to do what you want in a framework like that. It creates a StringVar for each Entry widget, which has the advantage what's displayed in each Entry will automatically be updated whenever the corresponding StringVar is changed (make that more-or-less automatic).
To determine which StringVar is associated with a given Entry, a separate dictionary is created which maps the internal tkinter variable name to corresponding Python variable. The internal tkinter variable name is obtained by using the universal cget() widget method.
import tkinter as tk
from tkinter.constants import *
ROWS, COLS = 2, 2
def process(entry_widgets, row, col):
var_name = entry_widgets[row][col].cget('textvariable')
var = root.variables[var_name]
try:
value = float(var.get())
except ValueError: # Something invalid (or nothing) was entered.
value = 0
var.set(value+5) # Update value.
root = tk.Tk()
# Create a grid of Entry widgets.
entries = []
root.variables = {} # To track StringVars.
for x in range(COLS):
row = []
for y in range(ROWS):
var = tk.StringVar(master=root) # Create variable.
root.variables[str(var)] = var # Track them by name.
entry = tk.Entry(root, textvariable=var)
entry.grid(row=x, column=y)
row.append(entry)
entries.append(row)
btn = tk.Button(root, text='Process', command=lambda: process(entries, 0, 1))
btn.grid(row=2, column=0, columnspan=COLS, sticky=E+W)
root.mainloop()
Would this be what you're looking for? I deleted a bunch of code that seems to do nothing in context -- you just want to replace the text in the corner box right?
from tkinter import *
def process():
replace(e4)
def replace(entry_loc):
temp = int(entry_loc.get())
temp += 5
entry_loc.delete(0,500)
entry_loc.insert(0, temp)
root = Tk()
var_e1 = StringVar
var_e2 = StringVar
var_e3 = StringVar
var_e4 = StringVar
e1 = Entry(root, textvariable=var_e1)
e2 = Entry(root, textvariable=var_e2)
e3 = Entry(root, textvariable=var_e3)
e4 = Entry(root, textvariable=var_e4)
e1.grid(row=0, column=0, padx=10, pady=10)
e2.grid(row=0, column=1)
e3.grid(row=1, column=0, padx=10, pady=10)
e4.grid(row=1, column=1)
b = Button(root, text='Process', command=process)
b.grid(row=2, column=0, columnspan=4, sticky=E + W)
root.mainloop()
I am trying to create a game level editor. The program reads a binary file, associate the byte to a image and then, with a loop, it shows all the images in canvas (Canvas B). The images are Radiobutton. This part works properly.
Below (Canvas A) I have a set of images that are radiobuttons too. Here I choose the image I want to use by clicking on it. This image will be used to redesign the Canvas B Then I go to the Canvas B, decide which tile I want to change and click on it. And it works: the radiobutton has now the chosen image.
In fact it works every time but only the first time. If I change my mind and want to change a radiobutton already changed nothing happens.
I tried to understand what the problem is by printing the variable of the radiobutton with .get()and I see that it stored the value of the last rabiobutton clicked. I tried to reset this value even with del but it doesn't work.
Here's the code (canvas B)
img_list=[]
n_row = 0
n_col = 0
index = 0
x = IntVar()
for f in os.listdir(path):
img_list.append(ImageTk.PhotoImage(Image.open(os.path.join(path,f))))
n_col +=1
index +=1
if n_col > 21:
n_row +=1
n_col = 1
tile = Radiobutton(A, image=img_list[index-1], indicatoron=0, bd=2, variable = x, value = index, selectcolor="red", command=several)
tile.grid(row=n_row, column = n_col)
And here's Canvas A
def erase():
global val_t_e_x
del val_t_e_x
val_t_e_x=t_e_x.get()
print(val_t_e_x)
img_qui=[]
for f in os.listdir(path):
img_qui.append(ImageTk.PhotoImage(Image.open(os.path.join(path,f))))
def several_editor():
global codice_bb
global val_x
global val_t_e_x
val_t_e_x=t_e_x.get()
print(val_t_e_x)
row_qui=row_list[val_t_e_x-1]
col_qui=col_list[val_t_e_x-1]
tile_editor=Radiobutton(B, image=img_qui[val_x-1], variable = val_t_e_x, value = rev, indicatoron=0, bd=0, selectcolor="blue",
highlightbackground="black", highlightcolor="black", command=erase)
tile_editor.grid(row=row_qui, column=col_qui)
col_b=0
row_b=9
l_editor=[]
row_list=[]
col_list=[]
rev=0
t_e_x = IntVar()
for x, y in zip(line[::2], line[1::2]):
a= ("./gfx/"+(x+y)+".png")
row_b-=1
rev+=1
if row_b<1:
col_b+=1
row_b=8
im = Image.open(a)
ph = ImageTk.PhotoImage(im)
l_editor.append(ph)
tile_editor = Radiobutton(B, image=l_editor[rev-1], variable = t_e_x, value = rev, indicatoron=0, bd=0, selectcolor="blue",
highlightbackground="black", highlightcolor="black", command=several_editor)
tile_editor.grid(row=row_b, column=col_b)
row_list.append(row_b)
col_list.append(col_b)
I suppose that the problem is in the function def several_editor()
tile_editor=Radiobutton(B, image=img_qui[val_x-1], variable = val_t_e_x, value = rev,
indicatoron=0, bd=0, selectcolor="blue", highlightbackground="black",
highlightcolor="black", command=erase)
and that I am not handling the val_t_e_x variable properly.
Hope you can help me.
The reason your function isn't returning is because you don't know what the input is for several_editor(). You need to anonymize it with lambda.
I'm going to provide a simple example of why this is necessary:
import tkinter, os, sys
import tkinter.ttk as ttk
class T():
def __init__(self):
labelstr=["ascii"]
top = tkinter.Tk()
top.geometry('200x50')
top.title('lambda')
for label in labelstr:
self.lab = tkinter.Label(top, text=label, width=len(label)).grid(row=labelstr.index(label)+1, column=0)
self.ent = tkinter.Entry(top, width=10).grid(row=labelstr.index(label)+1, column=1)
but = tkinter.Button(top, text="submit", command=lambda: self.submit(top))
but.grid(row=labelstr.index(label)+1, column=3)
top.mainloop()
def submit(self, frame):
for i in frame.winfo_children():
if i.winfo_class() == "Entry":
i.delete(0, tkinter.END)
i.insert(0, "HelloWorld!")
I can't really test the code where I am at the moment, but this should work.
The above is to provide a functional example of proper use of a lambda function within your code and demonstrate why you'd need it. Try removing the lambda and see that the function runs only once and will no longer run properly. This symptom should look familiar to you as it's exactly as you described it. Add the lambda back and the function runs again each time you hit the button.
I am new to programming in tkinter and am very stuck on using checkbuttons. I have created multiple checkbuttons in one go, all with different text for each one and a different grid position. However I have no idea how to get the value of each button or how to even set it. I want to be able to get the state/value for each button and if it is checked, then another function is called. How do I set and call the value/state of each button? Can this be done in a for loop or do I have to create them individually?
def CheckIfValid(self, window):
Class = self.ClassChosen.get()
Unit = self.UnitChosen.get()
Topic = self.TopicChosen.get()
if Class == '' or Unit == '' or Topic == '':
tm.showinfo("Error", "Please fill in all boxes")
else:
QuestionData = OpenFile()
QuestionsList = []
for x in range (len(QuestionData)):
#if QuestionData[x][2] == Topic:
QuestionsList.append(QuestionData[x][0])
for y in range(len(QuestionsList)):
self.ButtonVal[y] = IntVar()
Checkbutton(window, text = QuestionsList[y], padx = 20, variable = self.ButtonVal[y]).grid(row = 12 + y, column = 2)
ConfirmSelection = Button(window, text = "Set Homework", command = lambda: SetHomeworkClass.ConfirmHomework(self)).grid()
print(variable.get()) #here I would like to be able to get the value of all checkbuttons but don't know how
You use the list of IntVars either called from a command= in the Checkbutton or in the Button. Don't know why you are calling another class's object, SetHomeworkClass.objectConfirmHomework(self). It doesn't look like that will work as you have it programmed, as that is another name space and the list of IntVars is in this name space, but that is another topic for another thread.
try:
import Tkinter as tk # Python2
except ImportError:
import tkinter as tk # Python3
def cb_checked():
# remove text from label
label['text'] = ''
for ctr, int_var in enumerate(cb_intvar):
if int_var.get(): ## IntVar not zero==checked
label['text'] += '%s is checked' % cb_list[ctr] + '\n'
root = tk.Tk()
cb_list = [
'apple',
'orange',
'banana',
'pear',
'apricot'
]
# list of IntVar for each button
cb_intvar = []
for this_row, text in enumerate(cb_list):
cb_intvar.append(tk.IntVar())
tk.Checkbutton(root, text=text, variable=cb_intvar[-1],
command=cb_checked).grid(row=this_row,
column=0, sticky='w')
label = tk.Label(root, width=20)
label.grid(row=20, column=0, sticky='w')
# you can preset check buttons (1=checked, 0=unchecked)
cb_intvar[3].set(1)
# show what is initially checked
cb_checked()
root.mainloop()
I have a list of strings sorted in a tuple like this:
values = ('1.Python','2.Ruby','3.PHP','4.Perl','5.JavaScript')
My simple code is:
from tkinter import *
root = Tk()
values = ('1.Python','2.Ruby','3.PHP','4.Perl','5.JavaScript')
ru = Button(root,
text="Next",
)
ru.grid(column=0,row=0)
lab = Label(root,
text=values[0])
lab.grid(column=1,row=0)
ru2 = Button(root,
text="Previous"
)
ru2.grid(column=2,row=0)
root.mainloop()
I have two tkinter buttons "next" and "previous", the text value of the Label is directly taken from the tuple (text=value[0]), however I would want to know how to show the next string from the tuple when the next button is pressed, and how to change it to the previous values when the "previous" button is pressed. I know it can be done using for-loop but I cannot figure out how to implement that. I am new to python.
Use Button(..., command=callback) to assign function which will change text in label lab["text"] = "new text"
callback means function name without ()
You will have to use global inside function to inform function to assign current += 1 to external variable, not search local one.
import tkinter as tk
# --- functions ---
def set_next():
global current
if current < len(values)-1:
current += 1
lab["text"] = values[current]
def set_prev():
global current
if current > 0:
current -= 1
lab["text"] = values[current]
# --- main ---
values = ('1.Python','2.Ruby','3.PHP','4.Perl','5.JavaScript')
current = 0
root = tk.Tk()
ru = tk.Button(root, text="Next", command=set_next)
ru.grid(column=0, row=0)
lab = tk.Label(root, text=values[current])
lab.grid(column=1, row=0)
ru2 = tk.Button(root, text="Previous", command=set_prev)
ru2.grid(column=2, row=0)
root.mainloop()
BTW: if Next has to show first element after last one
def set_next():
global current
current = (current + 1) % len(values)
lab["text"] = values[current]
def set_prev():
global current
current = (current - 1) % len(values)
lab["text"] = values[current]
I have a list of variable length and want to create a checkbox (with python TKinter) for each entry in the list (each entry corresponds to a machine which should be turned on or off with the checkbox -> change the value in the dictionary).
print enable
{'ID1050': 0, 'ID1106': 0, 'ID1104': 0, 'ID1102': 0}
(example, can be any length)
now the relevant code:
for machine in enable:
l = Checkbutton(self.root, text=machine, variable=enable[machine])
l.pack()
self.root.mainloop()
This code produces 4 checkboxes but they are all either ticked or unticked together and the values in the enable dict don't change. How to solve? (I think the l doesn't work, but how to make this one variable?)
The "variable" passed to each checkbutton must be an instance of Tkinter Variable - as it is, it is just the value "0" that is passed, and this causes the missbehavior.
You can create the Tkinter.Variable instances on he same for loop you create the checkbuttons - just change your code to:
for machine in enable:
enable[machine] = Variable()
l = Checkbutton(self.root, text=machine, variable=enable[machine])
l.pack()
self.root.mainloop()
You can then check the state of each checkbox using its get method as in
enable["ID1050"].get()
Just thought I'd share my example for a list instead of a dictionary:
from Tkinter import *
root = Tk()
users = [['Anne', 'password1', ['friend1', 'friend2', 'friend3']], ['Bea', 'password2', ['friend1', 'friend2', 'friend3']], ['Chris', 'password1', ['friend1', 'friend2', 'friend3']]]
for x in range(len(users)):
l = Checkbutton(root, text=users[x][0], variable=users[x])
print "l = Checkbutton(root, text=" + str(users[x][0]) + ", variable=" + str(users[x])
l.pack(anchor = 'w')
root.mainloop()
Hope it helps
You can use this code.
The exec() command allows you to execute a string variable.
from tkinter import *
root = Tk()
users = ['Anne', 'Bea', 'Chris']
variables=[]
for x in range(len(users)):
var_ejecutar=f"global {users[x]}_double_var"
exec(var_ejecutar)
var_ejecutar=f"{users[x]}_double_var=DoubleVar()"
exec(var_ejecutar)
variables.append(f"{users[x]}_double_var")
var_ejecutar=f"""l = Checkbutton(root, text=\"{str(users[x][0])}\",
variable={users[x]}_double_var,onvalue = 1,offvalue = 0)"""
exec(var_ejecutar)
var_ejecutar="l.pack(anchor = 'w')"
exec(var_ejecutar)
def get_val():
for i in variables:
var_ejecutar=f"print({i}.get())"
exec(var_ejecutar)
btn= Button(root, text="ACTUALIZAR", state=NORMAL, command=get_val,bg="#C2CDD1") #crear boton
btn.pack(anchor = 'w')
root.mainloop()