Nyoa
Nyoa

Reputation: 195

Pyqt widget lingers after being removed

I have a QVBox layout that houses a QVBox layout and a QHBox layout. I use the other QVBox layout to hold dynamically created GUI objects and the QHBox layout to hold the buttons that add/remove those objects. Everything works correctly if I position the QHBox on top of the QVBox, but when I try to position the QHBox beneath the QVBox the objects aren't removed correctly but stay there "lingering" on top of the QHBox. I'll upload pictures to demonstrate the problem. First picture is before taking action, second is after creating a new object and third is after deleting the object

Before action

After creating new component

After deleting the component

Here is the code that creates and deletes the new objects

    def addClient(self):
            if (len(self.clients) < 5):
                    client = clientComponent(self)
                    self.clients.append(client)
                    index = len(self.clients)-1
                    self.vLayout3.addWidget(self.clients[index])

                    client.setIndex(index)

                    self.clients[index].startButton.clicked.connect(partial(self.threadcontrol, '2', client.getIndex()))
                    self.clients[index].stopButton.clicked.connect(partial(self.clientstop, '0', client.getIndex()))

    def deleteClient(self):
            if (len(self.clients) > 1):
                    self.vLayout3.removeWidget(self.clients.pop())

This is where I complete the layout

    def initializeUi(self):

            self.mainWidget = QWidget(self)
            self.setCentralWidget(self.mainWidget)

            self.mainLayout = QVBoxLayout(self.mainWidget)
            self.hLayout1 = QHBoxLayout()
            self.hLayout2 = QHBoxLayout()
            self.vLayout1 = QVBoxLayout()
            self.vLayout2 = QVBoxLayout()
            self.vLayout3 = QVBoxLayout()

            self.addServer()
            self.addClient()

            self.serverBox = QGroupBox('Server')
            self.clientBox = QGroupBox('Client')

            self.traffic1 = QLabel('0.0Mb/s', self)
            self.traffic1.setAlignment(Qt.AlignRight)
            self.traffic2 = QLabel('0.0Mb/s', self)
            self.traffic2.setAlignment(Qt.AlignCenter)
            self.traffic3 = QLabel('0.0Mb/s', self)
            self.traffic3.setAlignment(Qt.AlignLeft)

            self.newClientButton = QPushButton('+', self)
            self.deleteClientButton = QPushButton('-', self)

            self.hLayout1.addWidget(self.traffic1)
            self.hLayout1.addWidget(self.traffic2)
            self.hLayout1.addWidget(self.traffic3)
            self.hLayout2.addWidget(self.newClientButton)
            self.hLayout2.addWidget(self.deleteClientButton)
            self.vLayout2.addLayout(self.vLayout3)
            self.vLayout2.addLayout(self.hLayout2)

            self.mainLayout.addWidget(self.plot)
            self.mainLayout.addLayout(self.hLayout1)
            self.serverBox.setLayout(self.vLayout1)
            self.mainLayout.addWidget(self.serverBox)
            self.clientBox.setLayout(self.vLayout2)
            self.mainLayout.addWidget(self.clientBox)

Upvotes: 0

Views: 1687

Answers (2)

user3419537
user3419537

Reputation: 5000

This is happening because your main window remains the parent of the client widgets after you remove them from the layout. You will see similar behaviour if you assign a widget a parent widget without adding it to any layout.

Removing the parent should resolve the issue.

def deleteClient(self):
    if (len(self.clients) > 1):
        client = self.clients.pop()
        self.vLayout3.removeWidget(client)
        client.setParent(None)

You may also need to make a call to adjustSize to resize the window to fit the remaining widgets

Upvotes: 3

robyschek
robyschek

Reputation: 2035

When you delete a widget from layout it still remains in parent widget's object tree, so it gets displayed outside of any layout. To remove a widget from the object tree call widget.setParent(None). widget.deleteLater() also works.
Here is my MCVE(Qt4, Py2.7):

from PyQt4.QtGui import (QApplication, QWidget, QPushButton,
                         QVBoxLayout, QHBoxLayout)

app=QApplication([])

self = QWidget()
main_layout = QVBoxLayout(self)

clients = []
l2 = QHBoxLayout()
main_layout.addLayout(l2)

b_add = QPushButton('add', self)
l2.addWidget(b_add)

def addClient():
    b = QPushButton(str(len(clients)), self)
    clients.append(b)
    main_layout.addWidget(b)
b_add.clicked.connect(addClient)

b_rm = QPushButton('rm', self)
l2.addWidget(b_rm)

def deleteClient():
    b = clients.pop()
    main_layout.removeWidget(b)
    # comment out two following lines to get the behavior you observe
    b.setParent(None)
    self.adjustSize()
b_rm.clicked.connect(deleteClient)


self.show()
app.exec_()

On my system I also have to call self.adjustSize() after deletion to resize the main window

Upvotes: 1

Related Questions