Agregar y eliminar dinámicamente widgets en PyQt

Utilizando PyQt, estoy tratando de crear una interfaz para la cual puedo agregar o eliminar widgets dinámicamente. Quiero definir una clase separada para el widget que se agregará o eliminará. Parece que no puedo obtener el widget que instalo para mostrar dentro de la interfaz principal. Aquí está el código que estoy usando:

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_() 

la cosa es que cuando uso el código siguiente dentro de mi método ‘addWidget’, hace exactamente lo que quiero que haga, pero el método de la clase no parece funcionar.

 z = QtGui.QPushButton(self.scrollAreaWidgetContents) count = self.formLayout.rowCount()) self.formLayout.setWidget(count, QtGui.QFormLayout.LabelRole, z) 

Me pregunto por qué z = Test () no está dando ningún resultado. ¿Algunas ideas? ¡Gracias!

En realidad, funciona. El problema es que su widget de Test tiene un QPushButton sin ningún tipo de gestión de diseño. Por lo tanto, no puede calcular su minimumSize teniendo en cuenta el botón. Cuando coloca ese widget en un diseño, simplemente se reduce a 0 (ya que un QWidget no tiene un QWidget minimumSize predeterminado) y no ve nada.

Tiene dos opciones, ya sea que administre manualmente el diseño e ingrese en un mundo de dolor innecesario, o confía en los administradores de diseño. En general, prefieres este último.

Volvería a escribir su script de esta manera (aunque no estoy seguro de por qué usa QFormLayout , lo dejo como está):

 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_() 

Aquí hay un pequeño cambio que hará que el botón se elimine solo una vez que se haga clic:

 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_() 

De esta manera, no debería filtrarse cuando se elimina y el botón puede usarse para cosas. Sigo este patrón para las barras de progreso por las docenas de descargas y monitoreo de trozos y funciona bien incluso con subprocesos y procesamiento múltiple. Y no los fáciles QThreads …

Si quiere decir, elimine un widget cada vez que haga clic en un botón, o durante cualquier evento de su progtwig, use el método self.yourwidget.deleteLater() : self.yourwidget.deleteLater()

 self.button.clicked.connect(delete_widget); def delete_widget(self): self.widget.deleteLater(); 

self.widget.deleteLater ();

El uso de la función anterior hace que ese widget desaparezca de la aplicación