Create multiple Entry boxes in a loop tkinter - python

I was making an application using tkinter and came across an error. I wanted people to input a variable, which I have made, and then have that many Entry boxes popup on the screen for input. I was wondering what is wrong with my code, if it is possible, or if there is a better way. Thanks in advance!
p.s. the NoOfBoxes has been predefined
int(NoOfBoxes)
x = 1
while(NoOfBoxes>=x):
a = a + 50
fill_empty(a)
x = x + 1
def fill_empty():
empty = tk.Entry(self)
empty.grid(row=200,column=a)
return empty

In first line of shown code, you are converting NoOfBoxes to an integer but you are not assigning back it to NoOfBoxes hence, when while line comes, NoOfBoxes is still not an integer. Also, there is no parameter on your fill_empty definition.
Most likely you will need those Entry widgets at some point in your code, so it'll be much better if you keep references.
listOfEntries = [fill_empty(idx) for idx in range(int(NoOfBoxes))]
def fill_empty(a):
empty = tk.Entry(self)
empty.grid(row=200,column=a)
return empty
When you want to make any operation on those, you can easily do something like:
listOfEntries[0].get()

Related

execute multiple variable functions(var_1,var_2,var_3)

I got another little question...
I want to make multiple variables which I create with 'setattr'
That works quite fine. It creates these variables:
self.sectionButton_1 = Button(text=x)
self.sectionButton_2 = Button(text=x)
self.sectionButton_3 = Button(text=x)
Now I want them to get displayed on the window with tkinter so that this should happen:
self.sectionButton_1.grid(row=i, column=0)
self.sectionButton_2.grid(row=i, column=0)
and so on..
But how do I have to edit the loop that the sectionButtons gonna be created with .grid from tkinter in a loop without writing the above ten times.
# Display Section selection
def checkSection(self):
# Read all sections from config
self.sections = config.sections()
self.sectionsCount = str(len(self.sections))
self.i = 0
self.text = Label(text="Choose Section:" + self.sectionsCount)
self.text.grid(row=1, column=0)
for x in self.sections:
i = +1
setattr(self, 'sectionButton_' + str(i), Button(text=x))
I'm not that good at explaining but hopefully its enough to understand my problem ^^
If not, just comment, I will try to answer it
If you have a group of related variables of the same type and you're doing the same operations to each one then that's a natural place to switch to using a list instead of individual variables.
Your code would become more like:
self.sectionButtons = []
for i, x in enumerate(self.sections):
button = Button(text=x)
button.grid(row=i+1, column=0)
self.sectionButtons.append(button)
This also has the advantage of no longer needing to construct the variable names as strings and use setattr, which is often a sign there's a better way.

Display output in GUI interface after checking the contents of the dictionary

