Function traceback says not receiving positional arguments - python-3.x

Issue begins at def displayAnswer
import tkinter as tk
#icftk stands for incompressible-flow toolkit
"""This program is being built to aid in getting all
parameters of a flow given certain initial conditions"""
#CREATES THE WINDOW
root = tk.Tk()
root.title("Incompressible Fluid Toolkit")
class flow:
"""This class contains all necessary parameters needed to define a flow that i
incompressible, 1D-Steady, idiabatic and encounters no energy gain or loss"""
def __init__(self,vel,diameter,density,viscosity,massflow = 0, Re = 0, newdia = 1, jetforce = 0, newvel = 0):
"""initialize a fluid with given basic measured properties"""
self.vel = vel
self.diameter = diameter
self.density = density
self.viscosity = viscosity
self.massflow = massflow # mass flow rate
self.Re = Re #Reynolds Number
self.newdia = newdia # downstream diameter for velocity change
self.jetforce = jetforce # force the stream can produce normal to a surface
self.newvel = newvel # new velocity after a cross sectional area change
def reynolds(self):
"""This function calculates reynolds
Pass ro, v, D and mu in the same unit system, in that order"""
self.Re = (self.diameter*self.vel*self.density)/(self.viscosity)
print(f"The Reynolds number for this flow is {self.Re}")
def mdot(self):
"""This function finds the mass flowrate of a flow"""
flowarea = 3.14159*(self.diameter**2) / 4
self.massflow = self.density*self.vel*flowarea
print(f"The mass flowrate is {self.massflow}")
def streamforce(self):
"""This function gives the max force that the fluid jet can apply
normal to a surface perpendicular to the flow"""
self.jetforce = self.massflow*self.vel
print(f"The maximum force the jet can apply is {self.jetforce}")
def velchange(self):
"""This function is used to determine the velocity change of
a flow when there is a change in cross sectional area of the pipe"""
newarea = 3.14159 * (self.newdia**2) / 4
self.newvel = self.massflow/(self.density*newarea)
print(f"At the location of the area change, there is a velocity change from {self.vel} to {self.newvel}")
#ALL ABOVE FUNCTIONS HAVE BEEN CONFIRMED TO WORK WITH GIVEN TEST CONDITIONS BELOW
#use test case velocity = 18.64, diameter = 0.017, density = 1.23, and viscosity = 0.0000184
#Display Entry Boxes
velo = tk.Label(root, text="Flow Velocity") # Create a text label
velo.grid(row = 0, column = 0, pady = 10) # Pack it into the window, padding determines how mach space is around a window element
veloent = tk.Entry()
veloent.grid(row = 0, column = 1, pady = 10)
diam = tk.Label(root, text="Pipe Diameter") # Create a text label
diam.grid(row = 1, column = 0, pady = 10) # Pack it into the window, padding determines how mach space is around a window element
diament = tk.Entry()
diament.grid(row = 1, column = 1, pady = 10)
dens = tk.Label(root, text="Fluid Density") # Create a text label
dens.grid(row = 2, column = 0, pady = 10) # Pack it into the window, padding determines how mach space is around a window element
densent = tk.Entry()
densent.grid(row = 2, column = 1, pady = 10)
visc = tk.Label(root, text="Fluid Viscosity") # Create a text label
visc.grid(row = 3, column = 0, pady = 10) # Pack it into the window, padding determines how mach space is around a window element
viscent = tk.Entry()
viscent.grid(row = 3, column = 1, pady = 10)
#Display answers at the bottom of the window
def displayAnswer(veloent,diament,densent,viscent):
ve = float(veloent)#gets velocity entry and turns it into a float
di = float(diament)#gets diameter entry and turns it into a float
de = float(densent)#gets density entry and turns it into a float
vi = float(viscent)#gets viscosity entry and turns it into a float
fluid = flow(ve,di,de,vi)
fluid.reynolds()
fluid.mdot()
fluid.streamforce()
reynoldsanswer = tk.Label(root, text = "f{fluid.reynolds}")
reynoldsanswer.grid(row = 5)
mdotanswer = tk.Label(root, text = "f{fluid.mdot}")
mdotanswer.grid(row = 6)
streamforceanswer = tk.Label(root, text = "f{fluid.streamforce}")
streamforceanswer.grid(row = 7)
calculatebutton = tk.Button(root,command = displayAnswer)
calculatebutton.grid(row = 4)
root.mainloop()
I am new to tkinter, trying to get experience designing simple GUI. I am using a button to initiate a calculation to obtain values about an incompressible flow. When the button is pressed, the console throws this error.
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
TypeError: displayAnswer() missing 4 required positional arguments: 'veloent', 'diament', 'densent', and 'viscent'
Similarly, if I try to convert the Entry into a float from a string outside of the function, the console throws a cannot convert string to float error.
Honestly not sure if all of the code is even right, but I'll cross these bridges one at a time.
Any insight is appreciated.
Best,
T

