Зацикливание на виджеты в 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.
Конечно, это не должно мешать вам создавать свою собственную более питоническую библиотеку.