Making a grid of Entry boxes in Tkinter in a loop - python

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.

Related

how to fit 5 buttons besides 4 buttons in python tkinter

class calculate:
def __init__(self):
self.window = tk.Tk()
self.numbers = tk.Frame(master = self.window)
self.signs = tk.Frame(master = self.window)
self.lst, self.lst2 = (1,2,3,4,5,6,7,8,9,0,".","="),("C","+","-","*","/")
def buttons(self):
val = 0
for i in range(4):
for j in range(3):
self.numbutton = tk.Button(master = self.numbers,text = self.lst[val])
self.numbutton.grid(row = i,column = j)
val += 1
for i in range(5):
self.signbutton = tk.Button(master = self.signs,text = self.lst2[i])
self.signbutton.grid(row = i)
def packing(self):
self.numbers.grid(column= 0,row = 0,rowspan = 4)
self.signs.grid(column = 1,row = 0,rowspan = 4)
self.window.mainloop()
calculator = calculate()
calculator.buttons()
calculator.packing()
I am trying to put some buttons by using gird in python tkinter.
and I want that numbers and signs have same height.
but the signs is of larger height.
please help.
Thanks for help in advance.
You can force the size of a frame by giving the frame an height:
self.numbers = tk.Frame(master = self.window, height=200)
self.signs = tk.Frame(master = self.window, height=200)
Both frames will have a height of 200 but you can change it to whatever you want
for i in range(4):
for j in range(3):
self.numbutton = tk.Button(master = self.numbers,text = self.lst[val],width=5,height=5)
self.numbutton.grid(row = i,column = j)
val += 1
for i in range(5):
self.signbutton = tk.Button(master = self.signs,text = self.lst2[i],width=5, height=4)
self.signbutton.grid(row = i)
Add a padding in y of some 0.1 or 0.2 to make it look good.
You can add sticky="nsew" to all .grid(...) and add self.numbers.rowconfigure("all", weight=1) to make the number buttons to use all the available space inside self.numbers frame.
Below is modified code:
import tkinter as tk
class calculate:
def __init__(self):
self.window = tk.Tk()
self.numbers = tk.Frame(master=self.window)
self.signs = tk.Frame(master=self.window)
self.lst, self.lst2 = (1,2,3,4,5,6,7,8,9,0,".","="), ("C","+","-","*","/")
def buttons(self):
val = 0
for i in range(4):
for j in range(3):
self.numbutton = tk.Button(master=self.numbers, text=self.lst[val])
self.numbutton.grid(row=i, column=j, sticky="nsew") # added sticky
val += 1
for i in range(5):
self.signbutton = tk.Button(master=self.signs, text=self.lst2[i])
self.signbutton.grid(row=i, sticky="nsew") # added sticky
def packing(self):
self.numbers.grid(column=0, row=0, sticky="nsew") # added sticky
self.signs.grid(column=1, row=0, sticky="nsew") # added sticky
self.numbers.rowconfigure("all", weight=1) # use all available vertical space
self.window.mainloop()
calculator = calculate()
calculator.buttons()
calculator.packing()

creating button with tkinter

