Как вызвать функцию из функции в классе, который вызывается с помощью кнопки с лямбдой в Python3x?

У меня есть класс: MyClassName, например, с двумя функциями: одна для вычисления числа и одна для проверки того, все ли группы полей со списком (tkinter) имеют выбор. Я также использую tkinter для кнопки для вызова функции расчета с использованием лямбды, потому что я хочу, чтобы пользователь делал выбор в поле со списком, а затем нажимал кнопку расчета, отсюда и необходимость в лямбде.

Вот код кнопки:

# Calculate Button
        self.calculate_button = ttk.Button(button_frame,  
                            command = lambda: calculate(self),  # Use a lambda to send params to the function for command.
                            width = 12, 
                            text = "CALCULATE",
                            bootstyle = 'primary', 
                            state = 'enabled') 
# In the calculate function, I call another function:
def calculate(self):
            # Call the Class function from within another Class function.
            self.validate_Comboboxes() ...

А в функции validate_Comboboxes я использую что-то вроде этого:

 # Function to validate if all the Comboboxes were selected.
        def validate_Comboboxes(self):
           for widget in self.base_frame.winfo_children():
                if isinstance(widget, ttk.Combobox) and widget.get() == "":
                    messagebox.showerror("error", "All Comboboxes for the base frame must be selected for calculations!")
                    break
                    ...

Я тестировал функцию validate_Comboboxes отдельно вне этого приложения и знаю, что она работает. Однако я получаю эту ошибку: AttributeError: объект MyClassName не имеет атрибута validate_Comboboxes. Кажется, у меня это неправильно объявлено? Я понимаю, что если бы это был просто атрибут класса, вы бы использовали: myAttribute(self) для его объявления, но validate_Comboboxes(self) не имеет для меня смысла, поскольку я объявляю его с помощью своего оператора def, если только я что-то не упускаю?

Каков правильный способ закодировать это для моего варианта использования, главным образом для проверки того, что пользователь выбрал все поля со списком, прежде чем он нажмет кнопку расчета?

Я подумал, что если бы у вас было две функции внутри класса, например functionA(self) и functionB(self), вы могли бы вызвать функциюA из функцииB с помощью self.function(). Так является ли здесь проблемой механизм использования кнопки с лямбдой?

Лучше предоставить минимально воспроизводимый пример вместо блоков кода.

acw1668 18.06.2024 04:36

Если вы не отправляете данные в метод calculate, то lambda вам не нужен. Попробуйте изменить command = lambda: calculate(self) на command = self.calculate

Derek 18.06.2024 04:48

acw1668 Да, я согласен, но я не могу показать большую часть кода, потому что это рабочий проект. Я пытаюсь показать ровно столько, чтобы мои проблемы были описаны здесь.

James-Jesse Drinkard 19.06.2024 02:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Используя код предыдущих вопросов в качестве контекста, вы испытываете эти ошибки из-за области, в которой вы определяете свои функции validateComboboxes, calculate и clear.

Учитывая следующее, это обобщенная версия вашего кода...

class ComboBoxTestGroup:
    def __init__(self, master):
        ...
        ...
        
        def calculate(self):
            ...
        def clear(self):
            ...
        def validateComboboxes(self):
            ...

Поскольку три ранее упомянутые функции определены внутри тела метода __init__, эти функции не привязаны к экземпляру ComboBoxTestGroup и доступны только для кода, который выполняется в области действия методов __init__. Это, а также тот факт, что вы используете лямбду, которая будет оцениваться во время выполнения, означает, что когда вы попытаетесь вызвать calculate(self), определение функции больше не будет существовать.

Есть очень простое решение. Определите свои методы в теле/области класса вместо метода __init__. Это гарантирует, что функции будут привязаны к экземпляру класса и останутся доступными для вызова в течение всего времени существования объекта экземпляра.

Пример:

import tkinter
from tkinter import *
from tkinter import messagebox
from tkinter.ttk import Combobox
import ttkbootstrap as ttk
from ttkbootstrap.constants import *

window = ttk.Window(themename = 'superhero')
window.title('Combobox Test Group')
window.geometry('1200x275')

