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

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.

Related

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

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

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.

Scale with variable resolution [duplicate]

Is it possible to have a slider (Scale widget in tkinter) where the possible values that are displayed when manipulating the slider are discrete values read from a list?
The values in my list are not in even steps and are situation dependent.
From all the examples I've seen, you can specify a minimum value, a maximum value and a step value (n values at a time), but my list might look like this:
list=['0', '2000', '6400', '9200', '12100', '15060', '15080']
Just as an example. To reiterate, I want it go from for instance list[0] to list[1] or list[6] to list[5] when pulling the slider.
If anyone has any other suggestion for easily being able to pick a value from hundreds of items in a list, I'm all ears. I tried the OptionMenu widget but it gets to extensive and hard get a view of.
Edit you could set the command of the slider to a callback, have that callback compare the current value to your list and then jump to the nearest by calling set() on the slider
so:
slider = Slider(parent, from_=0, to=100000, command=callback)
and:
def callback(event):
current = event.widget.get()
#compare value here and select nearest
event.widget.set(newvalue)
Edit:
to show a complete (but simple example)
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
valuelist = [0,10,30,60,100,150,210,270]
def valuecheck(value):
newvalue = min(valuelist, key=lambda x:abs(x-float(value)))
slider.set(newvalue)
root = tk.Tk()
slider = tk.Scale(root, from_=min(valuelist), to=max(valuelist), command=valuecheck, orient="horizontal")
slider.pack()
root.mainloop()
i've tested this in python 2.7.6 and 3.3.2, even when dragging the slider this jumps to the nearest value to where the mouse is currently as opposed to only jumping when you let go of the slider.

Why does this function not return a value?

Be forewarned, I just started learning Python, and its my first time on this site. If I act like a n00b, please don't hate.
So I have created a program that is supposed to tell you how long it will take you to get to a star (distance is specified) at the speed of light, and factors of the speed of light. It begins with a library called easygui, which creates a nice window, which the user chooses a factor. The factor they have chosen becomes the variable "choice". This section of the code works fine. Ideally, this value would then be fed into a function, which would do the factoring, and return a value for the number of days of travel. This is unsuccessful. Most likely, I have simply set this up wrong, so if anyone knows the proper way to use functions, I'd really appreciate your help! Oh, and I tried to comment like crazy, so hopefully everything makes sense!
import easygui as eg #the gui creation library I am using
dist = 41000000000000 #distance to the star
light = 300000 #speed of light
def Convert (factor): #takes in factor chosen by user
speed = light*factor #the speed is the factor multiplied by the speed of light
time = (dist/speed)/3600 # the time is the distance/divided by the speed, since thats a huge value in seconds, the /3600 should reduce it to days
return time #"should" return the value it got for "time"
msg = "Choose a warp factor:" #creates a gui window for user to select factor
title = "Warp Factor Selection"
choices = ["1", "3", "5", "10", "50", "100", "200", "500", "1000"]
choice = eg.buttonbox(msg, title, choices) #gui returns the user's selection as "choice" WORKS!
choice = float(choice) #changes choice to float
if choice == 1:
Convert(choice) #attempts to feed "choice" into the function "convert" DOES NOT WORK :(
print (Convert(1)) #then print the value created from convert (have also tried print(time) but it always returns 0)
At this point in time, it is intentionally set up to only accept the choice of 1 as the factor. I want to figure this function thing out before I go and do the rest of the possible factors
thefourtheye already explained why, but if you want to avoid this in the future you could switch to Python 3 division by putting this at the top of your file:
from __future__ import division
In Python 3, it behaves more intuitively in situations like this (1/2 == .5) while you can still get the integer division behavior with // (1//2 == 0)
When you do
(dist/speed)/3600
if the (dist/speed) is lesser than 3600, result will be 0. You can try that out yourself,
print 3599/3600
will print
0
So, you need to convert the data to float like this
def Convert (factor):
speed = light*factor
return (float(dist)/float(speed))/3600.0
You may want to do this
if str(choice) in choices:
Convert(choice)
print (Convert(choice))
That way, you don't have to make a new if condition to test each number. This just says that if choice is in choices list, execute the function with choice.

Tkinter radio button clear / reset values

I am writing a Tkinter program for the first time and have a question on radio buttons. What I am trying to do is this:
open a set of images (one at a time).
When an image is opened, annotate a value using the radio button.
Collect this value in a list
So, in this example I have 2 compounds and the list would have 2 annotations.
The problem I have is, if by mistake the user clicks radiobutton 2 instead of one, and then corrects him/herself, the list will have 4 items (3 for the first image, 1 for the second). How do I handle this, so that the list will have only 2 values?
import Tkinter as tk
from PIL import ImageTk, Image
from tkFileDialog import askopenfilename
cmp_list = ["VU435DR","VU684DR"]
li = []
li_final = []
def sel():
selection = str(var.get())
if selection == "1":
li.append("Antagonist")
elif selection == "2":
li.append("Agonist")
for i in range(len(cmp_list)):
root = tk.Tk()
var = tk.IntVar()
ig = str(cmp_list[i] + '.png')
img = ImageTk.PhotoImage(Image.open(ig))
panel = tk.Label(root,image=img)
panel.pack(side = "top",fill="none",expand="no")
#w = tk.Text(height=2,width=50)
#w.pack(side='right")
q = tk.Radiobutton(root,text="Antagonist",command=sel,value=1,variable=var)
q.pack()
r = tk.Radiobutton(root,text="Agonist",command=sel,value=2,variable=var)
r.pack()
root.mainloop()
print li
Your code is creating more than one instance of tk.Tk(). This is not how Tkinter was designed to work, and it will yield unpredictable behavior. A proper Tkinter program always has exactly one instance of tk.Tk().
If you need more than one window, for the second and subsequent windows you should create an instance of tk.Toplevel.
To answer your specific question about how to handle someone first hitting one radiobutton and then the other -- the problem is that you are unconditionally appending to your list each time they click on a radiobutton. The solution is to use some sort of flag or indicator to know whether one of the radiobuttons has been clicked, or change your code so that it doesn't matter.
Let's look at that second option - make it so it doesn't matter. When you open up a new image you can automatically append a value to your list. In this case, set it to None to say that nothing has been picked yet. Then, in sel, you would always replace the last element rather than append a new element, since you know that the last element always refers to the current compound.

Categories

Resources