Генерируйте кнопки программно в PyQT

Мне нужно сгенерировать кнопки в цикле и внутри этого цикла назначить каждой кнопке отдельную задачу.
Я знаю, что что-то подобное уже задавалось, и, выполнив поиск, я получил следующий код:

def pressed_0():
    print(0)

def pressed_1():
    print(1)

def pressed_2():
    print(2)

for i in range(0,3):
    setattr(self,f"pressed_{i}", qtw.QPushButton(f"button {i}"))
    exec(f"self.pressed_{i}.clicked.connect(lambda:pressed_{i}())")                
    self.layout().addWidget(getattr(self, f"pressed_{i}"))  

Что мне не очень нравится, так это использование функции exec() и setattr/getattr. Что я спрашиваю, есть ли лучший способ выполнить то, что мне нужно.

Используй словарь

eyllanesc 18.04.2024 15:33

почему не список?

pippo1980 18.04.2024 15:39

согласно комментарию @eyllanesc, см. stackoverflow.com/a/74320664/9877065 Добавьте динамически виджет в цикл и получите его имя, pyQt5

pippo1980 18.04.2024 15:39

является ли self.layout.addWidget(button) решением? так что нет необходимости в otf dict или list ?? см. ответ ниже stackoverflow.com/a/78348030/9877065

pippo1980 18.04.2024 22:01

Как написал Махкита в своем ответе, нет абсолютно ничего плохого в использовании getattr() и setattr(), а exec() всегда следует избегать. Кроме того, его использование в вашем коде совершенно ненужно. Соединения сигналов редко выполняются с помощью чистых функций (обычное использование основано на членах экземпляра), но если вам действительно нужен доступ к таким функциям (и если вы очень осторожны с именами), вам следует предпочесть использовать globals()['someFunction'] для глобальных функции или locals()['someFunction'] для локальных.

musicamante 18.04.2024 22:20

Также обратите внимание: если вам специально не нужен доступ к именам этих кнопок (из-за жестко закодированных ссылок или снова через getattr()) в другой части вашего кода, вам, вероятно, вообще не нужно использовать setattr(): просто создайте локальную переменную и работайте с этим, как только виджет добавляется к родительскому элементу (как вы делаете с макетом addWidget()), вам не нужно заботиться ни об атрибуте экземпляра, ни о возможной сборке мусора, потому что с этого момента родительский элемент имеет стал владельцем этого виджета (на стороне C++), и Python его точно не удалит.

musicamante 18.04.2024 22:23
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
6
88
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Всегда следует избегать использования exec(). Хотя в getattr() нет ничего плохого.
Если вы хотите получать задачи для кнопок динамически, на основе индекса цикла, без использования getattr не обойтись.

Вот рабочий пример с альтернативой без getattr:

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout

class Window(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout(self)
        self.buttons = []

        for i in range(3):
            but = QPushButton(f'button {i}')
            func = getattr(self, f'pressed_{i}')
            but.clicked.connect(func)
            layout.addWidget(but)
            self.buttons.append(but)

        # alternative without getattr:
        self.button_tasks = (
            self.pressed_0,
            self.pressed_1,
            self.pressed_2,
        )
        for i, func in enumerate(self.button_tasks):
            but = QPushButton(f'button {i}')
            but.clicked.connect(func)
            layout.addWidget(but)
            self.buttons.append(but)

    @staticmethod
    def pressed_0():
        print(0)

    @staticmethod
    def pressed_1():
        print(1)

    @staticmethod
    def pressed_2():
        print(2)


app = QApplication([])
window = Window()
window.show()
app.exec_()

При использовании альтернативного метода задачам не обязательно иметь определенное имя и даже не обязательно быть методами класса.

Почему в обоих примерах вы используете строку self.buttons.append(but)? Кажется, это бесполезно

Ferex 19.04.2024 10:36

@Ferex, это на тот случай, если позже тебе понадобится доступ к кнопкам. Если вы этого не сделаете, вы можете опустить список кнопок.

mahkitah 19.04.2024 11:06

Допустим, вы хотите отключить кнопку 1, вы можете это сделать self.buttons[1].setEnabled(False)

mahkitah 19.04.2024 11:11

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

Похожие вопросы

Как интегрировать комментарии к столбцам Oracle в LangChain для расширенной генерации SQL-запросов (NL2SQL)?
Проблема с настройкой Llama-2 в Google Colab. Ошибка запуска ячейки при загрузке фрагментов контрольной точки
Python x в y в z
При загрузке фотографии возвращается сообщение «Недопустимый тип элемента»
Python находит индекс элемента в списке на основе оценки функции
Как заставить диалоговую поисковую цепочку включать метаданные в приглашение, используя langchain с chromadb, чтобы LLM знал о метаданных?
Название: Как визуализировать иерархические данные с помощью вложенных круговых диаграмм в Python?
На устройстве не осталось места при развертывании точно настроенной модели с помощью SageMaker
Многопроцессорность с функцией-оберткой дает странное поведение
Объект серии Python TypeError не может интерпретироваться как целое число при запуске функции в фрейме данных