The problem is that your function requires parameters, but never uses them. When you call the function from a button, the button will not by default pass any options. That's why you get missing 4 required positional arguments - the function requires four, the button passes zero.
Since your function is actually doing the right thing and fetching the values it needs, there's no need to pass in the parameters. The simple fix is to simply remove them from the definition of the function:
def displayAnswer():
ve = float(veloent)#gets velocity entry and turns it into a float
di = float(diament)#gets diameter entry and turns it into a float
de = float(densent)#gets density entry and turns it into a float
vi = float(viscent)#gets viscosity entry and turns it into a float
...

Related

Interference of canvas items and problem in setting coordinates

I'm working on an animation of a moving object, while drawing it's path.
I want to draw the pixels in which the center of the object went through... but guess what? python decided to set the NW anchor of the image with the coordinates I send, instead of the center. I infer it has something to do with the pixels I draw simultaneously (creating a one pixel rectangle). so the image appear on the right of the path bellow... I want the center of it to be on the top of the pixels... adding the main of the code:
from tkinter import*
import time
dt = 0.01
clock_place = (500, 10)
def round_two(t, t0):
return round((t-t0)*100)/100
def round_three(t, t0):
return round((t-t0)*1000)/1000
# showing 'real time motion' for a known path (also cyclic), with
# parametric representation
def paint_known_path(x_pos, y_pos, t_0):
window = Tk()
canvas = Canvas(window, height=700, width=1000)
canvas.pack()
canvas.config(background='black')
tennis_ball = PhotoImage(file='tennis ball.png')
t = t_0
x = x_pos(t_0)
y = y_pos(t_0)
particle = canvas.create_image(x, y, image=tennis_ball)
clock = canvas.create_text(clock_place, text=round_two(t, t_0),
fill='white')
while True:
canvas.create_rectangle(x, y, x, y, outline='red')
canvas.itemconfig(clock, text=round_two(t, t_0))
t += dt
x = x_pos(t)
y = y_pos(t)
canvas.moveto(particle, x, y)
window.update()
if x == x_pos(t_0) and y == y_pos(t_0):
if t - t_0 > 100*dt:
break
time.sleep(dt)
canvas.create_text((500, 100), text='orbit duration: ' +
str(round_three(t, t_0)), fill='white')
window.mainloop()
It turns out to be quite a bit require, but here is the main completion components.
The first additional part that you need to add:
# print('the ten ball height', tennis_ball.height(), tennis_ball.width())
# tennis ball dimensions
tb_hght = tennis_ball.height()
tb_wdth = tennis_ball.width()
mid_point_x = x + tennis_ball.height() / 2
mid_point_y = y + tennis_ball.width() / 2
Secondly, also needed to add some functions to for x_pos and y_pos like this (these are just example functions to make the code work):
def x_pos(a):
# any function of t,
return 100
def y_pos(a):
# any function of t,
return 100
Furthermore, you need to call the function at the end like this:
paint_known_path(x_pos,y_pos,0)
Finally, need to add the mid_point_x and mid_point_y to the path that is drawn (as these will be the image centre points).

Problem with dynamically changing which command a button calls in tkinter

