Title: Function traceback says not receiving positional arguments
Tags: python-3.x;user-interface;tkinter;typeerror
Question: 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.
Comment: @BryanOakley I honestly didnt even think I could write a function that took no arguments, thanks!

Comment: The error is telling you exactly what the problem is - your function requires four parameters, but when you call a command from a button it won't send any parameters. Since you are fetching the values you need, why does your function require parameters?

Comment: Welcome to Stack Overflow! Check out the [tour]. It would help if you made a [mre]. See [ask] if you want more tips.

Here is the accepted answer: 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
...


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 3, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2019:00:11/14/19', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<python-3.x><user-interface><tkinter><typeerror>', 'Title': 'Function traceback says not receiving positional arguments', 'ViewCount': 21, 'id': 58867204, 'user_AboutMe': '', 'user_AccountId': 4816086.0, 'user_DisplayName': 'T3MP35T', 'user_Reputation': 3.0, 'user_Views': 1.0, 'user_id': 3888145.0}}