2011-12-28 45 views
12

usando PyQt, estoy tratando de crear una interfaz para la cual pueda 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 instauro para mostrar dentro de la interfaz principal. Aquí está el código que estoy utilizando:agregando y eliminando widgets dinámicamente en 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_() 

la cosa es, cuando se utiliza el código de abajo en el interior de mi método de 'addWidget', que hace exactamente lo que yo quiero que haga, pero el método de la clase no parece que funciona

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!

Respuesta

12

En realidad, funciona. El problema es que su widget Test tiene un QPushButton sin ninguna administració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 contrae a 0 (ya que QWidget no tiene el valor predeterminado minimumSize) y no ve nada.

Tiene dos opciones, ya sea que administre el diseño manualmente y entre en un mundo de dolor innecesario, o confíe en los administradores de diseño. En general, deberías preferir este último.

Me gustaría volver a escribir el guión como este (Aunque no estoy seguro de por qué se utiliza 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_() 
+0

¡Gracias por la respuesta detallada! La razón por la que estaba usando Form Layout fue porque quería que los widgets comenzaran a aparecer en la parte superior del área de desplazamiento y llene los lugares vacíos desde allí, en lugar de aparecer en el medio y reorganizarse a medida que se crean los nuevos widgets. Aunque estoy seguro de que hay otras formas de hacerlo, formlayout me pareció una solución fácil ... ¡Gracias de nuevo! – boundless

+0

@boundless: Ah, ya veo. Mi acercamiento a eso sería envolviendo 'scrollLayout' en otro' QVBoxLayout' con un tramo de '1' añadido debajo de eso. Eso debería mantener las cosas en la parte superior. – Avaris

+0

otra cosa que me gusta es la configuración, es más fácil tener dos widgets uno junto al otro y mantener las cosas en la parte superior ... Aunque tal vez en ese punto, debería usar el diseño de la cuadrícula. Gracias de nuevo por la pista! – boundless

4

Aquí hay un pequeño cambio que hará que el botón de borrarse a sí mismo una vez que ha hecho 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 mem fugas cuando se elimina y el botón se puede utilizar realmente para la materia. Sigo este patrón de barras de progreso por docenas para la monitorización de descargas y fragmentos y funciona bien incluso con subprocesamiento y procesamiento múltiple. Y no los QThreads fáciles ...

+3

¿Qué parte ha cambiado y por qué tiene este efecto? –

0

Si quieres decir, eliminar un widget cada vez que se hace clic en un botón, o durante cualquier evento de ur programa, utilice el método 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 el widget desaparece de la aplicación

Cuestiones relacionadas