0

It's been a while I'm searching all over the internet for that, but still couldn't get the answer... basically I have a QVBoxLayout which contains several frames - and each frame contains a button which function is to delete its parent frame. The main code was created using QT Designer and pyuic4. I wrote the two additional functions, one works perfectly ("createFrame") but I'm struggling with the "deleteFrame" one. the label inside the frame shows the index of that frame in the vert_layout "array". the problem I noted on my code is that, using it that way, I can only delete the last frame added. So, can someone help me with this issue?

please see my code below:

# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
import sys

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
    return QtGui.QApplication.translate(context, text, disambig)

#Custom button that sends out its own instance as the signal
class MyPushButton(QtGui.QPushButton):
    mySignal = QtCore.pyqtSignal(QtGui.QWidget)
    def mousePressEvent(self, *args, **kwargs):
        self.mySignal.emit(self)

class Functions:
    def createFrame(self,mainWindow):
        #just local frame no need to store it in the class
        frame = QtGui.QFrame()
        frame.setGeometry(QtCore.QRect(10, 10, 241, 61))
        frame.setFrameShape(QtGui.QFrame.StyledPanel)
        frame.setFrameShadow(QtGui.QFrame.Raised)
        frame.setObjectName(_fromUtf8("frame"))
        pushButton_2 = MyPushButton(frame)
        pushButton_2.setGeometry(QtCore.QRect(94, 10, 141, 41))
        pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
        label = QtGui.QLabel(frame)
        label.setGeometry(QtCore.QRect(20, 10, 71, 41))
        label.setFrameShape(QtGui.QFrame.NoFrame)
        label.setAlignment(QtCore.Qt.AlignCenter)

        #the vert_layout belongs to class Ui_MainWindow
        mainWindow.vert_layout.addWidget(frame)

        label.setObjectName(_fromUtf8("label"))
        label.setText(str(mainWindow.vert_layout.indexOf(frame)))
        pushButton_2.setText(_translate("MainWindow", "delete this frame and all\n its childs", None))

        pushButton_2.mySignal.connect(self.deleteFrame)

        #my initial idea was to include the mainWindow (instance of 
        #Ui_MainWindow class in order to use vert_layout - but apparently
        #I need to modify the signal as well, right?
    def deleteFrame(self,ref,mainWindow):
        #finding the index of the FRAME (mybutton's parent)
        #that is to be deleted
        frame = mainWindow.vert_layout.itemAt(self.vert_layout.indexOf(ref.parent()))
        widget = frame.widget()
        if widget is not None:
            widget.deleteLater()
class Ui_MainWindow(object):

def setupUi(self, MainWindow):
    MainWindow.setObjectName(_fromUtf8("MainWindow"))
    MainWindow.resize(400, 284)

    self.vert_layout = QtGui.QVBoxLayout()

    self.centralwidget = QtGui.QWidget(MainWindow)
    self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
    self.scrollArea = QtGui.QScrollArea(self.centralwidget)
    self.scrollArea.setGeometry(QtCore.QRect(10, 10, 281, 261))
    self.scrollArea.setWidgetResizable(True)
    self.scrollArea.setObjectName(_fromUtf8("scrollArea"))
    self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
    self.scrollAreaWidgetContents = QtGui.QWidget()
    self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 277, 257))
    self.scrollAreaWidgetContents.setObjectName(_fromUtf8("scrollAreaWidgetContents")) 

    self.scrollAreaWidgetContents.setLayout(self.vert_layout)

    self.scrollArea.setWidget(self.scrollAreaWidgetContents)
    self.pushButton = QtGui.QPushButton(self.centralwidget)
    self.pushButton.setGeometry(QtCore.QRect(310, 20, 75, 23))
    self.pushButton.setObjectName(_fromUtf8("pushButton"))
    MainWindow.setCentralWidget(self.centralwidget)

    self.retranslateUi(MainWindow)
    QtCore.QMetaObject.connectSlotsByName(MainWindow)

    f = Functions()

    self.pushButton.clicked.connect(lambda: f.createFrame())

def retranslateUi(self, MainWindow):
    MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
    self.pushButton.setText(_translate("MainWindow", "create", None))

class Main(QtGui.QMainWindow):
def __init__(self):
    QtGui.QMainWindow.__init__(self)
    self.ui = Ui_MainWindow()
    self.ui.setupUi(self)

if __name__== '__main__':
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
sys.exit(app.exec_())
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

1 Answers1

0

All you are currently doing is deleting the self.frame widget each time. So only the last created one gets deleted. And not the one you actually click on.

