Динамическое добавление и удаление виджетов в PyQt
используя PyQt, я пытаюсь создать интерфейс, для которого я могу добавить или удалить виджет динамически. Я хочу определить отдельный класс для виджета, который будет добавлен или удален. Кажется, я не могу получить виджет, который я создаю для отображения внутри основного интерфейса. Вот код, который я использую:
from PyQt4 import QtGui, QtCore
import sys
class Main(QtGui.QMainWindow):
def __init__(self, parent = None):
super(Main, self).__init__(parent)
# central widget
self.centralWidget = QtGui.QWidget(self)
# main layout
self.vLayout = QtGui.QVBoxLayout(self.centralWidget)
# main button
self.pButton_add = QtGui.QPushButton(self.centralWidget)
self.pButton_add.setText('button to add other widgets')
# scroll area
self.scrollArea = QtGui.QScrollArea(self.centralWidget)
self.scrollArea.setWidgetResizable(True)
# scroll area widget contents
self.scrollAreaWidgetContents = QtGui.QWidget(self.scrollArea)
# scroll area widget contents - layout
self.formLayout = QtGui.QFormLayout(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
# add all main to the main vLayout
self.vLayout.addWidget(self.pButton_add)
self.vLayout.addWidget(self.scrollArea)
# set central widget
self.setCentralWidget(self.centralWidget)
# connections
self.pButton_add.clicked.connect(self.addWidget)
def addWidget(self):
z = Test(self.scrollAreaWidgetContents)
count = self.formLayout.rowCount()
self.formLayout.setWidget(count, QtGui.QFormLayout.LabelRole, z)
class Test(QtGui.QWidget):
def __init__( self, parent):
super(Test, self).__init__(parent)
self.pushButton = QtGui.QPushButton(self)
app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()
Дело в том, что, когда я использую приведенный ниже код внутри моего метода addWidget, он точно выполняет то, что я хочу, но метод класса не работает.
z = QtGui.QPushButton(self.scrollAreaWidgetContents)
count = self.formLayout.rowCount())
self.formLayout.setWidget(count, QtGui.QFormLayout.LabelRole, z)
Интересно, почему z = Test() не дает никаких результатов? Есть идеи? Спасибо!
Ответы
Ответ 1
Собственно, он работает. Проблема в том, что ваш виджет Test
имеет QPushButton
без управления компоновкой. Поэтому он не может рассчитать свой minimumSize
с учетом кнопки. Когда вы помещаете этот виджет в макет, он просто сжимается до 0
(так как QWidget
не имеет значения по умолчанию minimumSize
), и вы ничего не видите.
У вас есть два варианта: вы вручную управляете макетом и вводите ненужный мир боли, или полагаетесь на менеджеров макетов. В общем, вы должны предпочесть последний.
Я бы переписал ваш script следующим образом (хотя я не уверен, почему вы используете QFormLayout
, я оставляю его как есть.):
from PyQt4 import QtGui, QtCore
import sys
class Main(QtGui.QMainWindow):
def __init__(self, parent = None):
super(Main, self).__init__(parent)
# main button
self.addButton = QtGui.QPushButton('button to add other widgets')
self.addButton.clicked.connect(self.addWidget)
# scroll area widget contents - layout
self.scrollLayout = QtGui.QFormLayout()
# scroll area widget contents
self.scrollWidget = QtGui.QWidget()
self.scrollWidget.setLayout(self.scrollLayout)
# scroll area
self.scrollArea = QtGui.QScrollArea()
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setWidget(self.scrollWidget)
# main layout
self.mainLayout = QtGui.QVBoxLayout()
# add all main to the main vLayout
self.mainLayout.addWidget(self.addButton)
self.mainLayout.addWidget(self.scrollArea)
# central widget
self.centralWidget = QtGui.QWidget()
self.centralWidget.setLayout(self.mainLayout)
# set central widget
self.setCentralWidget(self.centralWidget)
def addWidget(self):
self.scrollLayout.addRow(Test())
class Test(QtGui.QWidget):
def __init__( self, parent=None):
super(Test, self).__init__(parent)
self.pushButton = QtGui.QPushButton('I am in Test widget')
layout = QtGui.QHBoxLayout()
layout.addWidget(self.pushButton)
self.setLayout(layout)
app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()
Ответ 2
Вот небольшое изменение, которое заставит кнопку удалять себя после нажатия:
from PyQt4 import QtGui, QtCore
import sys
class Main(QtGui.QMainWindow):
def __init__(self, parent = None):
super(Main, self).__init__(parent)
# main button
self.addButton = QtGui.QPushButton('button to add other widgets')
self.addButton.clicked.connect(self.addWidget)
# scroll area widget contents - layout
self.scrollLayout = QtGui.QFormLayout()
# scroll area widget contents
self.scrollWidget = QtGui.QWidget()
self.scrollWidget.setLayout(self.scrollLayout)
# scroll area
self.scrollArea = QtGui.QScrollArea()
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setWidget(self.scrollWidget)
# main layout
self.mainLayout = QtGui.QVBoxLayout()
# add all main to the main vLayout
self.mainLayout.addWidget(self.addButton)
self.mainLayout.addWidget(self.scrollArea)
# central widget
self.centralWidget = QtGui.QWidget()
self.centralWidget.setLayout(self.mainLayout)
# set central widget
self.setCentralWidget(self.centralWidget)
def addWidget(self):
self.scrollLayout.addRow(TestButton())
class TestButton(QtGui.QPushButton):
def __init__( self, parent=None):
super(TestButton, self).__init__(parent)
self.setText("I am in Test widget")
self.clicked.connect(self.deleteLater)
app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()
Таким образом, он не должен терять утечку при удалении, и кнопка фактически может использоваться для вещей. Я следую этому шаблону для индикаторов выполнения десятками для мониторинга загрузок и кусков, и он отлично работает даже с поточной обработкой и многопроцессорной обработкой. И не простые QThreads...
Ответ 3
Если вы хотите сказать, удалите виджет всякий раз, когда нажимаете кнопку или во время любого события программы ur, используйте метод deleteLater(): self.yourwidget.deleteLater()
self.button.clicked.connect(delete_widget);
def delete_widget(self):
self.widget.deleteLater();
self.widget.deleteLater();
Использование вышеописанной функции приводит к тому, что виджет исчезает из приложения