Posts: 201
Threads: 37
Joined: Dec 2021
I dont mean it as a complaint but i like it when you guys comes with sopheticated answers like this.
Its clearly meant to teach me the proper way to implement class and attributes and i tha nk you for that. But its not solving the main issue.
from tkinter import *
class Temperature:
def __init__(self, valeur):
self.valeur = valeur
def conversionF(self):
if choix.get() == 'Celcius à Fahrenheit':
resultat = float((9 * self.valeur) / 5 + 32)
return resultat.configure(text=str(fahrenheit))
else:
return self.conversionC(self) ///////// <------i still want to know if it is logical and possible to that.
def conversionC(self):
resultat = float((self.valeur - 32) * 5 / 9)
return resultat.configure(text=str(celcius))
def changement(event):
if choix.get() == 'Celcius à Fahrenheit':
txt1.configure(text='Température en Celcius')
txt2.configure(text='Température en Fahrenheit')
else:
txt2.configure(text='Température en Celcius')
txt1.configure(text='Température en Fahrenheit')
valeur = Temperature(valeur = str(entree.get())) ///<----instead of a number i want to fit my method to input the temperature.
///How do i do that.
fen1 = Tk()
fen1.title('Conversion')
txt1 = Label(fen1, text='Température en Fahrenheit')
txt1.grid(row=0, column=0, sticky=E)
entree = Entry(fen1)
entree.grid(row=0, column=1)
txt2 = Label(fen1, text='Température en Celcius')
txt2.grid(row=1, column=0, sticky=E)
resultat = Label(fen1, text='')
resultat.grid(row=1, column=1)
bouton = Button(fen1, text='Conversion', command=conversionF)
bouton.grid(row=2, column=0)
choix = StringVar(fen1)
choix.set('Celcius à Fahrenheit')
liste = OptionMenu(fen1, choix, 'Celcius à Fahrenheit', 'Fahrenheit à Celcius', command=changement)
liste.grid(row=2, column=1)
fen1.mainloop() There must be an easy way to fix that code without reformating the whole thing. I get the bid picture, its the small details that slows me.
Posts: 6,780
Threads: 20
Joined: Feb 2020
I told you how to fix your problem. Write a little program that prints "Fahrenheit" or "Celsius". When you get that working you will know how to write a temperature conversion program.
Posts: 1,583
Threads: 3
Joined: Mar 2020
When called as a method, the instance is automatically passed in as the first argument. So you could do:
return self.conversionC()
Posts: 6,780
Threads: 20
Joined: Feb 2020
def conversionF(self): < Notes 1
if choix.get() == 'Celcius à Fahrenheit': < Notes 2, 3, 4
resultat = float((9 * self.valeur) / 5 + 32) < Notes 5
return resultat.configure(text=str(fahrenheit)) < Notes 6, 7
else:
return self.conversionC(self) ///////// <------i still want to know if it is logical and possible to that. < Notes 8 Notes 1:
Indenting is wrong. This is not part of class Temperature.
Notes 2:
There should not be an "if" statement in this function. This function converts temperature to Fahrenheit. it should not care about choix. The GUI code should call the appropriate method, conversionF() or conversionC() based on the value of choix.
Notes 3:
Temperature conversion class should not know about choix. The Temperature class should do temperature conversion and the GUI should take care of all the user interface stuff. choix is GUI related and should not appear in the Temperature class
Notes 4:
Do not use hard coded strings or numbers in comparisons. It is too easy to make a typing error and have this comparison return False when you want it to return True. These "magic values" are also hidden inside the code and if you decide to change the string in the GUI you may not remember it has to change here too.
Notes 5:
Why are you converting to float(). The equation will produce a float. There is no reason to call float() to change the float result to a float.
Notes 6:
resultat is a float. It does not understand .configure(). If resultat was something capable of .configure() it would not belong in this method. Calculate the number and return the value.
Notes 7:
There should be no "if" and no "else" in this function.
Six lines of code and 7 errors (at least). This is why I think you should toss the code and start fresh. All the errors make it difficult for me to understand what you think this code is supposed to do, and that makes it difficult to offer advice. Start simple. Get simple to work. Fully understand simple. Graduate to something more complex.
Posts: 6,780
Threads: 20
Joined: Feb 2020
Mar-05-2022, 07:11 AM
(This post was last modified: Mar-05-2022, 07:11 AM by deanhystad.)
Here is my temperature converter using my temperature class. I didn't have to make any changes to the Temperature class to use it in the GUI program (I added some more units for fun). The Temperature class is responsible for doing the unit conversion, and the GUI is responsible for getting user input, calling the Temperature methods to do the conversion, and displaying the results. I think your biggest problem was that you mashed all this together and there was no clear definition of who was responsible for what.
"""
Temperature converter panel. Enter temperature in entry. Specify units for the
"input" temperature and the tempeerature display. Converted temperatur appears
in label.
"""
import enum
import tkinter as tk
from tkinter import ttk
###### THIS IS THE TEMPERATURE CLASS PART ######
class Temperature:
"""I am a temperature. You can specify my units. I do unit conversion"""
# Temperature unts and unit conversion information. All temperatures are
# converted to and from Celsius regardless of the specified or default units.
class Unit(enum.Enum):
CELSIUS = "C"
FAHRENHEIT = "F"
KELVIN = "K"
RANKINE = "Ra"
REAUMER = "R"
# Convert from unit to Celsius
convert_from = {
Unit.CELSIUS: lambda x: x,
Unit.KELVIN: lambda x: x - 273.15,
Unit.FAHRENHEIT: lambda x: (x - 32) / 1.8,
Unit.RANKINE: lambda x: (x - 491.67) / 1.8,
Unit.REAUMER: lambda x: x * 1.25
}
# convert from Celsius to unit
convert_to = {
Unit.CELSIUS: lambda x: x,
Unit.KELVIN: lambda x: x + 273.15,
Unit.FAHRENHEIT: lambda x: x * 1.8 + 32,
Unit.RANKINE: lambda x: x * 1.8 + 491.67,
Unit.REAUMER: lambda x: x * 0.8
}
def __init__(self, value=None, unit=Unit.CELSIUS):
self.units = unit
self.set(0 if value is None else value)
def set(self, value, unit=None):
"""Set temperature value. Can specify unit for value."""
if unit is None:
unit = self.units
self.degreesC = self.convert_from[unit](value)
return self.degreesC
def set_units(self, units):
"""Change the default temperature units"""
self.units = units
def get(self, unit=None):
"""Get temperature value. Can specify unit for value."""
if unit is None:
unit = self.units
return self.convert_to[unit](self.degreesC)
def __str__(self):
"""Get str for printing."""
return f"{self.get()} °{self.units.value:0.2f}"
###### THIS IS THE GRAPHICAL USER INTERFACE PART ######
class TemperatureConverter(tk.Tk):
"""
Panel that uses Temperature class to do temperature unit conversion
Converts temperature from one temperature unit to another.
"""
def __init__(self, *args, **kvargs):
super().__init__(*args, **kvargs)
self.wm_title("Temperature Converter")
self.temperature = Temperature()
self.units = {unit.name:unit for unit in self.temperature.Unit}
unit_names = list(self.units.keys())
tk.Label(self, text="Convert").pack(padx=5, pady=5, side=tk.LEFT)
# "from" temperature widgets
self.from_units = tk.StringVar(value=unit_names[0])
self.from_value = tk.DoubleVar(value=0.0)
tk.Entry(self, textvariable=self.from_value, width=8, justify=tk.RIGHT) \
.pack(padx=5, pady=5, side=tk.LEFT)
ttk.Combobox(self, textvariable=self.from_units, values=unit_names, width=12) \
.pack(padx=5, pady=5, side=tk.LEFT)
tk.Label(self, text="to").pack(padx=5, pady=5, side=tk.LEFT)
# "to" temperature widgets
self.to_units = tk.StringVar(value=unit_names[0])
self.to_value = tk.StringVar(value="0.00")
tk.Label(self, textvariable=self.to_value, width=8, anchor=tk.E).pack(padx=5, pady=5, side=tk.LEFT)
ttk.Combobox(self, textvariable=self.to_units, values=unit_names, width=12) \
.pack(padx=5, pady=5, side=tk.LEFT)
# Bind variable write event to convert method. Convert method ignores arguments
for var in (self.from_value, self.from_units, self.to_units):
var.trace("w", self.convert)
def convert(self, *_):
"""Peform temperature unit conversion"""
try:
degrees = self.from_value.get()
self.temperature.set(degrees, self.units[self.from_units.get()])
degrees = self.temperature.get(self.units[self.to_units.get()])
self.to_value.set(f"{degrees:0.2F}")
except tk.TclError:
self.to_value.set("-NA-")
TemperatureConverter().mainloop()
Posts: 1,838
Threads: 2
Joined: Apr 2017
Mar-05-2022, 07:26 AM
(This post was last modified: Mar-05-2022, 07:26 AM by ndc85430.)
(Mar-04-2022, 11:18 PM)Frankduc Wrote: when you guys comes with sopheticated answers like this.
I don't think the code I showed was particularly sophisticated, but I can appreciate you may not be familiar with testing or enumerations. The main point I want to get across now though is that the Temperature class I wrote (that passed my tests) was simple. Why simple? Because it represents a single idea: what it means to be a temperature - there's a value and a unit and one can convert between units. Your class, on the other hand, is complicated. It mixes together the idea of what it means to be a temperature and displaying a temperature on a GUI. That makes it harder to understand and harder to change if you needed to - with multiple things going on in a class, if you change one thing you risk breaking another. Try to separate out different ideas like this - remember the Unix philosophy of "do one thing and do it well".
Posts: 201
Threads: 37
Joined: Dec 2021
Just one question.
from tkinter import *
class Temperature:
def __init__(self):
self.valeur = 0
def conversionF(self):
resultat = float((9 * self.valeur) / 5 + 32)
return resultat.configure(text=str(fahrenheit))
def conversionC(self):
resultat = float((self.valeur - 32) * 5 / 9)
return resultat.configure(text=str(celcius))
matemp = Temperature()
matemp.valeur = float(entree.get())
matemp.conversionF()
matemp.conversionC()
fen1 = Tk()
fen1.title('Conversion')
txt1 = Label(fen1, text='Température en Fahrenheit')
txt1.grid(row=0, column=0, sticky=E)
entree = Entry(fen1)
entree.grid(row=0, column=1)
txt2 = Label(fen1, text='Température en Celcius')
txt2.grid(row=1, column=0, sticky=E)
resultat = Label(fen1, text='')
resultat.grid(row=1, column=1)
bouton = Button(fen1, text='Conversion', command=conversionF)
bouton.grid(row=2, column=0)
fen1.mainloop() Why it return this error:
Error: TypeError: conversionF() missing 1 required positional argument: 'self'
It was my first question and still is. You guys are probably sick of that thread but...
What does it want.
Posts: 1,027
Threads: 16
Joined: Dec 2016
Mar-05-2022, 08:42 PM
(This post was last modified: Mar-05-2022, 08:42 PM by Axel_Erfurt.)
Your indentation is wrong, that's the problem.
from tkinter import *
class Temperature:
def __init__(self):
self.valeur = 0
def conversionF(self):
result = float((9 * float(entree.get()) / 5 + 32))
resultat.configure(text=str(result))
def conversionC(self):
result = float((float(entree.get() - 32) * 5 / 9))
resultat.configure(text=str(result))
t = Temperature()
fen1 = Tk()
fen1.title('Conversion')
txt1 = Label(fen1, text='Température en Fahrenheit')
txt1.grid(row=0, column=0, sticky=E)
entree = Entry(fen1)
entree.grid(row=0, column=1)
txt2 = Label(fen1, text='Température en Celcius')
txt2.grid(row=1, column=0, sticky=E)
resultat = Label(fen1, text='')
resultat.grid(row=1, column=1)
bouton = Button(fen1, text='Conversion', command=t.conversionF)
bouton.grid(row=2, column=0)
fen1.mainloop()
Posts: 6,780
Threads: 20
Joined: Feb 2020
Mar-05-2022, 09:38 PM
(This post was last modified: Mar-05-2022, 09:38 PM by deanhystad.)
Actually we've explained this over and over and over. One last try.
The error message could not be any more descriptive.
The function conversionF(self) has an argument named "self". When you press the conversion button you call conversionF() without passing any arguments. Your function call is "missing 1 required positional argument".
But this is not the error. This error is one of two things. Either conversionF() is supposed to be a method of class Temperature, or it is supposed to be a standalone function.
Either your program should look more like this:
import tkinter as tk
class Temperature:
"""All classes should have a docstring describing their purpose"""
def __init__(self):
self.valeur = 0
# Indentation is important. Needs to be indented to same level as __init__()
def conversionF(self):
"""Methods should also have docstrings"""
fahrenheit = float((9 * self.valeur) / 5 + 32)
return resultat.configure(text=str(fahrenheit))
def conversionC(self):
"""To describe what they do"""
celcius = float((self.valeur - 32) * 5 / 9)
return resultat.configure(text=str(celcius))
# This is not part of class temperature because it is indented the same level as "class Temperature"
fen1 = tk.Tk()
matemp = Temperature()
entree = tk.Entry(fen1).pack()
resultat = tk.Label(fen1, text='')
resultat.pack()
tk.Button(fen1, text='Conversion', command=matemp.conversionF).pack()
fen1.mainloop() Or it should look more like this:
import tkinter as tk
# Treating this as a function. There is no temperature class anymore
def conversionF():
"""Methods should also have docstrings"""
fahrenheit = float((9 * valuer) / 5 + 32)
return resultat.configure(text=str(fahrenheit))
def conversionC():
"""To describe what they do"""
celcius = float((valuer - 32) * 5 / 9)
return resultat.configure(text=str(celcius))
# These should not all be global variables
fen1 = tk.Tk()
valuer = 0
entree = tk.Entry(fen1).pack()
resultat = tk.Label(fen1, text='')
resultat.pack()
tk.Button(fen1, text='Conversion', command=conversionF).pack()
fen1.mainloop() Both programs convert 0 to something. Both programs are still riddled with logic errors.
Posts: 201
Threads: 37
Joined: Dec 2021
Thank you very much to both of you, gentlemen, for your patience and wisdow.
That is what i wanted to know. What specificaly was going wrong in the code.
I didn't understand that t = Temperature() or matemp = Temperature() belong to the scope of the Class temperature.
I got confused because in the book in some examples the funtions are at the same level of the class and sometimes at the level of the init self function. I wonder if its always the case. That points out to what you are saying:
Quote: Either conversionF() is supposed to be a method of class Temperature, or it is supposed to be a standalone function.
Now i can fix the rest.
Axel, Dean have a nice evening!
|