2011-12-28 10 views
12

usando PyQt, sto cercando di creare un'interfaccia per la quale posso aggiungere o rimuovere widget in modo dinamico. Voglio definire una classe separata per il widget che verrà aggiunto o rimosso. Non riesco a essere in grado di ottenere il widget che istanziato per visualizzare all'interno dell'interfaccia principale. Ecco il codice che sto usando:aggiungendo e rimuovendo dinamicamente i widget in 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 è, quando uso il codice qui sotto dentro il mio metodo 'addWidget', che fa esattamente quello che voglio fare, ma il metodo di classe non lo fa sembra funzionare.

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

Mi chiedo perché z = Test() non sta dando alcun risultato? Qualche idea? Grazie!

risposta

12

In realtà, funziona. Il problema è che il tuo widget Test ha un QPushButton senza alcuna gestione del layout. Quindi non può calcolare il suo minimumSize tenendo in considerazione il pulsante. Quando metti quel widget in un layout, si riduce a 0 (dal momento che un QWidget non ha il valore predefinito minimumSize) e non vedi nulla.

Hai due scelte: gestisci manualmente il layout e entri in un mondo di dolore inutile, oppure ti affidi ai gestori di layout. In generale, dovresti preferire quest'ultimo.

vorrei riscrivere lo script come questo (Anche se io non sono sicuro perché si utilizza QFormLayout, lo lascio così com'è.):

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

Grazie per la risposta dettagliata! Il motivo per cui stavo usando il layout del modulo era che volevo che i widget iniziassero a comparire nella parte superiore dell'area di scorrimento e riempire i posti vuoti da lì, invece di apparire al centro e riorganizzarsi quando vengono creati i nuovi widget. Anche se sono sicuro che ci sono altri modi per farlo, formlayout mi è sembrato una soluzione facile per me .. Grazie ancora! – boundless

+0

@boundless: Ah, capisco. Il mio approccio sarebbe quello di avvolgere 'scrollLayout' in un altro' QVBoxLayout' con un tratto di '1' aggiunto sotto. Questo dovrebbe mantenere le cose al top. – Avaris

+0

un'altra cosa che mi piace per la creazione di form, è che rende più facile avere due widget l'uno accanto all'altro, pur mantenendo le cose al top .. Anche se forse a quel punto, dovrei semplicemente usare il layout della griglia. Grazie ancora per il suggerimento! – boundless

4

Ecco un piccolo cambiamento che farà la pulsante elimina per sé, una volta cliccato:

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

in questo modo non dovrebbe mem perdite quando cancellato e il pulsante può effettivamente essere usato per cose. Seguo questo schema per le barre di avanzamento delle dozzine per il download e il controllo dei chunk e funziona perfettamente anche con il threading e il multi processing. E non le qthreads facile ...

+3

Quale parte hai cambiato e perché ha questo effetto? –

0

Se u vuole dire eliminare un widget ogni volta che si fa clic su un pulsante, o durante qualsiasi evento di ur programma, utilizzare il metodo deleteLater(): self.yourwidget.deleteLater()

self.button.clicked.connect(delete_widget); 

def delete_widget(self): 
    self.widget.deleteLater(); 

self.widget.deleteLater();

Utilizzando la funzione di cui sopra fa quel widget dissappear dall'applicazione

Problemi correlati