I have created a pop up that would ask for entry, and the amount of entries would depend on the information given.
self.e = Entry(self.top, bd = 5)
self.e.grid(column = 1, row = 0)
row = 2
for d in extra:
self.e2 = Entry(self.top, bd = 5)
self.e2.grid(column = 1, row = row)
row = row + 1
def ok(self):
new = self.e.get().strip()
Function ok would be called by a button and then it would return the values. How do I return a list of values from an unknown amount of entries?
Python 2.7
Normally, you would put the entries in a list:
from Tkinter import *
class App(object):
def __init__(self, top):
self.top = top
self.ok_button = Button(self.top, text='OK', command=self.ok)
self.make_entries()
def make_entries(self):
self.entries = []
for d in extra:
e2 = Entry(self.top, bd = 5)
e2.grid(column = 1, row = row)
self.entries.append(e2)
row += 1
def ok(self):
values = [e.get().strip() for e in self.entries]
root = Tk()
app = App(root)
root.mainloop()
Related
I did a tkinter window where an user has to select some items in a listbox which displays two radiobuttons. If the user selects one radiobutton and then deselects the item in the listbox, radiobuttons are deleted. The problem is that if user selects the same item as previously, the radiobutton is already selected. I would like they are empty when they are created again.
Thanks in advance
from tkinter import *
import tkinter as tk
class Application(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.dictLabel = dict()
self.createWidgets()
def createWidgets(self):
self.ListNumber = ['one', 'two', 'three', 'four']
self.labelListNumber = tk.Label(self, text=' Select a Number : ')
self.labelListNumber.place(x=40, y=30)
self.frame = Frame(self)
self.frame.place(x=200, y=30)
self.list = Listbox(self.frame, exportselection=False,activestyle = tk.NONE, height=5, selectmode="multiple")
self.list.pack(side='left', fill='y')
for each_item in range(len(self.ListNumber)):
self.list.insert(END, self.ListNumber[each_item])
self.scrollbar = Scrollbar(self.frame, orient="vertical", command=self.list.yview)
self.scrollbar.pack(side='right', fill='y')
self.list.config(yscrollcommand=self.scrollbar.set)
self.dictRadioButtonValue = dict()
self.list.bind('<<ListboxSelect>>',self.createRadioButton)
def createRadioButton(self, evt):
index = self.list.curselection() # grab the index
c = 1
if len(index) == 0 or len(self.dictLabel) != 0:
for e in self.dictLabel:
self.dictLabel[e][0].place_forget()
self.dictLabel[e][1].place_forget()
self.dictLabel[e][2].place_forget()
del self.dictLabel
self.dictLabel = dict()
for i in index:
item = self.list.get(i)
if not item in self.dictRadioButtonValue:
if len(self.dictRadioButtonValue) > len(index):
if not item in self.dictLabel[item]:
del self.dictRadioButtonValue[item]
else :
radioButtonValue = tk.IntVar()
radioButtonValue.set(' ')
self.dictRadioButtonValue[item] = radioButtonValue
L = tk.Label(self, text=f"Number selected is {item}")
radiobtn5 = tk.Radiobutton(self, text="Yes", variable = self.dictRadioButtonValue[item], value = 5)
radiobtn7 = tk.Radiobutton(self, text="No", variable = self.dictRadioButtonValue[item], value = 6)
L.place(x=350, y=10+(c * 20))
radiobtn5.place(x=500, y=10 + (c * 20))
radiobtn7.place(x=550, y=10 + (c * 20))
self.dictLabel[item] = L, radiobtn5, radiobtn7
c = c+1
if __name__ == "__main__":
app = Application()
app.geometry("700x250")
app.mainloop()
It is because the deselected item is not removed from self.dictRadioButtonValue.
Create a copy of self.dictRadioButtonValue and then remove the items that are used from the copy. At the end, remove remaining items in copy from self.dictRadioButtonValue:
def createRadioButton(self, evt):
index = self.list.curselection() # grab the index
c = 1
if len(index) == 0 or len(self.dictLabel) != 0:
for e in self.dictLabel:
self.dictLabel[e][0].place_forget()
self.dictLabel[e][1].place_forget()
self.dictLabel[e][2].place_forget()
del self.dictLabel
self.dictLabel = dict()
copy = self.dictRadioButtonValue.copy()
for i in index:
item = self.list.get(i)
if not item in self.dictRadioButtonValue:
# new item selected
radioButtonValue = tk.IntVar(value=' ')
self.dictRadioButtonValue[item] = radioButtonValue
else:
# remove current item from copy
del copy[item]
L = tk.Label(self, text=f"Number selected is {item}")
radiobtn5 = tk.Radiobutton(self, text="Yes", variable = self.dictRadioButtonValue[item], value = 5)
radiobtn7 = tk.Radiobutton(self, text="No", variable = self.dictRadioButtonValue[item], value = 6)
L.place(x=350, y=10+(c * 20))
radiobtn5.place(x=500, y=10 + (c * 20))
radiobtn7.place(x=550, y=10 + (c * 20))
self.dictLabel[item] = L, radiobtn5, radiobtn7
c = c+1
# remove remaining items in copy from self.dictRadioButtonValue
for item in copy:
del self.dictRadioButtonValue[item]
First off, this is kind of a hard to explain problem, but I will take a crack at it.
I have created an array with some 'items' in it and have put those items from that array (using a for loop so that no matter how many items may be in the array it still works) into a listbox where you can select one of the items to delete. However because I used a for loop, the items in the listbox don't have a number I can associate with them and so i can't delete the one item that I want.
Below is the code I am using at the moment:
from tkinter import *
import tkinter.messagebox as box
global num
num = 1
inventorylist = ["Item1","Item2","Item3","Item4"]
def remove():
global i
del inventorylist[i]
situation_I()
def situation_IR():
global num
if num == 1:
windowi.destroy()
num = 2
global windowir
windowir = Tk()
windowir.title( "IR" )
listframe = Frame( windowir )
listbox = Listbox( listframe )
global i
for i in range(len(inventorylist)):
e = i+1
listbox.insert(e, inventorylist[i])
btn_ir_1 = Button( listframe, text = "Remove", command = remove )
btn_ir_1.pack(side = RIGHT, padx = 5)
listbox.pack(side = LEFT)
listframe.pack(padx = 30, pady = 30)
windowir.mainloop
def situation_I():
global num
if num == 2:
windowir.destroy()
num = 1
global windowi
windowi = Tk()
windowi.title( "I" )
Btn_i = Button( windowi, text = "Remove item", command = situation_IR )
Btn_i.grid( row = 61, column = 76, columnspan = 50 )
Label_i = Label( windowi, relief = "groove", width = 50 )
Label_i.grid( row = 1, column = 76, rowspan = 50, columnspan = 100, padx = ( 10, 10 ) )
all_lines = []
for i in range(0, len(inventorylist), 3):
line = ", ".join(inventorylist[i:i+3])
all_lines.append(line)
words = ",\n".join(all_lines)
Label_i.configure( text = words )
windowi.mainloop()
situation_I()
At the moment it just deletes the last item in the array no matter what.
This should work, use curselection() to find the index of the selected item, the code is given below and I hope that it solves your problem.
import tkinter as tk
class Root(tk.Tk):
list = ['Item1', 'Item2', 'Item3', 'Item4']
def __init__(self):
super().__init__()
box = tk.Listbox(self)
btn = tk.Button(self, text = 'Remove', command = lambda: self.rmv(box))
for item in Root.list: box.insert(tk.END, item)
box.pack(side = 'top')
btn.pack(side = 'bottom')
def rmv(self, *args):
box, = args
try:
ind = box.curselection()[0]
del Root.list[ind] #To delete values in the list too.
box.delete(ind)
except:
pass
if __name__ == '__main__':
Root().mainloop()
I tried to incorporate this piece into my script and add the calculation into column 7, however, it appears to be failing to return correct multiple of inputs, any idea why? Here is the code:
def autofill(self, event):
row = int(event.widget.grid_info()['row'])
auto_list = self.in_list(self.LookUpList, self._entry[row, 0].get())
if auto_list is not None:
self._entry[row,1].delete(0, 'end')
self._entry[row,1].insert(0, auto_list[1])
self._entry[row,2].delete(0, 'end')
self._entry[row,2].insert(0, auto_list[2])
self._entry[row,4].delete(0, 'end')
self._entry[row,4].insert(0, auto_list[3])
self._entry[row,6].delete(0,'end')
if self._entry[row,3].get() != '':
a = self._entry[row,3].get()
else: a = 0
b = int(self._entry[row,4].get())
c = int(a * b)
self._entry[row,6].insert(0, c)
I have just found the error, had to convert one variable into int, then it worked:
self._entry[row,6].delete(0,'end')
if self._entry[row,3].get() != '':
a = int(self._entry[row,3].get())
else: a = 0
b = int(self._entry[row,4].get())
c = int(a * b)
self._entry[row,6].insert(0, c)
Here is a fix that does what you're asking for. The main thing to note is that, I added an autofill method, and a binding to the Return key that calls the autofill method. You need to hit the Return/Enter key after typing for the cells to be populated, you can change this to any other event that you prefer.
There are few other changes just to make the code work in its current state. I did not make any change regarding how efficient/elegant your implementation is, I leave that to you.
from tkinter import *
class SimpleTableInput(Frame):
def __init__(self, parent, rows, columns):
Frame.__init__(self, parent)
self._entry = {}
self.rows = rows
self.columns = columns
# register a command to use for validation
vcmd = (self.register(self._validate), "%P")
# create the table of widgets
for row in range(self.rows):
for column in range(self.columns):
index = (row, column)
if column == 3:
e = Entry(self, validate="key", validatecommand=vcmd)
else:
e = Entry(self)
e.grid(row=row, column=column, stick="nsew")
self._entry[index] = e
# adjust column weights so they all expand equally
for column in range(self.columns):
self.grid_columnconfigure(column, weight=1)
## Lookup table:
self.LookUpList=[
['a','Black skirt','PP','2000'],
['b','Pink T-shirt','PP','1000'],
['c','Yellow skirt','Marela','1500'],
['d','White trousers','PP','2000']]
## Bind the Return/Enter key to populate the entries
for row in range(self.rows):
self._entry[row, 0].bind("<Return>", self.autofill)
def in_list(self, list_of_lists, item):
if not list_of_lists:
return None
if item in list_of_lists[0]:
return list_of_lists[0]
return self.in_list(list_of_lists[1:], item)
## The method that will be called to populate the entries
def autofill(self, event):
row = int(event.widget.grid_info()['row'])
auto_list = self.in_list(self.LookUpList, self._entry[row, 0].get())
self._entry[row,1].delete(0, 'end')
self._entry[row,1].insert(0, auto_list[1])
def get(self):
'''Return a list of lists, containing the data in the table'''
result = []
for row in range(self.rows):
current_row = []
for column in range(self.columns):
index = (row, column)
current_row.append(self._entry[index].get())
result.append(current_row)
return result
def _validate(self, P):
if P.strip() == "":
return True
try:
f = float(P)
except ValueError:
self.bell()
return False
return True
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
names = ["Cislo produktu",
"Popis produktu",
"Znacka",
"Mnozstvi",
"Jednotkova cena",
"Prodejna",
"Celkova cena"]
frame = Frame(self)
frame.pack(side="top", fill="both")
for i, title in enumerate(names):
l = Label(frame, text=title)
l.grid(row=0, column=i)
frame.grid_columnconfigure(i, weight=1)
self.EmptySpace = Label(self)
self.table = SimpleTableInput(self, 30, 7)
self.table.pack(side="top", fill="both")
self.EmptySpace.pack(side="top",fill="both")
## frame1 = Frame(self)
## frame1.pack(side="left",fill="both")
## self.SubButton = Button(self, text="Ulozit a zavrit", command=self.on_ulozit)
## self.StornoButton = Button(self, text="Stornovat nakup", command=self.on_storno)
## self.SubButton.pack(side="left", fill="both", expand=True)
## self.StornoButton.pack(side="left", fill="both", expand=True)
def on_ulozit(self):
data = self.table.get()
data1 = [list(filter(None, lst)) for lst in data]
data2 = list(filter(None, data1))
for item in data2:
item.append(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
## look up property
with open('C:\\Users\\chroustovskyj\\Desktop\\Dev_py\\App\\Data_Storage\\Data_Storage.csv', 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerows(data2)
root.destroy()
def on_storno(self):
print("This is storno.")
if __name__ == '__main__':
root = Tk()
root.wm_title("Formular")
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))
Example(root).pack(side="top", fill="both", expand=False)
root.mainloop()
I want to make a grid of entry boxes that I can edit and save to a text file somewhere else, but every time I run my code, If I call the variable "e", I can only edit the last box that was made.
from Tkinter import *
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
self.TXTlist = open('txtlist.txt', 'r+')
self.row = self.TXTlist.readline()
self.row = self.row.rstrip('\n')
self.row = self.row.replace('characters = ', "") #should end up being "6"
self.columns = self.TXTlist.readline()
self.columns = self.columns.rstrip('\n')
self.columns = self.columns.replace('columns = ', "") #should end up being "9"
i = 0
x = 0
for i in range (int(self.row)):
for x in range (int(self.columns)):
sroot = str('row' + str(i) + 'column' + str(x))
e = Entry(self, width=15)
e.grid(row = i, column = x, padx = 5, pady = 5, sticky = W)
e.delete(0, END)
e.insert(0, (sroot))
x = x + 1
x = 0
i = i + 1
root = Tk()
root.title("Longevity")
root.geometry("450x250")
app = Application(root)
root.mainloop()
I would store the entries in some sort of data structure to have easy access to them later. a list of lists would work nicely for this:
self.entries = []
for i in range (int(self.row)):
self.entries.append([])
for x in range (int(self.columns)):
...
e = Entry(self, width=15)
self.entries[-1].append(e)
...
Now you have a reference to the entry box:
self.entries[row_idx][col_idx]
And you can modify it however you want.
I'm a full time student, taking my first class in python.
This is so strange, it was working, and now, it is no longer showing the buttons, labels, and entry fields. I'm sure it was something I removed or added, but, I'm at a loss.
Any ideas? All suggestions are appreciated.
from Tkinter import *
import tkFont
import tkMessageBox
class BouncyGUI(Frame):
"""The GUI used to interface with the bouncy calculation from chapter 9 section 1."""
def __init__(self):
Frame.__init__(self)
# Establish the Base Frame
self.master.title("Calculate the Bounciness of a Ball")
self.master.rowconfigure(0, weight = 1)
self.master.columnconfigure(0, weight = 1)
self.master.grid()
self.master.resizable(0,0)
# Establish the components for capturing the Height
self._heightLabel = Label(self,
text = "Height of initial drop:",
justify = "left")
self._heightLabel.grid(row = 0, column = 0)
self._heightVar = DoubleVar()
self._heightEntry = Entry(self,
textvariable = self._heightVar,
justify = "center")
self._heightEntry.grid(row = 0, column = 1)
# Establish the "bounciness index"
self._bouncyIndex = Label(self,
text = "Bounciness Index:",
justify = "left")
self._bouncyIndex.grid(row = 1, column = 0)
self._bouncyVar = DoubleVar()
self._bouncyEntry = Entry(self,
textvariable = self._bouncyVar,
justify = "center")
self._bouncyEntry.grid(row = 1, column = 1)
self._bouncyVar.set(0.6)
# Establish number of allowable bounces
self._numberBounces = Label(self,
text = "Number of Bounces:",
justify = "left")
self._numberBounces.grid(row = 2, column = 0)
self._numberBouncesVar = IntVar()
self._numberBouncesEntry = Entry(self,
textvariable = self._numberBouncesVar,
justify = "center")
self._numberBouncesEntry.grid(row = 2, column = 1)
# Establish a field for the response
self._answer = Label(self,
text = "Distance Travelled",
justify = "left")
self._answer.grid(row = 3, column = 0)
self._answerVar = DoubleVar()
self._answerFont = tkFont.Font(weight="bold", size = 12)
self._answerEntry = Entry(self,
textvariable = self._answerVar,
justify = "center",
font = self._answerFont)
self._answerEntry.grid(row = 3, column = 1)
self._answerEntry.config(state = DISABLED, bg = "green")
# Create frame to hold buttons
self._buttonFrame = Frame(self)
self._buttonFrame.grid(row = 4, column = 0, columnspan = 2)
# Create Reset Button
self._buttonReset = Button(self._buttonFrame,
text = "Reset",
command = self._reset,
width = 15,
padx = 2,
pady = 2)
self._buttonReset.grid(row = 0, column = 0)
#self._buttonReset.config(state = DISABLED)
# Create Calculate Button
self._buttonCalc = Button(self._buttonFrame,
text = "Calculate",
command = self._calculate,
width = 15,
padx = 2,
pady = 2)
self._buttonCalc.grid(row = 0, column = 1)
#self._buttonCalc.config(state = NORMAL)
def _reset(self):
"""Allow for the screen to reset for fresh data entry."""
self._heightVar.set(0.0)
self._numberBouncesVar.set(0)
self._answerVar.set(0.0)
#self._buttonCalc.config(state = NORMAL)
#self._buttonReset.config(state = DISABLED)
#self._numberBouncesEntry.config(state = NORMAL)
#self._bouncyEntry.config(state = NORMAL)
#self._heightEntry.config(state = NORMAL)
def _calculate(self):
"""Calculate the bounciness and update the GUI"""
if self._validDataTypes():
self._answerVar.set(computeDistance(self._heightVar.get(), \
self._bouncyVar.get(), \
self._numberBouncesVar.get()))
#self._numberBouncesEntry.config(state = DISABLED)
#self._bouncyEntry.config(state = DISABLED)
#self._heightEntry.config(state = DISABLED)
#self._buttonCalc.config(state = DISABLED)
#self._buttonReset.config(state = NORMAL)
def _validDataTypes(self):
theMessage = ""
if self._isInt(self._numberBouncesVar.get()) != True:
theMessage += "Please re-enter Integer Value for Number of Bounces.\n"
elif self._isFloat(self._bouncyVar.get()) != True:
theMessage += "Please re-enter Float Value for Bounciness Index.\n"
elif self._isFloat(self._heightVar.get()) != True:
theMessage += "Please re-enter Float Value for Initial Height."
if len(message) > 0:
tkMessageBox.showerror(message = message, parent = self)
return False
else:
return True
def _isInt(self, value):
# Test to ensure that value entered is an integer
try:
x = int(value)
except ValueError:
# If not return false
return False
# if it is an integer, return true
return True
def _isFloat(self, value):
# Test to ensure that value entered is a float value
try:
x = float(value)
except ValueError:
# If not return false
return False
# If it is a float, return true
return True
def computeDistance(height, index, bounces):
"""Compute the distance travelled."""
total = 0
for x in range(bounces):
total += height
height *= index
total += height
return total
def main():
"""Run the main program"""
BouncyGUI().mainloop()
main()
Your main() function setup code isn't working properly. I'm not sure how you had it set up before, but one way to get it working is this:
def main():
"""Run the main program"""
root = Tk()
gui = BouncyGUI()
gui.pack()
root.mainloop()
You need to grid the main app, not just call its mainloop:
def main()
app = BouncyGUI()
app.grid()
app.mainloop()
there is an error in your code when compiling:
NameError: global name 'message' is not defined