2013-11-23 16 views

risposta

12

Dipende da cosa si intende per "necessario".

Un'applicazione potrebbe potenzialmente consumare molta memoria se (ad esempio) non si presta attenzione quando si chiudono i widget. Le classi basate su QObject sono progettate per essere (facoltativamente) collegate tra loro in una gerarchia. Quando un oggetto di livello superiore viene eliminato, Qt cancellerà automaticamente anche tutti i suoi oggetti figli. Tuttavia, quando si chiudono i widget (che sono sottoclassi di QObject), la cancellazione automatica avverrà solo se è impostato l'attributo Qt.WA_DeleteOnClose (che, di solito, di solito non lo è).

Per illustrare, provare ripetutamente aprire e chiudere la finestra di dialogo in questo script demo, e vedere come l'elenco globale degli oggetti cresce:

from PyQt4 import QtCore, QtGui 

class Window(QtGui.QWidget): 
    def __init__(self): 
     QtGui.QWidget.__init__(self) 
     self.checkbox = QtGui.QCheckBox('Delete') 
     self.button = QtGui.QPushButton('Open', self) 
     self.button.clicked.connect(self.openDialog) 
     layout = QtGui.QHBoxLayout(self) 
     layout.addWidget(self.checkbox) 
     layout.addWidget(self.button) 

    def openDialog(self): 
     widget = QtGui.QDialog(self) 
     if (self.checkbox.isChecked() and 
      not widget.testAttribute(QtCore.Qt.WA_DeleteOnClose)): 
      widget.setAttribute(QtCore.Qt.WA_DeleteOnClose) 
      for child in self.findChildren(QtGui.QDialog): 
       if child is not widget: 
        child.deleteLater() 
     label = QtGui.QLabel(widget) 
     button = QtGui.QPushButton('Close', widget) 
     button.clicked.connect(widget.close) 
     layout = QtGui.QVBoxLayout(widget) 
     layout.addWidget(label) 
     layout.addWidget(button) 
     objects = self.findChildren(QtCore.QObject) 
     label.setText('Objects = %d' % len(objects)) 
     print(objects) 
     widget.show() 

if __name__ == '__main__': 

    import sys 
    app = QtGui.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(500, 300, 100, 50) 
    window.show() 
    sys.exit(app.exec_()) 

Con PyQt/PySide, ci sono due aspetti per la proprietà degli oggetti: la Parte di Python e parte di Qt. Spesso, la rimozione dell'ultimo riferimento Python a un oggetto non sarà sufficiente per eseguire la pulizia completa, poiché potrebbe esserci ancora un riferimento sul lato Qt.

In generale, Qt tende non agli oggetti di eliminazione implicita. Pertanto, se l'applicazione crea e rimuove molti QObjects (o apre e chiude molti QWidgets), è possibile che esegua le operazioni necessarie per eliminarli esplicitamente se l'utilizzo della memoria è un problema.

UPDATE:

solo per aggiungere ai punti di cui sopra sulla proprietà oggetto. A volte, è possibile mantenere un riferimento Python ad un oggetto, mentre la parte Qt viene cancellata. Quando questo accade, si vedrà un errore come questo:

RuntimeError: underlying C/C++ object has been deleted

Di solito, la documentazione Qt vi darà alcuni suggerimenti su quando questo potrebbe accadere. Per esempio, QAbstractItemView.setModel dà questo avvertimento:

The view does not take ownership of the model unless it is the model's parent object...

Questo vi sta dicendo che è necessario sia mantenere un riferimento Python per l'oggetto, o passare un oggetto padre adatto alla costruzione dell'oggetto, perché Qt non sempre Reparent automaticamente .

+0

grazie per aver spiegato. – iMath

+1

1) Penso che non ci siano differenze nella parte PyQt/PySide o Python, finché l'oggetto è referenziato, non verrà ripulito. Non lo credi? 2) Inoltre, WA_DeleteOnClose è adatto per widget che possiamo chiudere, ma per QOBject come QNetworkReply e QDialog qui chiuso ma non viene eliminato, deleteLater() è appropriato, giusto? – iMath

+0

@ user1485853. (1) Sì, ma vedere l'aggiornamento alla mia risposta per un'eccezione importante. (2) Sì, 'WA_DeleteOnClose' è solo un esempio comune di quando le cose _might_ non vengono ripulite correttamente.Per QOjects, se non hanno un genitore, e nessun riferimento a python, saranno automaticamente raccolti dalla garbage (eventualmente) - quindi non c'è bisogno di deleteLater(). In generale, non preoccuparti troppo dell'eliminazione esplicita degli oggetti: fai attenzione a "premature optimimization"! Solo preoccuparsi di questi problemi quando si hanno prove _real_ che stanno causando un problema. – ekhumoro

0

Un'applicazione deleteLater può essere la pulizia di te stesso, ovvero la pianificazione di un'eliminazione di un oggetto QO (ad esempio nel threading) per liberare risorse dall'interno dell'oggetto stesso.

Qui per example qualcuno lo sta utilizzando in connessione con il segnale thread.finished. Potrebbe essere limitato ai casi con segnalazione pesante però.