Modified your code for what you need. Hope it helps you understand.

# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
import sys

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

#Custom button that sends out its own instance as the signal
class MyPushButton(QtGui.QPushButton):
    mySignal = QtCore.pyqtSignal(QtGui.QWidget)
    def mousePressEvent(self, *args, **kwargs):
        self.mySignal.emit(self)

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(400, 284)

        self.vert_layout = QtGui.QVBoxLayout()

        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.scrollArea = QtGui.QScrollArea(self.centralwidget)
        self.scrollArea.setGeometry(QtCore.QRect(10, 10, 281, 261))
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName(_fromUtf8("scrollArea"))
        self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.scrollAreaWidgetContents = QtGui.QWidget()
        self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 277, 257))
        self.scrollAreaWidgetContents.setObjectName(_fromUtf8("scrollAreaWidgetContents")) 

        self.scrollAreaWidgetContents.setLayout(self.vert_layout)

        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.pushButton = QtGui.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(310, 20, 75, 23))
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.pushButton.clicked.connect(lambda: self.createFrame())

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.pushButton.setText(_translate("MainWindow", "create", None))

    def createFrame(self):
        #just local frame no need to store it in the class
        frame = QtGui.QFrame()
        frame.setGeometry(QtCore.QRect(10, 10, 241, 61))
        frame.setFrameShape(QtGui.QFrame.StyledPanel)
        frame.setFrameShadow(QtGui.QFrame.Raised)
        frame.setObjectName(_fromUtf8("frame"))
        pushButton_2 = MyPushButton(frame)
        pushButton_2.setGeometry(QtCore.QRect(94, 10, 141, 41))
        pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
        label = QtGui.QLabel(frame)
        label.setGeometry(QtCore.QRect(20, 10, 71, 41))
        label.setFrameShape(QtGui.QFrame.NoFrame)
        label.setAlignment(QtCore.Qt.AlignCenter)

        self.vert_layout.addWidget(frame)

        label.setObjectName(_fromUtf8("label"))
        label.setText(str(self.vert_layout.indexOf(frame)))
        pushButton_2.setText(_translate("MainWindow", "delete this frame and all\n its childs", None))

        pushButton_2.mySignal.connect(self.deleteFrame)

    def deleteFrame(self,ref):
        #finding the index of the FRAME (mybutton's parent)
        #that is to be deleted
        frame = self.vert_layout.itemAt(self.vert_layout.indexOf(ref.parent()))
        widget = frame.widget()
        if widget is not None:
            widget.deleteLater()

class Main(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

if __name__== '__main__':
    app = QtGui.QApplication(sys.argv)
    window = Main()
    window.show()
    sys.exit(app.exec_())
smitkpatel
  • 722
  • 6
  • 21
  • thank you so much!! I'll take a look carefully in the code, but this is exactly what I was looking for. although it is working, the error below appears for me: `File "C:\Users\ramonsa\Desktop\ajuda.py", line 24, in mousePressEvent return QtGui.QPushButton.mousePressEvent(self, *args, **kwargs) TypeError: QPushButton.mousePressEvent() is a private method` – Ramon Antunes Mar 13 '15 at 14:30
  • something strange... when I tried to implement such code in another application it kept complaining about the access to this private method but now it doesn't work... first I ran this code above in the python shell, and now I'm back to eclipse. how do I access private methods? – Ramon Antunes Mar 13 '15 at 18:28
  • I am not sure. that kind of error doesn't come up in eclipse or python shell and you are using windows. I work on CentOS.Still edited the code. See if it works fine now. – smitkpatel Mar 13 '15 at 18:46
  • Hope the answer is acceptable now. Let me know if any more errors. I'll look into it. – smitkpatel Mar 13 '15 at 19:08
  • it works perfectly now, thanks! I'm trying to implement it in my application. but I'm struggling a little bit because now my `vert_layout` belongs to a diferent class from which we find the deleteFrame` method, so I need another input for such method so I can access the `vert_layout`. I think I should pass such input using the signal, am I right? but I don't know how to do this - I mean, I know I can create something like `mySignal = QtCoore.pyqtSignal(QWidget, Ui_MainWindow)`, but didn't work. I really thank you for everything so far! would appreciate if you help me with this! – Ramon Antunes Mar 17 '15 at 21:15
  • I just edited my question with a code similar to mine - the "main" code is quite long and calls different files. but if you prefer I can share, no problem at all! – Ramon Antunes Mar 18 '15 at 13:14