tkinter: default values wont appear in entries even with use of StringVar() - python

My program is an IFS editor which has two windows: one for displaying a fractal and the other for working with the corresponding IFS. The latter requires a grid of entries containing the values of linear transformations. Since I need 24 entries (6 entries for each linear transformation, and 4 transformations), I defined instead a table of entries using some for loops. I know that I have to set textvariable to StringVar and use StringVar.set() for putting in some default values, but when I run my program, the entries are still empty.
This is what I have. Here "matrices" is a 4x6 matrix of floats:
FunctionEntries=[[],[],[],[]]
FunctionSetEntries=[[],[],[],[]]
for i in range(4):
for j in range(6):
FunctionSetEntries[i]=FunctionSetEntries[i]+[Tkinter.StringVar()]
k=Tkinter.Entry(window, width="5", textvariable = FunctionSetEntries[i][j])
FunctionSetEntries[i][j].set(matrices[i][j])
FunctionEntries[i]=FunctionEntries[i]+[k]
FunctionEntries[i][j].grid(row=3+i,column=j+1)
FunctionEntries=FunctionEntries+[FunctionEntries[i]]
The strange part is that when I defined some other entries individually, everything was ok. Here were some of the entries that showed the default values correctly:
P=[0.85,0.07,0.07,0.01]
probs1=Tkinter.StringVar()
probs1.set(P[0])
probs2=Tkinter.StringVar()
probs2.set(P[1])
probs3=Tkinter.StringVar()
probs3.set(P[2])
probs4=Tkinter.StringVar()
probs4.set(P[3])
probLabel=Tkinter.Label(FractalWindow, width="15")
probLabel.configure(text="probabilities= ")
probEntry1=Tkinter.Entry(FractalWindow, width= "5", textvariable = probs1)
probEntry2=Tkinter.Entry(FractalWindow, width= "5", textvariable = probs2)
probEntry3=Tkinter.Entry(FractalWindow, width= "5", textvariable = probs3)
probEntry4=Tkinter.Entry(FractalWindow, width= "5", textvariable = probs4)
The last few were in a different window, so is that part of the issue? But everything else in both windows is running fine as far as I can tell. I also don't see any difference between what I did here and what I did in the previous case (the order of the entry definition and .set() didn't change anything). The grids also display properly. The only thing wrong is that the entries are empty. What's going on here?
Thanks!
EDIT: There seems to be a problem with the double windows. I defined FractalWindow first, and the default values for my entries appear in FractalWindow, but not "window". On the other hand, if I define "window" first, the default values appear, but not for those in FractalWindow. Why is this happening?

FunctionSetEntries[i]=FunctionSetEntries[i]+[Tkinter.StringVar()] is going to contain a StringVar() 6 times, one for each "j". If you use one list with 24 entries for simplicity to start out, you can just do the following (and note that you only have to keep a reference to either the Entry or StringVar, not both, to get/set the contents).
function_entries=[]
for i in range(4):
for j in range(6):
s_var=Tkinter.StringVar()
function_entries.append(s_var)
Tkinter.Entry(window, width="5", textvariable = s_var).grid(etc)
## proof of concept when not using a nested list
for num in range(24):
row, column=divmod(num, 6)
print num, row, column
for row in range(4):
for column in range(6):
print "list offset for %d, %d = %d" % (row, column, row*6+column)

Ok I figured it out. I needed to set one of my windows as Toplevel() instead. That enables me to use StringVar in both places. So something like
window=Tkinter.tk()
FractalWindow=Tkinter.Toplevel()
should do the job.

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.

Recreate left-to-right scrolling text in tkinter

I want to create a fast typing effect through packing a label in tkinter. When I run this code, it prints left to right as I want it to, but the letters are spaced far apart and the spaces print {} brackets instead.
How can I remove the brackets and just show a space? Is there also a cleaner and easier way to do the scrolling effect other than the list method I used?
root = Tk()
delay = 50
label_var = StringVar()
label = Label(root, textvariable=label_var, height=10)
num = 0
def scroll():
global num
roll_text = list(message) # Edit: deleted this line
num = num + 1
label_var.set(roll_text[1:num]) # Edit: changed roll_text to message
root.after(delay, scroll)
message = ' This message should be scrolling left to right. '
scroll()
label.pack()
root.mainloop()
The brackets are appearing because you're converting the string to a list. When tkinter is given a list where it expects a string it uses Tcl's rules for converting the list back to a string. Those rules include using curly braces to preserve the original data.
The solution is simple: don't pass a list to label_var.set.
As for the alignment, because you don't provide any alignment options, tkinter will try to center the widget. A simple solution for this specific case is to pass side='left' to the pack command.

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.

Changing the text of "mass-produced" labels

Hy All,
I'm creating a layout for a database, and made a big canvas which are the lines, spawning smaller canvas inside them (as cells) to contain labels for the data. It looks nice, but the problem is, that due to this "mass-creation" of canvas and label widgets, none of them stays uniqly addressable, they are all named after the same variable when created in a for loop. Any idea how to tag/address them during the creation so I can edit them later?
for f in range(15)
z = z+1
f = Label(someFrame, width = 45 if z < 4 else 12, text = f, borderwidth=2, relief="groove", bg = "#E5E5E5" if Color == True else "#B2B2B2" )
f.pack(side = LEFT)
It may look a bit messy, but you have a picture at least how the widgets are being created and what is my issue.
You can store your widgets in a dictionary. Something like this:
widget_dict = {}
for idx in range(10):
widget_dict['abc' + str(idx)] = label(root, ...)
Then you can access each widget through its dictionary key:
widget_dict[abc2].config(text='Banana')
Before your for loop create a list. Then inside of the for loop just append every label to the list. Or you can use a dictionary to store them, depending on how you want to deal with that.

Create multiple Entry boxes in a loop tkinter

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

Categories

Resources