Передача переменных
Как передать переменную entry из def changer() в def analyse()?
В процессе ориентировался на этот вопрос, но, у меня так не работает, стабильно получаю ошибку вида:
TypeError: changer() missing 1 required positional argument: 'entry'
import tkinter as tk
from tkinter import ttk
def changer(event):
units_get = str(units.get())
entry = float(entry_a.get())
if units_get == 'нед.':
entry *= 7 / float(30.416)
entry = round(entry, 2)
ttk.Label(changed_units, style='changed_units.TLabel', text=f'-> {entry} мес.').place(x=0, y=3)
elif units_get == 'мес.':
for widget in changed_units.winfo_children():
widget.destroy()
elif units_get == 'годы':
entry *= float(30.416)
entry = round(entry, 2)
ttk.Label(changed_units, style='changed_units.TLabel', text=f'-> {entry} мес.').place(x=0, y=3)
return entry
def analyse(entry):
var_a = float(entry)
var_b = float(b.get())
score = var_a + var_b
print(score)
app = tk.Tk()
app.title('changer')
width = 300
height = 100
x = int((app.winfo_screenwidth() / 2) - (width / 2))
y = int((app.winfo_screenheight() / 2) - (height / 2))
app.geometry(f'{width}x{height}+{x}+{y}')
app.resizable(width=False, height=False)
app['background'] = '#666666'
ttk.Style().configure('changed_units.TLabel', font=('Tahoma', 8),
foreground='#ffffff', background='#666666', border=0)
changed_units = tk.Frame(app, bg='#666666')
changed_units.place(x=80, y=50, height=25, width=100)
units = ttk.Combobox(app, state='readonly', values=['нед.', 'мес.', 'годы'])
units.place(x=10, y=50, height=25, width=60)
units.current(1)
units.bind('<<ComboboxSelected>>', changer)
a = tk.StringVar()
entry_a = ttk.Entry(app, textvariable=a)
entry_a.place(x=10, y=12, height=25, width=60)
b = tk.StringVar()
entry_b = ttk.Entry(app, textvariable=b)
entry_b.place(x=80, y=12, height=25, width=60)
ttk.Button(app, text='Анализ', command=analyse).place(x=220, y=10, height=30, width=60)
app.mainloop()
Ответы (3 шт):
Можно объявить entry и сделать ее глобальной в функциях changer() и analyse().
А лучше используя ООП, как-то так:
main.py
import tkinter as tk
from tkinter import ttk
class App(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.entry = 1
self.score = 0
ttk.Style().configure(
'self.changed_units.TLabel',
font=('Tahoma', 8),
foreground='#ffffff',
background='#666666',
border=0)
self.changed_units = tk.Frame(master, bg='#666666')
self.changed_units.place(
x=80, y=50, height=25, width=100)
self.units = ttk.Combobox(master,
state='readonly',
values=['нед.', 'мес.', 'годы'])
self.units.place(x=10, y=50, height=25, width=60)
self.units.current(1)
self.units.bind('<<ComboboxSelected>>', self.changer)
self.a = tk.StringVar()
self.entry_a = ttk.Entry(master, textvariable=self.a)
self.entry_a.place(x=10, y=12, height=25, width=60)
self.b = tk.StringVar()
self.entry_b = ttk.Entry(master, textvariable=self.b)
self.entry_b.place(x=80, y=12, height=25, width=60)
ttk.Button(master,
text='Анализ',
command=self.analyse
).place(x=220, y=10, height=30, width=60)
def changer(self, event):
units_get = str(self.units.get())
self.entry = float(self.entry_a.get())
if units_get == 'нед.':
self.entry *= 7 / float(30.416)
self.entry = round(self.entry, 2)
ttk.Label(self.changed_units,
style='self.changed_units.TLabel',
text=f'-> {self.entry} мес.').place(x=0, y=3)
elif units_get == 'мес.':
for widget in self.changed_units.winfo_children():
widget.destroy()
elif units_get == 'годы':
self.entry *= float(30.416)
self.entry = round(self.entry, 2)
ttk.Label(self.changed_units,
style='self.changed_units.TLabel',
text=f'-> {self.entry} мес.').place(x=0, y=3)
# return entry
def analyse(self): # (entry)
var_a = float(self.entry)
var_b = float(self.b.get())
self.score = var_a + var_b
print(self.score)
if __name__ == '__main__':
root = tk.Tk()
root.title('changer')
width = 300
height = 100
x = int((root.winfo_screenwidth() / 2) - (width / 2))
y = int((root.winfo_screenheight() / 2) - (height / 2))
root.geometry(f'{width}x{height}+{x}+{y}')
root.resizable(width=False, height=False)
root['background'] = '#666666'
app = App(root)
app.pack()
root.mainloop()
Могу предложить посмотреть в сторону functools.partial — это метод из стандартной либы, которым можно воспользоваться, что бы создать что-то вроде замыкания.
Если проще, то можно зафиксировать аргументы функции как в lambda, но при этом сразу ссылаться на конкретную реализацию.
Небольшой пример:
import tkinter as tk
from functools import partial
def set_value():
value = entry.get()
button.config(command=partial(print_value, value))
def print_value(value):
label.config(text=f"value: {value}")
root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
tk.Button(root, text="Запомнить value!", command=set_value).pack()
button = tk.Button(root, text="Вывести value")
button.pack()
label = tk.Label(root, text="value: ")
label.pack()
root.mainloop()
Есть еще один слегка безумный вариант, помима глобальной переменной, приведу его просто в качестве шутки:
import tkinter as tk
def set_value():
value = entry.get()
print_value.value=value
def print_value():
label.config(text=f"value: {print_value.value}")
root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
tk.Button(root, text="Запомнить value!", command=set_value).pack()
button = tk.Button(root, text="Вывести value", command=print_value)
button.pack()
label = tk.Label(root, text="value: ")
label.pack()
root.mainloop()
Так как функции, это ничто иное как класс, то можно добавлять им любые новые паля и хранить там что угодно.
Исправил! Теперь работает как нужно и все передается!
import tkinter as tk
from tkinter import ttk
def changer(*args):
units_get = str(units.get())
entry = float(entry_a.get())
if units_get == 'нед.':
entry *= 7 / float(30.416)
entry = round(entry, 2)
ttk.Label(changed_units, style='changed_units.TLabel', text=f'-> {entry} мес.').place(x=0, y=3)
elif units_get == 'мес.':
for widget in changed_units.winfo_children():
widget.destroy()
elif units_get == 'годы':
entry *= float(30.416)
entry = round(entry, 2)
ttk.Label(changed_units, style='changed_units.TLabel', text=f'-> {entry} мес.').place(x=0, y=3)
return entry
def analyse(*args):
entry = changer()
var_a = float(entry)
var_b = float(b.get())
score = var_a + var_b
print(score)
app = tk.Tk()
app.title('changer')
width = 300
height = 100
x = int((app.winfo_screenwidth() / 2) - (width / 2))
y = int((app.winfo_screenheight() / 2) - (height / 2))
app.geometry(f'{width}x{height}+{x}+{y}')
app.resizable(width=False, height=False)
app['background'] = '#666666'
ttk.Style().configure('changed_units.TLabel', font=('Tahoma', 8),
foreground='#ffffff', background='#666666', border=0)
changed_units = tk.Frame(app, bg='#666666')
changed_units.place(x=80, y=50, height=25, width=100)
units = ttk.Combobox(app, state='readonly', values=['нед.', 'мес.', 'годы'])
units.place(x=10, y=50, height=25, width=60)
units.current(1)
units.bind('<<ComboboxSelected>>', changer)
a = tk.StringVar()
entry_a = ttk.Entry(app, textvariable=a)
entry_a.place(x=10, y=12, height=25, width=60)
b = tk.StringVar()
entry_b = ttk.Entry(app, textvariable=b)
entry_b.place(x=80, y=12, height=25, width=60)
ttk.Button(app, text='Анализ', command=analyse).place(x=220, y=10, height=30, width=60)
app.mainloop()
Если я правильно все понял, ошибка возникала из-за того, что нужно было расширить количество параметров передаваемых функциям changer и analyse, поэтому переменная entry терялась. Поправьте, если ошибаюсь.
И еще вариант, в котором вообще не нужна передача из одной функции в другую, но, работает точно так же.
import tkinter as tk
from tkinter import ttk
def units_indicator(event):
entry = float(entry_a.get())
units_get = str(units.get())
if units_get == 'нед.':
entry *= 7 / float(30.416)
entry = round(entry, 2)
ttk.Label(changed_units, style='changed_units.TLabel', text=f'-> {entry} мес.').place(x=0, y=3)
elif units_get == 'мес.':
for widget in changed_units.winfo_children():
widget.destroy()
elif units_get == 'годы':
entry *= float(30.416)
entry = round(entry, 2)
ttk.Label(changed_units, style='changed_units.TLabel', text=f'-> {entry} мес.').place(x=0, y=3)
def analyse():
entry = float(entry_a.get())
units_get = str(units.get())
if units_get == 'нед.':
entry *= 7 / float(30.416)
entry = round(entry, 2)
elif units_get == 'мес.':
entry = float(entry_a.get())
elif units_get == 'годы':
entry *= float(30.416)
entry = round(entry, 2)
var_a = float(entry)
var_b = float(b.get())
score = var_a + var_b
print(score)
app = tk.Tk()
app.title('changer')
width = 300
height = 100
x = int((app.winfo_screenwidth() / 2) - (width / 2))
y = int((app.winfo_screenheight() / 2) - (height / 2))
app.geometry(f'{width}x{height}+{x}+{y}')
app.resizable(width=False, height=False)
app['background'] = '#666666'
ttk.Style().configure('changed_units.TLabel', font=('Tahoma', 8),
foreground='#ffffff', background='#666666', border=0)
changed_units = tk.Frame(app, bg='#666666')
changed_units.place(x=80, y=50, height=25, width=100)
units = ttk.Combobox(app, state='readonly', values=['нед.', 'мес.', 'годы'])
units.place(x=10, y=50, height=25, width=60)
units.current(1)
units.bind('<<ComboboxSelected>>', units_indicator)
a = tk.StringVar()
entry_a = ttk.Entry(app, textvariable=a)
entry_a.place(x=10, y=12, height=25, width=60)
b = tk.StringVar()
entry_b = ttk.Entry(app, textvariable=b)
entry_b.place(x=80, y=12, height=25, width=60)
ttk.Button(app, text='Анализ', command=analyse).place(x=220, y=10, height=30, width=60)
app.mainloop()