I am creating a GUI interface that takes input from the user.
first, the weight.
second, the speed.
Then, I want to do some calculations based on these inputs.
first, acceleration, which is shown in the script below as the first function I defined.
second, force, which I utilised the weight input to multiply with the acceleration function.
mostly, I have done the interface already, but I cannot test the functions is they will be working properly, unless I have compare the calculated values to the dictionary contents.
let's say, I have a default dict information, as shown below.
Grade 1: A
Force: 500
Grade 2: B
Force: 300
Grade 3: C
Force:100
THE PROBLEM:
If for example, I entered, 50 for weight and 100 for speed, and hit the button, the program should automatically calculate the force based on these inputs.
If for example, the calculated force was 250...that value falls in Grade 2: B in the default dictionary.
(how can I go to the default dictionary and check those, loop through all the values of the keys in there, until my program decides that the value actually falls in this grade?)
then, the GUI should print the final output in the interface, in this case, it the GRADE 2: B.
How can I add these in my script below?
any hint would be much appreciated. This is an assignment but if you don't want to give the real code, I understand and that's fair enough. I just want to know where to start, look at, and how to understand the codes.
So please, I'd be happy if you could help.
here's what I have done so far.
from tkinter import *
from tkinter import ttk
x = []
def cal_acceleration(*args):
try:
# 1/2 and 0.4 default value, get the velocity value
# from below then multiplied by 1/2.
acce=((1/2) * ve.get()) / 0.40
x.append(acce)
except ValueError:
pass
def cal_force(*args):
try:
# multiplied the output of this function to the above function.
force=ma.get() * x
except ValueError:
pass
"""Creating a GUI with the following interface."""
root = Tk()
root.title("what type?")
frame = ttk.Frame(root, padding="5 5 5 5")
frame.grid(column=0, row=0, sticky=(N,S,E,W)) # stick frame to center.
ma = StringVar() # allocate user input weight
v = StringVar() # allocate user input speed
ma_entry = ttk.Entry(frame, width=7,textvariable=m) # entry dialogue for weight
ma_entry.grid(column=1,row=0,sticky=(W,E))
ve_entry = ttk.Entry(frame, width=7, textvariable=v) # entry dialogue for speed
ve_entry.grid(column=1,row=1,sticky=(W,E))
ma_label = ttk.Label(frame, text="how heavy:") # labelling weight
ma_label.grid(column=0, row=0,sticky=E)
velo_label = ttk.Label(frame, text="speed:") # labelling speed
velo_label.grid(column=0, row=1,sticky=E)
# setting the button for GUI. combining two functions using lambda.
find_button = ttk.Button(frame, text="Find", command=lambda[cal_acceleration(),cal_force()])
find_button.grid(column=2,row=0,sticky=W)
root.mainloop()
thank you very much.
The first step would be to fix your existing code.
As it is right now, it is not working for several reasons explained below, which leads me to think you have not tested it (recently).
Lambda call does not have ":" to it, preventing from calling your functions.
Check for your variable names, is it "v" or "ve" and is it "m" or "ma" ?
Debug your calculating function to work (it doesn't).
hint: your data must be the right type. you have Int, it wants Float.
hint: do you think multiplying a list works?
Then have it print your data first. When you know it's the result you expected, then you can start working on displaying in the gui.

Python GUI creating a list item with Text and checkboxes

I am trying to create a list like in outlook. With list items with an layout like this:
Don't get me wrong this isn't a "give me the full answer" question. I just have the problem of the right naming. I would appreciate it a lot if some could throw in the right words and I will look for them by my own.
I used tkinter at the moment but in that it seems like there isn't a solution for that.
Kind regards.
I think Tkinter can do this by using a bit of object oriented programming you could define how one list element should look like and then with static variables you could define a position of a new line relative to the position of the previous line. Something like:
from tkinter import *
class Line:
y = 0 # static variable for the y position
def __init__(self):
self.y_local = Line.y
Line.y = Line.y + 40 # increase the static variable for the next line
print(self.y_local)
def draw(self, tk, h_line="Headline", a_info="Addtional Information", date="01/01/1970"):
self.label_head = Label(text=h_line)
self.label_head.place(x=20, y=self.y)
self.label_info = Label(text=a_info)
self.label_info.place(x=20, y=self.y+20)
self.label_date = Label(text='Date')
self.label_date.place(x=200, y=self.y)
self.label_ndate = Label(text=date)
self.label_ndate.place(x=200, y=self.y+20)
self.chkbtn = Checkbutton(tk, text="Checkbox")
self.chkbtn.place(x=300, y=self.y+20)
tk = Tk()
data = [
["News", "WWIII has been avoided", "02/04/2018"],
["Python", "Python solves 42 riddles", "02/04/2018"]
]
for line in data:
temp = Line()
temp.draw(tk, line[0], line[1], line[2])
mainloop()
Hope I understood your question well. That you have a list with information and want to display that in an easy and scalable way. I have not looked to add the lines around the information as I've never done that before I know there are separators I've used vertical once before but I wouldn't be surprised if you can draw a box around each line either.

Which Tkinter functions should i use to find the coordinates of a randomly placed(in the canvas) text entry and how?

Thanks for looking into my question. I'll try to give you a big and small picture of what I'm trying to do here.
Big Picture:
So, basically I'm trying to make a simple mindmapping program where, after the first entry, every text I input unto the Entry widget is linked to the previous text via a line widget. So like this: Hello----There, and then Hello----There----Yo. Actually, I'm hoping for more modifications in the future like being able to rearrange the links via some metric I have yet explored, but this is basically it.
Small/Specific Picture:
I realize that in order to do this, I will have to find a way to acquire all the xy coordinates of every text drawn on the canvas (text I drew on the canvas by using the random function). I need the coordinates of the first text and the coordinates of the second text so I can use those to draw the line to visually link the two texts. I thought of using an array to list down all inputted text, but I realize that only stores the text and not the location of the text on the canvas. I have explored using tags, or using the coords functions or using the bbox function, but to no avail. Any clues on how to go about this? I would highly appreciate it, Thanks. :)
import Tkinter
import random
a = Tkinter.Tk()
b = Tkinter.Canvas(a, width=1000, height=500)
b.pack()
def c(event):
b.create_text(random.randint(50,940), random.randint(50,480), anchor="center", text=d.get())
f.append(d.get())
d.delete(0, 'end')
print f
#this function creates a randomly located text taken from the entry widget below and, at the same time, appends the text in the list known as f''
d = Tkinter.Entry(a)
d.pack()
d.bind("<Return>", c)
d.focus()
b.create_line(300, 250, 600, 290)
#this is my very early attempt at linking text inputted and drawn on the Canvas
f = []
a.mainloop()
Simply assign random values to variables before you use it to create text on canvas, and keep on list with object ID and text.
x = random.randint(...)
y = random.randint(...)
obj_id = b.create_text(x, y, ...)
f.append([x, y, obj_id, d.get()])
BTW: if you have obj_id then you can also do
x,y = b.coords(obj_id)

