I have written a piece of code code I want to improve it when I enter the elements ,It only allows me to insert data into first index at first,then it enables the second box to insert data into and so. how do I disable the states of other elements of Array?
import tkinter as tk
root=tk.Tk()
root.title("Looping of entry box")
root.geometry("1200x600")
def ApplytoLabel():
xx=size.get()
for i in range(xx):
element = box_list[i].get() # Get value from corresponding Entry
ArrayLabel=tk.Label(ArrayR,text="Array Element: " + element,font="Arial 12 bold",bg="red",fg="white",bd="5")
ArrayLabel.pack()
box_list = [] # Create list of Entrys
def Boxes():
xx=size.get()
for i in range(xx):
box=tk.Entry(ArrayR,font="Arial 10 bold",bd="5",width="5")
box.pack(side="left")
box_list.append(box) # Append current Entry to list
ApplytoLabel1=tk.Button(ArrayR,text="Submit To Array",command=ApplytoLabel)
ApplytoLabel1.pack()
Array = tk.Frame(root)
Array.pack()
text1=tk.Label(Array,text="Enter the Size of Array:",
font="Arial 10 bold",fg="blue")
text1.grid(row=0,column=0,sticky="w")
size=tk.IntVar()
ArraySize=tk.Entry(Array,textvariable=size)
ArraySize.grid(row=0,column=1,sticky="w")
SizeofArray=tk.Button(Array,text="Submit",command=Boxes)
SizeofArray.grid(row=0,column=2,sticky="w")
ArrayR = tk.Frame(root)
ArrayR.pack()
root.mainloop()
This is one way:
import tkinter as tk
root=tk.Tk()
root.title("Looping of entry box")
root.geometry("1200x600")
def ApplytoLabel():
xx=size.get()
for i in range(xx):
if box_list[i].cget('state') == 'normal':
element = box_list[i].get() # Get value from corresponding Entry
ArrayLabel=tk.Label(ArrayR,text="Array Element: " + element,font="Arial 12 bold",bg="red",fg="white",bd="5")
ArrayLabel.pack()
box_list[i].configure(state='disabled')
try:
box_list[i+1].configure(state='normal')
except IndexError: pass
break
box_list = [] # Create list of Entrys
def Boxes():
xx=size.get()
for i in range(xx):
box=tk.Entry(ArrayR,font="Arial 10 bold",bd="5",width="5",state='disabled' if i else 'normal')
box.pack(side="left")
box_list.append(box) # Append current Entry to list
ApplytoLabel1=tk.Button(ArrayR,text="Submit To Array",command=ApplytoLabel)
ApplytoLabel1.pack()
Array = tk.Frame(root)
Array.pack()
text1=tk.Label(Array,text="Enter the Size of Array:",
font="Arial 10 bold",fg="blue")
text1.grid(row=0,column=0,sticky="w")
size=tk.IntVar()
ArraySize=tk.Entry(Array,textvariable=size)
ArraySize.grid(row=0,column=1,sticky="w")
SizeofArray=tk.Button(Array,text="Submit",command=Boxes)
SizeofArray.grid(row=0,column=2,sticky="w")
ArrayR = tk.Frame(root)
ArrayR.pack()
root.mainloop()
In general though, you would probably want each button to have it's on lambda callback with ApplytoLabel receiving a single parameter so you do not have to loop (and break) every time. I would also wrap everything in a class.
Related
I made a tool to add multiple order numbers in our system. The first time a row of entry cells is placed the focus is where it should be. But the second time the focus is not in the new left cell. First I thought it has to do with using the tab key. But if I understand the code correct, I first execute the moving of the tab key and then execute the code. So the command to focus on the new left cell is last.
Where am I going wrong?
import tkinter as tk
from tkinter import ttk
# Create variables for later use
order_list = []
date_list = []
row_number = 0
active_order_entry = None
active_date_entry = None
def add_a_row_of_entry_cells():
global row_number
global active_order_entry
global active_date_entry
row_number += 1
order_entry = ttk.Entry()
order_entry.grid(row=row_number, column=0)
order_entry.focus()
date_entry = ttk.Entry()
date_entry.grid(row=row_number, column=1)
# Make these entries the active ones
active_order_entry = order_entry
active_date_entry = date_entry
# Add entries to a list
order_list.append(order_entry)
date_list.append(date_entry)
def tab_pressed(event):
if active_order_entry.get() != "" and active_date_entry.get() != "":
add_a_row_of_entry_cells()
else:
print("Order, date or both are not filled yet")
def button_pressed():
print("Button pressed")
# Create window
window = tk.Tk()
# Add function to the Tab key
window.bind("<Tab>", tab_pressed)
# Labels on top of the columns
label_order_number = tk.Label(window, text="Order", fg="#22368C")
label_order_number.grid(row=row_number, column=0)
label_date = tk.Label(window, text="Date", fg="#22368C")
label_date.grid(row=row_number, column=1)
# Create empty row
empty_row = tk.Label(window)
empty_row.grid(row=87, column=0)
# Create button
button = tk.Button(window, text="Add orders", command=lambda: button_pressed())
button.grid(row=98, column=0, columnspan=3)
# Create empty row
empty_row = tk.Label(window)
empty_row.grid(row=99, column=0)
# Add the first row
add_a_row_of_entry_cells()
window.mainloop()
My code:
import tkinter as tk
from tkinter import ttk
win = tk.Tk()
def assign():
value = number.get()
if value == 'op1':
label = tk.Label(win, text = number)
label.grid(column = 1, row = 0)
number = tk.StringVar()
box = ttk.Combobox(win, textvariable = number, state = 'readonly')
box['values'] = ('op1','op2','op3')
box.set('op2')
box.grid(column = 0, row = 0)
box.bind('<<ComboboxSelected>>', assign())
win.mainloop()
Explanation: this is how I think my program works.
box, which is the Combobox, has assigned a textvariable named number that, I suppose, takes the values of box, that is, ('op1', 'op2', 'op3'). box is then binded to a subprogram called assign() which will retrieve the value of number and set it equal to value. If value is equal to 'op1', the subprogram will create and grid a label called label that will display the text 'Hello'. Unfortunately, this doesn't work. In other words, my objective is to, when the user selects one of the values given in box['values'], assign() runs and, If the codition is met, display label.
Output:
As you can see, even though I selected 'op1', label isn't displayed next to box.
You will have to remove the () while using bind to avoid function call, then create a label outside functions and then update it from the inside using config, like:
label = tk.Label(win)
def assign(event):
value = number.get() # Get the value
if value == 'op1':
label.config(text=number) # Update the text
label.grid(column = 1, row = 0)
box.bind('<<ComboboxSelected>>', assign) # Remove the ()
This way you don't rewrite the labels and just update the labels with new values.
But I think there is no use of StringVar here, just remove it and use box.get() to get the value from the combobox. So according to me the best practice would be:
import tkinter as tk
from tkinter import ttk
win = tk.Tk()
label = tk.Label(win) # Create this outside of function
def assign(event):
value = box.get() # Get value from combobox
if value == vals[0]: # Check the selected item with the values tuple
label.config(text=value) # Update the text of label
label.grid(column=1,row=0)
vals = ('op1','op2','op3') # Tuple of values
box = ttk.Combobox(win,values=vals,state='readonly') # Add value option
box.current(1) # Set the second item as current value
box.grid(column=0,row=0)
box.bind('<<ComboboxSelected>>', assign)
win.mainloop()
import tkinter as tk
from tkinter import ttk
win = tk.Tk()
label = tk.Label(win) # Create this outside of function
def assign(event):
value = box.get() # Get value from combobox
if value == vals[0]: # Check the selected item with the values tuple
label.config(text=value) # Update the text of label
label.grid(column=1, row=0)
elif value == vals[1]: # Check the selected item with the values tuple
label.config(text=value) # Update the text of label
label.grid(column=1, row=0)
elif value == vals[2]: # Check the selected item with the values tuple
label.config(text=value) # Update the text of label
label.grid(column=1, row=0)
vals = ('op1', 'op2', 'op3') # Tuple of values
box = ttk.Combobox(win, values=vals, state='readonly') # Add value option
box.current(1) # Set the second item as current value
box.grid(column=0, row=0)
box.bind('<<ComboboxSelected>>', assign)
win.mainloop()
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]
This question already has answers here:
How to pass arguments to a Button command in Tkinter?
(18 answers)
tkinter creating buttons in for loop passing command arguments
(3 answers)
Closed 6 months ago.
I need to create table of buttons using Tkinter in Python 2.7, which has n rows and n columns, and has no button in bottom right corner.
Problem is that when I press a button, in its place, I need to create free space and move that button to space that was empty before, and I cannot do that because I don't know how to get grid (x and y axes) information of pressed button to use it to create free space.
This is my current code:
from Tkinter import *
#Input:
n=int(raw_input("Input whole positive number: "))
L = range(1,n+1)
k = n
m = n
#Program:
root = Tk()
for i in L:
for j in L:
frame = Frame(root)
frame.grid(row = i, column = j)
if j == k and i == m:
pass
else:
button = Button(frame)
button.grid(row = i, column = j)
root.mainloop()
It would be something like this, where I wanted to get button grid position, and use it to change k and m variables to make empty space in position where pressed button was.
You can pass the row and column by using a lambda expression for the button:
button = Button(..., command=lambda row=i, column=j: doSomething(row, column))
Could you do something like create the grid of buttons up front, but include a hidden button in the blank space? Then when the button is clicked hide the clicked one and display the hidden one. Then you don't have to worry about moving buttons around, unless you need the actual button object to move for some reason.
Edit to enhance answer from comments:
Below is a simple example of hiding a button and it shows how to track the buttons as well, unless I screwed up moving it to the editor. This can be translated to a list or dictionary of buttons or whatever need be. You'd also need to determine find a way to register the local buttons or add some context to know which one to show or hide.
from Tkinter import Button, Frame, Tk
class myButton(Button):
def __init__(self, *args, **kwargs):
Button.__init__(self, *args, command=self.hideShowButton,
** kwargs)
self.visible = True
def hideShowButton(self):
self.visible = False
self.pack_forget()
window = Tk()
frame = Frame(window)
frame.pack()
b1 = myButton(window, text="b1")
b1.pack()
b2 = myButton(window, text="b2")
b2.pack()
b3 = myButton(window, text="b3")
b3.pack()
window.wait_window(window)
print "At the end of the run b1 was %s, b2 was %s, b3 was %s" % (str(b1.visible), str(b2.visible), str(b3.visible))
This is the way I tried to do this and problem is that I still don't know how to get row and column of pressed button...
from Tkinter import *
#Input:
n = int(raw_input("Input whole positive number: "))
L = range(1,n+1)
k = n
m = n
#Try putting values for k and m which are less then n and you will see what i need to get
#Moving:
def Move():
#This i cant fill
return k,m
#Program:
root = Tk()
for i in L:
for j in L:
frame = Frame(root)
frame.grid(row = i,column = j)
if i == int(k) and j == int(m):
pass
else:
button = Button(frame, command = lambda: Move())
button.pack()
root.mainloop()
So by changing k and m values gap is created on other place...