In this simple calculator GUI, I'm creating a frame template using classes. The frame has 2 labels, 2 entry boxes, and a button. I'd like the button to run a specific command depending on the function_call variable passed when initializing - but this doesn't work. The two_points function should be called for the first object, and one_point should be called for the second. How do I dynamically change which command is called based on which object I'm using? Thank you for taking the time to read this.
from tkinter import *
root = Tk()
root.title("Simple Slope Calculator")
class Slope_Calc:
# Variable info that changes within the frame
def __init__(self, master, num_1, num_2, frame_name, label_1_name, label_2_name, function_call):
self.num_1 = int(num_1)
self.num_2 = int(num_2)
self.frame_name = frame_name
self.label_1_name = label_1_name
self.label_2_name = label_2_name
self.function_call = function_call
# Frame template
self.frame_1 = LabelFrame(master, text = self.frame_name, padx = 5, pady = 5)
self.frame_1.grid(row = self.num_1, column = self.num_2, padx = 10, pady = 10)
self.label_1 = Label(self.frame_1, text = self.label_1_name)
self.label_1.grid(row = 0, column = 0)
self.entry_1 = Entry(self.frame_1)
self.entry_1.grid(row = 0, column = 1)
self.label_2 = Label(self.frame_1, text = self.label_2_name)
self.label_2.grid(row = 1, column = 0)
self.entry_2 = Entry(self.frame_1)
self.entry_2.grid(row = 1, column = 1)
self.calc_button = Button(self.frame_1, text = "Calculate", command = self.function_call) # This is what doesn't work
self.calc_button.grid(row = 1, column = 2, padx = 5)
# Strips string of spaces and parentheses
# Returns a list of relevant ordered pair
def strip_string(self, entry_num):
ordered_pair = entry_num.get().split(", ")
ordered_pair[0] = ordered_pair[0].replace("(", "")
ordered_pair[1] = ordered_pair[1].replace(")", "")
return(ordered_pair)
# Calculates slope based on one point and y-intercept
def one_point(self):
pair_1 = self.strip_string(self.entry_1)
b = int(self.entry_2.get())
m = (int(pair_1[1]) - b)/(float(pair_1[1]))
label_3 = Label(self.frame_1, text = "SLOPE-INTERCEPT EQUATION: y = " + str(m) + "x + " + str(b))
label_3.grid(row = 2, column = 0, columnspan = 2)
# Calculates slope based on two points given
def two_points(self):
pair_1 = self.strip_string(self.entry_1)
pair_2 = self.strip_string(self.entry_2)
m = (int(pair_2[1]) - int(pair_1[1]))/float(int(pair_2[0]) - int(pair_1[0]))
b = (int(pair_1[1])) - (m*int(pair_1[0]))
label_3 = Label(self.frame_1, text = "SLOPE-INTERCEPT EQUATION: y = " + str(m) + "x + " + str(b))
label_3.grid(row = 2, column = 0, columnspan = 2)
# Calling each object
two_p = Slope_Calc(root, 0, 0, "Two Points", "First Ordered Pair", "Second Ordered Pair", "two_points")
one_p = Slope_Calc(root, 0, 1, "One Point and Y-Intercept", "Ordered Pair", "Y-intercept", "one_point")
root.mainloop()
The command keyword argument of the Button constructor is supposed to be a function.
Here you give it instead a string which is the name of the method of self that should be called. So you must first get this method using setattr to be able to call it. This should do it:
def call():
method = getattr(self, self.function_call)
method()
self.calc_button = Button(
self.frame_1,
text = "Calculate",
command = call)
You then have an error in strip_string but that's another story.

ValueError with entry-field. Tkinter math-program

writing a tkinter program for my kids to do some math.
It first shows a label with the math-question, for example "What is 5 + 3?"
Then an inputfield (entry) shows to get the answer (entry-field checks if integers are entered)
A Button is created to start a function to check the solution.
Function to create random numbers and create entry-field:
def Do_Math(self):
nr1 = random.choice(self.numbers) #random number from list
nr2 = random.choice(self.numbers) #random number from list
do_math = nr1 + nr2 #do the math
txt_som = Label(tk, text = 'wat is de som van ' + str(nr1) + ' en ' + str(nr2) + ' ?', state='normal', \
font=('Courier', 14, "bold"), justify=LEFT, padx = 10, background='LightCyan2')
txt_som.place(x = 20, y = 170)
tk.update()
oplossing = Entry(tk, validate="key") #create input-field #validate to check for integer
oplossing['validatecommand'] = (oplossing.register(self.testVal),'%P','%d') #validate to check for integer
oplossing.place(x = 20, y = 200) #place inputfield on screen
oplossing.focus_set() #set focus so user can directly input.
self.oplossing = oplossing
self.do_math = do_math
#knop voor ingeven oplossing:
knop_oplossing = Button(tk, text='Ok?', command=self.solution) #create button
knop_oplossing.place(x = 20, y = 250) #place button on screen
tk.update()
Function to check the solution:
If the solution is good then the above function runs again to create new numbers.
def solution(self):
while True:
if int(self.oplossing.get()) == self.do_math:
#self.oplossing.delete(0, END) #clear entr-value
play.random_sound('good')
self.lbl.place(self.lbl.pi) #Place label
self.lbl_w.place_forget() #Hide label
tk.update()
#global score
#score = score + 1
#print('GOED GEDAAN!', score, 'van', asked_maths, 'pogingen goed')
game.Do_Math() #Choose new random numbers
elif int(self.oplossing.get()) != self.do_math:
play.random_sound('wrong')
self.lbl.place_forget() #Hide label
self.lbl_w.place(self.lbl_w.pi) #Place label
tk.update()
break #Go out the while loop and do nothing
Every runs ok, but in the background i get following error every time the solution is good:
if int(self.oplossing.get()) == self.do_math:
ValueError: invalid literal for int() with base 10: ''
I think the problem is that the function "solution" tries this:
int(self.oplossing.get()) == self.do_math
but the entry-field has no value jet.
What do you think? I wanna solve these error messages before going further.
Thnx in advanced!