I was really curious why I cannot get my add_button to work,
as the window fails to come up when creating it.
from tkinter import *
class Calculator:
#-------------------------------------------------
def __init__(self, master):
self.master = master
master.title("Calculator")
self.close_button = Button(master, text = "Close", command = master.destroy)
Label(master, text = "First Digit").grid(row = 0)
Label(master, text = "Second Digit").grid(row = 1)
self.input1 = 0
self.input2 = 0
input1 = Entry(master)
input2 = Entry(master)
input1.grid(row = 0, column = 1)
input2.grid(row = 1, column = 1)
self.close_button.grid(row = 2, column = 0)
self.add_buton = Button(master, text = "Add", command = self.add())
self.add_button.grid(row = 2, column = 1)
master.configure(background = 'grey')
return
#-------------------------------------------------
def add(self):
return self.input1.get() + self.input2.get()
#-------------------------------------------------
#-------------------------------------------------
root = Tk()
calc = Calculator(root)
root.mainloop()
#-------------------------------------------------
Welcome to Stack!
I've looked through you code I've been able to do what you are asking. There were a few errors within your code:
a) you had self.add_buton and self.add_button which caused an error.
b) self.input1 = 0 and self.input2 = 0 are not required.
c) You were calling self.add() as the command and you should be calling self.add. When calling it as a command you do not need ()
d)input1 = Entry(master) should be self.input1 = tk.Entry(master)
e) You should convert your input values into int or float as otherwise it will just one value onto the end of the other. (Eg, 1 + 5 = 15 whereas int(1) + int(5) = 6
Here is your code with the entry boxes working as they should. I have import tkinter as tk hence why it is tk.Entry
from tkinter import *
import tkinter as tk
class Calculator:
#-------------------------------------------------
def __init__(self, master):
self.master = master
master.title("Calculator")
self.close_button = Button(master, text = "Close", command = master.destroy)
Label(master, text = "First Digit").grid(row = 0)
Label(master, text = "Second Digit").grid(row = 1)
self.input1 = tk.Entry(bd=5, width=35, background='gray35', foreground='snow')
self.input2 = tk.Entry(bd=5, width=35, background='gray35', foreground='snow')
self.input1.grid(row = 0, column = 1)
self.input2.grid(row = 1, column = 1)
self.close_button.grid(row = 2, column = 0)
self.add_button = tk.Button(master, text = "Add", command = self.add)
self.add_button.grid(row = 2, column = 1)
master.configure(background = 'grey')
return
#-------------------------------------------------
def add(self):
val = self.input1.get()
print(val)
#-------------------------------------------------
#-------------------------------------------------
root = Tk()
calc = Calculator(root)
root.mainloop()
This should now work how you wanted it too. The variables within the entry can be changed to suit. You were correct in calling the value of the entry with self.input1.get().
Hope this has helped.

Display output from functions called by buttons placed on GUI

I've tried to search this topic up, but it has been very confusing, as I don't use/quite understand stdout/stderr... However, I have this code right now that prints a list onto the console. Can someone explain to me how I could get this to print directly onto a GUI Textbox? My code:
from tkinter import *
import math
class TimeGenerator:
def __init__(self,master):
frame = Frame(master)
frame.grid()
label_iso = Label(root, text="Isotope A, Element")
label_vol = Label(root, text="Voltage")
label_range = Label(root, text="Charge Range")
entry_iso = Entry(root)
entry_vol = Entry(root)
entry_range = Entry(root)
label_iso.grid(row=0, sticky=E)
label_vol.grid(row=1, sticky=E)
label_range.grid(row=2, sticky=E)
entry_iso.grid(row=0, column=1)
entry_vol.grid(row=1, column=1)
entry_range.grid(row=2,column=1)
button = Button(root, text='Time Range', command=self.calculateTime)
button.grid(row=3, columnspan=2)
self.iso = entry_iso
self.vol = entry_vol
self.r = entry_range
def calculateTime(self):
x = 5
self.iso = self.iso.get().replace(" ", "")
list = []
for e in self.iso.split(","):
list.append(e)
f = open("/Users/LazyLinh/PycharmProjects/mass.mas12.txt", "r")
i = 0
while (i < 40):
header = f.readline()
i += 1
self.mass = 0
for line in f:
line = line.strip()
columns = line.split()
if (list[0] == columns[3]):
if (list[1] == columns[4]):
if (len(columns) == 16):
self.mass = float(columns[13].replace("#","")) + float(columns[14].replace("#",""))
else:
self.mass = float(columns[12].replace("#","")) + float(columns[13].replace("#",""))
self.r = self.r.get().replace(" ", "")
tup = tuple(int(x) for x in self.r.split(","))
list = []
for q in range(tup[0], tup[1] + 1):
y = x * math.sqrt(self.mass / (2 * q * float(self.vol.get())))
list.append(y)
i = tup[0]
for time in list:
print(i, ':', time)
i = i + 1
root = Tk()
b = TimeGenerator(root)
root.mainloop()
Thank you!
Somewhere in your code you need to create a text widget:
class TimeGenerator:
def __init__(self,master):
...
self.text = Text(...)
...
Later, use the insert method of the text widget instead of a print statement:
for time in list:
self.text.insert("end", "%d: %s\n" % (i, time))
i = i + 1

How to obtain all available Entry values

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()

Python Tkinter changing StringVar value to use it as a background indicator on a UI

I'm building a UI where the users have to select some dates. I've added a row called Date Indicator which shows a box with a color. The starting color (until the user selects both dates) is grey. This color has to change depending on the dates that the user selects.
If he selects two dates where the days between them are more than two weeks, the box has to became green.
If he selects two dates where the days between them are less than two weeks, the box has to became yellow.
If he selects two dates where the days between them are less than one week, the box has to became red.
This is a Photoshoped result for the desired solution:
The code seems to be long, but you only have to check it until the tkCalendar class. From there to the bottom is just the calendar code you dont need to change. (And yes, there are some imports you dont need to use for this code, I maintain them because I've to use them for other stuff, but you can remove them)
# -*- coding: utf-8 -*-
import os
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
import xlrd
import csv
from tkMessageBox import *
from win32com.client import Dispatch
import datetime
import time
import calendar
year = time.localtime()[0]
month = time.localtime()[1]
day =time.localtime()[2]
strdate = (str(year) + "/" + str(month) + "/" + str(day))
fnta = ("Helvetica", 10)
fnt = ("Helvetica", 10)
fntc = ("Helvetica", 10, 'bold')
strtitle = "Calendario"
strdays= "Do Lu Ma Mi Ju Vi Sa"
dictmonths = {'1':'Ene','2':'Feb','3':'Mar','4':'Abr','5':'May',
'6':'Jun','7':'Jul','8':'Ago','9':'Sep','10':'Oct','11':'Nov',
'12':'Dic'}
class Planificador(Frame):
def __init__(self,master):
Frame.__init__(self, master)
self.master = master
self.initUI()
def initUI(self):
self.master.title("Planner")
self.frameOne = Frame(self.master)
self.frameOne.grid(row=0,column=0)
self.frameTwo = Frame(self.master)
self.frameTwo.grid(row=0, column=1)
self.frameThree = Frame(self.master)
self.frameThree.grid(row=0, column=2)
self.frameFour = Frame(self.master)
self.frameFour.grid(row=1,column=0, sticky=N)
self.frameFive = Frame(self.master)
self.frameFive.grid(row=1, column=1)
self.frameSix = Frame(self.master)
self.frameSix.grid(row=1, column=2, sticky=N)
self.frameSeven = Frame(self.master)
self.frameSeven.grid(row=2,column=0)
self.frameEight = Frame(self.master)
self.frameEight.grid(row=2, column=1, sticky=S)
self.frameNine = Frame(self.master)
self.frameNine.grid(row=2, column=2)
self.start_date_menu()
def start_date_menu(self):
self.initial_num_elements = 4
self.TEXT_MENU_ROW = 0 # initial date menu grid row
self.COL_WIDTH = 10 # width of each subcolumn of dates
for frame in (self.frameFour, self.frameSix):
self.dayintext = Label(frame, text="Day in",
width=self.COL_WIDTH, justify="center")
self.dayintext.grid(row=self.TEXT_MENU_ROW, column=0)
self.dayouttext = Label(frame, text="Day out", width=self.COL_WIDTH,
justify="center")
self.dayouttext.grid(row=self.TEXT_MENU_ROW, column=1)
self.status = Label(frame, text="Date indicator", width=self.COL_WIDTH,
justify="center")
self.status.grid(row=self.TEXT_MENU_ROW, column=2)
self.dates = [self.create_all_entrys(aux_index)
for aux_index in xrange(self.initial_num_elements)]
self.anadirpiezas = Button(self.frameEight, text="add more",
command=self.addone, width=self.COL_WIDTH)
self.anadirpiezas.grid(row=0, column=3)
def addone(self):
self.dates.append(self.create_all_entrys(len(self.dates)))
self.printdates()
def printdates(self):
print "IN:"
for i in xrange(self.initial_num_elements):
print self.dates[i][0].get() # col 0
print "OUT:"
for i in xrange(self.initial_num_elements):
print self.dates[i][2].get() # col 2
def create_all_entrys(self, aux_index):
menu_col = aux_index % 2 # left/right column of the date frame
menu_row = self.TEXT_MENU_ROW + aux_index/2 + 1
frame = self.frameSix if aux_index % 2 else self.frameFour
in_var = StringVar(value="--------")
in_btn = Button(frame, textvariable=in_var, width=self.COL_WIDTH,
command=lambda v=in_var: self.fnCalendar(v))
in_btn.grid(row=menu_row, column=0)
out_var = StringVar(value="--------")
out_btn = Button(frame, textvariable=out_var, width=self.COL_WIDTH,
command=lambda v=out_var: self.fnCalendar(v))
out_btn.grid(row=menu_row, column=1)
self.colorvar = StringVar()
self.colorvar.set('grey')
self.status_color = Label(frame, width=2, bg=self.colorvar.get())
self.status_color.grid(row=menu_row,column=2)
return in_var, in_btn, out_var, out_btn
def fnCalendar(self, datebar):
tkCalendar(self.master, year, month, day, datebar)
class tkCalendar :
def __init__ (self, master, arg_year, arg_month, arg_day,
arg_parent_updatable_var):
print arg_parent_updatable_var.get()
self.update_var = arg_parent_updatable_var
top = self.top = Toplevel(master)
top.title("Choose a date")
try : self.intmonth = int(arg_month)
except: self.intmonth = int(1)
self.canvas =Canvas (top, width =200, height =220,
relief =RIDGE, background ="#ece9d8", borderwidth =0)
self.canvas.create_rectangle(0,0,303,30, fill="#ece9d8",width=0 )
self.canvas.create_text(100,17, text="Choose!", font=fntc, fill="#BA1111")
stryear = str(arg_year)
self.year_var=StringVar()
self.year_var.set(stryear)
self.lblYear = Label(top, textvariable = self.year_var,
font = fnta, background="#ece9d8")
self.lblYear.place(x=85, y = 30)
self.month_var=StringVar()
strnummonth = str(self.intmonth)
strmonth = dictmonths[strnummonth]
self.month_var.set(strmonth)
self.lblYear = Label(top, textvariable = self.month_var,
font = fnta, background="#ece9d8")
self.lblYear.place(x=85, y = 50)
#Variable muy usada
tagBaseButton = "Arrow"
self.tagBaseNumber = "DayButton"
#draw year arrows
x,y = 40, 43
tagThisButton = "leftyear"
tagFinalThisButton = tuple((tagBaseButton,tagThisButton))
self.fnCreateLeftArrow(self.canvas, x,y, tagFinalThisButton)
x,y = 150, 43
tagThisButton = "rightyear"
tagFinalThisButton = tuple((tagBaseButton,tagThisButton))
self.fnCreateRightArrow(self.canvas, x,y, tagFinalThisButton)
#draw month arrows
x,y = 40, 63
tagThisButton = "leftmonth"
tagFinalThisButton = tuple((tagBaseButton,tagThisButton))
self.fnCreateLeftArrow(self.canvas, x,y, tagFinalThisButton)
x,y = 150, 63
tagThisButton = "rightmonth"
tagFinalThisButton = tuple((tagBaseButton,tagThisButton))
self.fnCreateRightArrow(self.canvas, x,y, tagFinalThisButton)
#Print days
self.canvas.create_text(100,90, text=strdays, font=fnta)
self.canvas.pack (expand =1, fill =BOTH)
self.canvas.tag_bind ("Arrow", "<ButtonRelease-1>", self.fnClick)
self.canvas.tag_bind ("Arrow", "<Enter>", self.fnOnMouseOver)
self.canvas.tag_bind ("Arrow", "<Leave>", self.fnOnMouseOut)
self.fnFillCalendar()
def fnCreateRightArrow(self, canv, x, y, strtagname):
canv.create_polygon(x,y, [[x+0,y-5], [x+10, y-5] , [x+10,y-10] ,
[x+20,y+0], [x+10,y+10] , [x+10,y+5] , [x+0,y+5]],
tags = strtagname , fill="black", width=0)
def fnCreateLeftArrow(self, canv, x, y, strtagname):
canv.create_polygon(x,y, [[x+10,y-10], [x+10, y-5] , [x+20,y-5] ,
[x+20,y+5], [x+10,y+5] , [x+10,y+10] ],
tags = strtagname , fill="black", width=0)
def fnClick(self,event):
owntags =self.canvas.gettags(CURRENT)
if "rightyear" in owntags:
intyear = int(self.year_var.get())
intyear +=1
stryear = str(intyear)
self.year_var.set(stryear)
if "leftyear" in owntags:
intyear = int(self.year_var.get())
intyear -=1
stryear = str(intyear)
self.year_var.set(stryear)
if "rightmonth" in owntags:
if self.intmonth < 12 :
self.intmonth += 1
strnummonth = str(self.intmonth)
strmonth = dictmonths[strnummonth]
self.month_var.set(strmonth)
else :
self.intmonth = 1
strnummonth = str(self.intmonth)
strmonth = dictmonths[strnummonth]
self.month_var.set(strmonth)
intyear = int(self.year_var.get())
intyear +=1
stryear = str(intyear)
self.year_var.set(stryear)
if "leftmonth" in owntags:
if self.intmonth > 1 :
self.intmonth -= 1
strnummonth = str(self.intmonth)
strmonth = dictmonths[strnummonth]
self.month_var.set(strmonth)
else :
self.intmonth = 12
strnummonth = str(self.intmonth)
strmonth = dictmonths[strnummonth]
self.month_var.set(strmonth)
intyear = int(self.year_var.get())
intyear -=1
stryear = str(intyear)
self.year_var.set(stryear)
self.fnFillCalendar()
def fnFillCalendar(self):
init_x_pos = 20
arr_y_pos = [110,130,150,170,190,210]
intposarr = 0
self.canvas.delete("DayButton")
self.canvas.update()
intyear = int(self.year_var.get())
monthcal = calendar.monthcalendar(intyear, self.intmonth)
for row in monthcal:
xpos = init_x_pos
ypos = arr_y_pos[intposarr]
for item in row:
stritem = str(item)
if stritem == "0":
xpos += 27
else :
tagNumber = tuple((self.tagBaseNumber,stritem))
self.canvas.create_text(xpos, ypos , text=stritem,
font=fnta,tags=tagNumber)
xpos += 27
intposarr += 1
self.canvas.tag_bind ("DayButton", "<ButtonRelease-1>", self.fnClickNumber)
self.canvas.tag_bind ("DayButton", "<Enter>", self.fnOnMouseOver)
self.canvas.tag_bind ("DayButton", "<Leave>", self.fnOnMouseOut)
def fnClickNumber(self,event):
owntags =self.canvas.gettags(CURRENT)
for x in owntags:
if (x == "current") or (x == "DayButton"): pass
else :
strdate = (str(self.year_var.get()) + "/" +
str(self.intmonth) + "/" +
str(x))
self.update_var.set(strdate)
self.top.withdraw()
def fnOnMouseOver(self,event):
self.canvas.move(CURRENT, 1, 1)
self.canvas.update()
def fnOnMouseOut(self,event):
self.canvas.move(CURRENT, -1, -1)
self.canvas.update()
if __name__ == "__main__":
root = Tk()
aplicacion = Planificador(root)
root.mainloop()
I'm totally lost trying to do this. I know I've to change self.colorvar but I dont know how to do it. I tryed to self.colorvar.set('red') for example but I cant make it work the way I explaned above. The in and out dates can be found on the printdates function. You help is much appreciated.
I don't think you can link the bg option to a StringVar. You can only do it with the option textvariable. The way you should do it is via the Label.config() method.
So you could write:
self.status_color.config(bg='red')
or, if you want to keep using the colorvar:
self.colorvar.set('red')
self.status_color.config(bg=self.colorvar.get())
That should work, and I guess that you can figure out the 2 week thing.
EDIT:
You can also 'link' the StringVar self.colorvar to a function that changes self.status_color (with the trace method); so that whenever colorvar is changed, your function will be called and it will change the status color.
This is my suggestion:
def myFunc(*args):
self.status_color.config(bg=self.colorvar.get())
self.colorvar.trace('w',self.myFunc)
Now every time you call self.colorvar.set(), you will be also calling self.myFunc.
EDIT:
As for the week thing, I'm not going to answer completely as it seems easy. Just get an integer for month and day of IN and OUT and do something like this:
monthdiff = monthout-monthin
if monthdiff!=0:
dayout += monthdiff*30 #or 31, depending on the month. Just add an if/else
weeks = ((dayout-dayin)//7)+1 #For python2.7 use only one slash
And then your if/else with the colour changing function. Be careful with January too, just add one if more. And I guess you can parse the IN and OUT strings to get the month and day yourself.

Categories