class ComboBoxTestGroup:
    def __init__(self, master):

        # Create the main frame.
        self.main_frame = ttk.Frame(master, relief=SUNKEN, borderwidth=1)
        self.main_frame.grid(row=0, column=0)

        # Dropdowns
        self.base_frame = tkinter.LabelFrame(self.main_frame, text='BASE', relief=SUNKEN, borderwidth=1)
        self.base_frame.grid(row=4, column=0, sticky = "news", padx=10, pady=15)

        self.base_label_ti = ttk.Label(self.base_frame, text='Technical Interface (TI)', font=('Helvetica', 10))
        self.base_label_ti.grid(row=0, column=0)

        self.ti_values = [("High", "H", "1.0"), ("Medium", "M", "0.5"), ("Low", "L", "0.1"),  ("None", "N", "0.0")]
        self.ti_combobox = ttk.Combobox(self.base_frame, bootstyle='primary', values=self.ti_values, state = 'readonly')
        self.ti_combobox.grid(row=1, column=0)

        self.base_label_ap = ttk.Label(self.base_frame, text='Application Project (AP)', font=('Helvetica', 10))
        self.base_label_ap.grid(row=0, column=1)

        self.ap_values = [("High", "H", "1.0"), ("Medium", "M", "0.5"), ("Low", "L", "0.1"),  ("None", "N", "0.0")]
        self.ap_combobox = ttk.Combobox(self.base_frame, bootstyle='primary', values=self.ap_values, state = 'readonly')
        self.ap_combobox.grid(row=1, column=1)

        self.base_label_al = ttk.Label(self.base_frame, text='Application Logs (AL)', font=('Helvetica', 10))
        self.base_label_al.grid(row=0, column=2)

        self.al_values = [("High", "H", "1.0"), ("Medium", "M", "0.5"), ("Low", "L", "0.1"),  ("None", "N", "0.0")]
        self.al_combobox = ttk.Combobox(self.base_frame, bootstyle='primary', values=self.al_values, state = 'readonly')
        self.al_combobox.grid(row=1, column=2)

        self.base_label_ic = ttk.Label(self.base_frame, text='Internal Composition (IC)', font=('Helvetica', 10))
        self.base_label_ic.grid(row=0, column=3)

        self.ic_values = [("High", "H", "1.0"), ("Medium", "M", "0.5"), ("Low", "L", "0.1"),  ("None", "N", "0.0")]
        self.ic_combobox = ttk.Combobox(self.base_frame, bootstyle='primary', values=self.ic_values, state = 'readonly')
        self.ic_combobox.grid(row=1, column=3)

        self.base_label_fc = ttk.Label(self.base_frame, text='Fixed Controls (FC)', font=('Helvetica', 10))
        self.base_label_fc.grid(row=0, column=4)

        self.fc_values = [("High", "H", "1.0"), ("Medium", "M", "0.5"), ("Low", "L", "0.1"),  ("None", "N", "0.0")]
        self.fc_combobox = ttk.Combobox(self.base_frame, bootstyle='primary', values=self.fc_values, state = 'readonly')
        self.fc_combobox.grid(row=1, column=4)

        # For loop to space widgets within the base_frame
        for widget in self.base_frame.winfo_children():
            widget.grid_configure(padx=20, pady=10)

        # Create a frame for the buttons.
        button_frame = ttk.Frame(self.main_frame, relief=SUNKEN, borderwidth=1)
        button_frame.grid(row=5, column=0)

        # Validate Button
        self.calculate_button = ttk.Button(button_frame,
                            command = self.calculate,  # no need for lambda
                            width = 12,
                            text = "VALIDATE",
                            bootstyle = 'primary',
                            state = 'enabled')

        self.calculate_button.grid(row=10, column=0, padx=75, pady=10)

        # Clear Button
        self.clear_button = ttk.Button(button_frame,
                            command=self.clear,  # no need for lambda
                            width = 12,
                            text = "CLEAR",
                            bootstyle = 'primary',
                            state = 'enabled')
        self.clear_button.grid(row=10, column=1, padx=75, pady=10)

    def calculate(self):
        self.validateComboboxes()

    # Function to clear the ttk widgets.
    def clear(self):
        # This clears the Comboboxes by the enclosing frame.
        for widget in self.base_frame.winfo_children():
            if isinstance(widget, ttk.Combobox):
                widget.set("")

                # Function to validate if all the Comboboxes were selected.
    def validateComboboxes(self):
        for widget in self.base_frame.winfo_children():
            if isinstance(widget, ttk.Combobox) and widget.get() == "":
                messagebox.showerror("error", "All Comboboxes must be selected in order to do calculations!")

widget_class = ComboBoxTestGroup(window)

# Run the GUI
window.mainloop()

Выручил меня снова! Хорошо, я проведу дополнительные исследования, поскольку tkinter более сложен, чем я думал. Я еще не до конца усвоил эту концепцию. Хотя спасибо за объяснение.

James-Jesse Drinkard 19.06.2024 02:36

Другие вопросы по теме