Tkinter how to make a dynamic optionmenu without using a dictionary

I found this question, which was helpful to see the methodology, but I want to use their method without using a dictionary.
Basically, in Python I'm trying to use two optionmenu's from Tkinter where the first will contain the tabs of an excel document, and then the second will contain information that I've read from one of the columns once the tab has been selected from the first optionmenu. As I don't want to store and read every single tab prior, it seems much more efficient to just call the function to read the data once the tab was chosen rather than create a dictionary beforehand. Does someone know a way of doing this?
Here is what I have so far(excel_transfer is a self created library based off openpyxl- if you have further questions on what I'm doing feel free to ask, otherwise it doesn't seem necessary to go into it for the purposes of this question):
import Tkinter
from Tkinter import *
from ttk import Frame
import manipulate_excel
import openpyxl
from openpyxl import load_workbook
class GUI(Frame):
def read_tabs(self):
wkbk = load_workbook('file.xlsx')
sheets=wkbk.get_sheet_names()
return sheets
def read_columns(self):
sheet = self.tabs_var.get()
#if no value is selected, keep return a blank value
if(sheet == ''):
return ['']
else:
filepath = 'file.xlsx'
workbook = excel_transfer.workbook(filepath)
wb = workbook.open_existing_workbook()
ws = wb(sheet)
#step through the rows until a blank value is read
row = 1
current_row = 0
previous_row = 0
values = []
#read the column, and append values to the array
while current_row != None:
previous_row = current_row
row = row + 1
cell = 'A' + str(row)
current_row = workbook.read_new_cell(cell, ws)
if(current_row != None):
values.append(current_row)
#if there are no values, still return a single array value so it doesn't barf
if(values== []):
values= ['']
return values
def build_gui(self):
n = Notebook(self)
tab = Tkinter.LabelFrame(self, text='Tab')
n.add(tab, text='Tab')
n.pack()
self.tabsvar = StringVar()
self.tabsvar.set('')
self.valuesvar = StringVar()
self.valuesvar.set('')
self.list_of_tabs = self.read_tabs()
self.list_of_values = self.read_columns()
self.TAB_OPTION = OptionMenu(tab, self.tabsvar, *self.list_of_tabs)
self.TAB_OPTION.grid(row=0, column=0)
self.VALUES_OPTION = OptionMenu(tab, self.valuesvar, *self.list_of_values)
self.VALUES_OPTION.grid(row=1, column=0)
if __name__ == '__main__':
root = Tk()
app = GUI(root)
root.mainloop()
The first option works to find the tabs, but the problem I have is the read_column only happens when the GUI is initially opened, it remains a blank value. How would I make the self.list_of_values responsive to which tab is chosen in the first optionmenu? Can I use trace without a dictionary? I'm sure there's prettier ways of writing the code I did- I'm open to constructive criticism as there's always plenty to learn. Thank you for the help!
Ok, so I found the answer after continuing to work with it to help out anyone in future having the same problem.
I changed self.TAB_OPTION to:
self.TAB_OPTION(tab, self.tabsvar, *self.list_of_tabs, command=self.read_columns)
By adding this, I had to pass in a variable into self.read_columns, as adding the command automatically passes the value the user selected in the first optionmenu. So, I changed self.read_columns to:
def read_columns(self, board):
sheet = board
#sheet = self.tabs_var.get()
I also took out the line shown to be commented above, so it received the value that was selected in the first optionmenu from the TAB_OPTION rather than reading what is selected from the GUI. I also added in:
self.VALUES_OPTION['menu'].delete(0, 'end')
for item in values:
self.VALUES_OPTION['menu'].add_command(label=item)
at the end of the read_columns function so it would regenerate the values for the second optionmenu. It deletes all of the previous values, then adds each value that had been read from the excel in by iterating through the array. I no longer needed the return value at the end of the function.
I hope this helps other confused coders :)

Categories

Resources