Зацикливание на виджеты в PyQt Layout

Мой вопрос несколько связан с получением виджетов макета в PyQT, но это не дубликат. Вместо того, чтобы искать стратегическое представление о том, как это сделать, я пытаюсь понять, каким будет самый идиоматичный и прямой способ сделать это. Поскольку PyQt является довольно точной привязкой API Qt C++, он представляет собой простой способ получить виджеты в макете. Вот та идиома, которую я использовал:

for i in range(layout.count()):
  item = layout.itemAt(i)
  if type(item) == QtGui.QLayoutItem:
    doSomeStuff(item.layout())
  if type(item) == QtGui.QWidgetItem:
doSomething(item.widget())

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

for w in layout.widgets():
  doSomething(w)

Я ошибся? Я скучаю по превосходной идиоме? Это лучший способ перебирать виджеты в PyQt? Я склонен думать в C++, поэтому иногда мне не хватает "очевидных" возможностей языка Python, которые делают вещи лучше. Часть того, что я делаю, - это рекурсивный переход в виджеты с макетами с виджетами с макетами (и т. Д.) Для автоматического подключения к пользовательскому интерфейсу, созданному в Designer во время выполнения. Добавьте в QTabWidgets обработку динамических свойств, установленных в конструкторе, и мой код в основном работает, но он кажется ужасно неуклюжим.

5 ответов

Решение

Вы можете поместить виджеты в генератор следующим образом:

items = (layout.itemAt(i) for i in range(layout.count())) 
for w in items:
   doSomething(w)

Если вы в конечном итоге используете это много, вы можете вставить этот код в функцию генератора:

def layout_widgets(layout):
   return (layout.itemAt(i) for i in range(layout.count()))


for w in layout_widgets(layout):
   doSomething(w)

Это очень поздний ответ, но я подумал, что он может пригодиться для дальнейшего рассмотрения. Я тоже искал ответ на этот вопрос. Но я хотел определить типы виджетов, чтобы справиться с ними соответствующим образом. Вот пример кода того, что я нашел:

for widget in centralwidget.children():
    if isinstance(widget, QLineEdit):
        print "linedit: %s  - %s" %(widget.objectName(),widget.text())

    if isinstance(widget, QCheckBox):
        print "checkBox: %s  - %s" %(widget.objectName(),widget.checkState())

Я надеюсь, что это будет полезно для кого-то когда-нибудь.:)

Просто комментарий,

items = (layout.itemAt(i) for i in range(layout.count())) 
for w in items:
   doSomething(w)

Я попробовал первый ответ, но обнаружил, что он возвращает тип WidgetItem, поэтому я сделал ревизию:

widgets = (layout.itemAt(i).widget() for i in range(layout.count())) 
for widget in widgets:
   if isinstance(widget, QLineEdit):
        print "linedit: %s  - %s" %(widget.objectName(), widget.text())
   if isinstance(widget, QCheckBox):
        print "checkBox: %s  - %s" %(widget.objectName(), widget.checkState())

Нашел способ, если вы можете получить доступ к WindowHandler, вы можете получить словарь всех объектов, просто выполнив:

      widgets = vars(self)

Обратите внимание, что я использую QT Designer (5.12) и у меня нет полного примера, показывающего, как я добавил такие виджеты. Однако вот мой пример:

      from PyQt5.QtWidgets import *
FORM_CLASS, _ = loadUiType(path.join(path.dirname('__file__'), "main.ui"))

class HMIWindowHandler(QMainWindow, FORM_CLASS):
    def __init__(self, parent=None):
        super(HMIWindowHandler, self).__init__(parent)
        QMainWindow.__init__(self)
        self.setupUi(self)

        # Prints out self to prove that it is a Window Handler.
        print(self)
        print(vars(self))

        # The vars function will return all of the items of the window handler as a dict.
        widgets = vars(self)

        # Prints the dict to prove class.
        print(type(widgets))

        # Iterates each key checks for the class type and then prints the objectsName
        for each_key, value_of_key in widgets.items():
            if (value_of_key.__class__.__name__ == 'QPushButton' or value_of_key.__class__.__name__ == 'QLabel'):
                print(value_of_key.objectName())

Результат:

      <views.admin.HMIWindowHandler object at 0x0000017BAC5D9EE0>

dict_items([('centralwidget', <PyQt5.QtWidgets.QWidget object at 0x0000017BAC5D9F70>),
('windows_stacked', <PyQt5.QtWidgets.QStackedWidget object at 0x0000017BAC79A040>),
('brewing', <PyQt5.QtWidgets.QWidget object at 0x0000017BAC79A0D0>), 
('boil_image', <PyQt5.QtWidgets.QLabel object at 0x0000017BAC79A160>)])

<class 'dict'>

boil_image
mash_image

Я считаю, что у вас уже есть простейшее решение этой проблемы. PyQt (и PySide) - это всего лишь обертки вокруг C++ API. Они добавляют больше поддержки Pythonic в нескольких областях - сигналы / слоты, базовые типы, такие как QString и т. Д., Но по большей части все остается точно так же, как в C++ API.

Конечно, это не должно мешать вам создавать свою собственную более питоническую библиотеку.

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