How to print the same text multiple times(5 times) in tkinter/GUI?

from tkinter import *
root=Tk()
textbox=Text(root)
textbox.pack()
button1=Button(root, text='Output Name', command=lambda : print('Hello'))
button1.pack()
def redirector(inputStr):
textbox.insert(INSERT, inputStr)
sys.stdout.write = redirector
root.mainloop()
This is my code with out a timer to do it five times.
This seems a little bit like homework, so lets try to get you on the right track over outright providing the code to accomplish this.
You're going to want to create a loop that performs your code a certain number of times. Let's say we just want to output a certain string 5 times. As an example, here's some really simple code:
def testPrint():
print('I am text!')
for i in range(5):
testPrint()
This will create a function called testPrint() that prints text "I am Text!", then run that function 5 times in a loop. If you can apply this to the section of code you need to run 5 times, it should solve the problem you are facing.
This worked for me. It creates a table using the .messagebox module. You can enter your name into the entry label. Then, when you click the button it returns "Hello (name)".
from tkinter import *
from tkinter.messagebox import *
master = Tk()
label1 = Label(master, text = 'Name:', relief = 'groove', width = 19)
entry1 = Entry(master, relief = 'groove', width = 20)
blank1 = Entry(master, relief = 'groove', width = 20)
def show_answer():
a = entry1.get()
b = "Hello",a
blank1.insert(0, b)
button1 = Button(master, text = 'Output Name', relief = 'groove', width = 20, command =show_answer)
#Geometry
label1.grid( row = 1, column = 1, padx = 10 )
entry1.grid( row = 1, column = 2, padx = 10 )
blank1.grid( row = 1, column = 3, padx = 10 )
button1.grid( row = 2, column = 2, columnspan = 2)
#Static Properties
master.title('Hello')

updating tkinter window for text background changes

Trying to show a green or red background in the text field of the answer to the simple addition quizzer.
Currently in PyCHarm complains that:
Entry.grid_configure(background = "red")
TypeError: grid_configure() missing 1 required positional argument: 'self'
0
I can't seem to figure this out. Any help is appreciated.
Here's the code so far:
from tkinter import *
import random
class MainGUI:
def __init__(self):
window = Tk() # Create the window
window.title("Addition Quizzer") # Set the title
#window.width(len(window.title()))
self.number1 = random.randint(0, 9)
self.number2 = random.randint(0, 9)
Label(window, text = "+").grid(row = 2, column = 1, sticky = E)
Label(window, text = "Answer").grid(row = 3, column = 1, sticky = W)
self.firstNumber = StringVar()
Label(window, text = self.number1, justify = RIGHT).grid(row = 1, column = 2)
self.secondNumber = StringVar()
Label(window, text = self.number2, justify = RIGHT).grid(row = 2, column = 2)
self.entry = StringVar()
Entry(window, textvariable = self.entry, justify = CENTER, width = 4, background = "grey").grid(row = 3, column = 2)
Button(window, text = "Answer:", command = self.computeAnswer).grid(row = 4, column = 1, sticky = E)
self.result = StringVar()
Label(window, textvariable = self.result).grid(row = 4, column = 2)
window.mainloop() # Create the event loop
def computeAnswer(self):
self.result.set(format(self.number1 + self.number2))
if self.entry == self.result:
self.displayCorrect()
else:
self.displayIncorrect()
def displayCorrect(self):
# self.correctAnswer = "Correct"
# Label(self.window, text = self.correctAnswer, background = "green", justify = RIGHT).grid(row = 5, column = 2)
Entry.grid_configure(background = "green")
def displayIncorrect(self):
# self.incorrectAnswer = "Incorrect"
# Label(self.window, text = self.incorrectAnswer, background = "red", justify = RIGHT).grid(row = 5, column = 2)
Entry.grid_configure(background = "red")
MainGUI()
If you had read and followed this in the Help Center material, you would have reduced your code to the following, which still gets the same error message.
from tkinter import *
Entry.grid_configure()
The message refers to the fact that Python instance methods require an instance. This is usually done by calling the method on an instance instead of the class. Otherwise, an instance must be given as the first argument. Consider
mylist = []
mylist.append(1)
list.append(mylist, 2)
print(mylist)
# [1, 2]
You need to save a reference to your Entry box. Change
Entry(window, ..., background = "grey").grid(...)
to
self.entry = Entry(window, ..., background = "grey").grid(...)
I do not know if calling .grid_configure(background=color will do what you want.
This will, I am sure.
self.entry['background'] = 'red'

Resources