Reputation: 347
I have created a button who creates buttons in a vertical layout, called "elementos". In each row, there is a label and a X button who should delete the row. There is a list with the text of the label called "puntos" MRE:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QOpenGLWidget
import sys
from sys import argv, exit
class Renderizador(QOpenGLWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.puntos = []
self.num_elementos = 0
def borrar_punto(self):
self.puntos.pop()
ui.elementos.removeWidget(self.name)
ui.elementos.removeWidget(self.borrar)
self.name.deleteLater()
self.borrar.deleteLater()
self.num_elementos -= 1
def crear_punto(self):
do = ui.valor_do.value()
cota = ui.valor_cota.value()
alejamiento = ui.valor_alej.value()
self.puntos.append((ui.nombre.toPlainText(), do, cota, alejamiento))
self.name = QtWidgets.QLabel()
self.name.setText(ui.nombre.toPlainText() + "({}, {}, {})".format(do, cota, alejamiento))
self.borrar = QtWidgets.QPushButton()
self.borrar.setText("X")
self.borrar.clicked.connect(lambda: self.borrar_punto())
ui.elementos.addWidget(self.name, self.num_elementos, 0, 1, 1)
ui.elementos.addWidget(self.borrar, self.num_elementos, 1, 1, 1)
self.num_elementos += 1
self.update()
class UiVentana:
def __init__(self):
ventana.resize(1500, 1000)
ventana.setLayoutDirection(QtCore.Qt.LeftToRight)
ventana.setFixedSize(ventana.size())
self.widget_central = QtWidgets.QWidget(ventana)
self.gridLayoutWidget = QtWidgets.QWidget(self.widget_central)
self.gridLayoutWidget.setGeometry(QtCore.QRect(1000, 60, 280, 50))
self.Vistas = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.Visor = Renderizador(self.widget_central)
self.Visor.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
self.gridLayoutWidget_2 = QtWidgets.QWidget(self.widget_central)
self.gridLayoutWidget_2.setGeometry(QtCore.QRect(1004, 105, 300, 400))
self.Punto = QtWidgets.QGridLayout(self.gridLayoutWidget_2)
self.Punto.setContentsMargins(5, 5, 5, 5)
self.Punto.setVerticalSpacing(4)
self.texto_nombre = QtWidgets.QLabel(self.gridLayoutWidget_2)
self.texto_nombre.setText("Nombre:")
self.Punto.addWidget(self.texto_nombre, 3, 0, 1, 1)
self.crear_punto = QtWidgets.QPushButton(self.gridLayoutWidget_2)
self.crear_punto.setText("Crear")
self.crear_punto.clicked.connect(self.Visor.crear_punto)
self.Punto.addWidget(self.crear_punto, 3, 2, 1, 1)
self.texto_cota = QtWidgets.QLabel(self.gridLayoutWidget_2)
self.nombre = QtWidgets.QTextEdit(self.gridLayoutWidget_2)
self.nombre.setMaximumSize(QtCore.QSize(100, 24))
self.Punto.addWidget(self.nombre, 3, 1, 1, 1)
self.scroll = QtWidgets.QScrollArea()
self.scroll.setWidgetResizable(True)
self.scroll_widget = QtWidgets.QWidget()
self.scroll_widget.resize(200, 300)
self.elementos_widget = QtWidgets.QWidget()
self.vbox = QtWidgets.QVBoxLayout(self.scroll_widget)
self.vbox.setContentsMargins(0, 0, 0, 0)
self.vbox.addWidget(self.elementos_widget)
self.vbox.addStretch()
self.elementos = QtWidgets.QGridLayout()
self.elementos_widget.setLayout(self.elementos)
self.scroll.setWidget(self.scroll_widget)
self.scroll_widget.setLayout(self.elementos)
self.scroll.setWidget(self.scroll_widget)
self.Punto.addWidget(self.scroll, 4, 0, 1, 3)
self.valor_do = QtWidgets.QSpinBox(self.gridLayoutWidget_2)
self.Punto.addWidget(self.valor_do, 2, 0, 1, 1)
self.valor_alej = QtWidgets.QSpinBox(self.gridLayoutWidget_2)
self.Punto.addWidget(self.valor_alej, 2, 1, 1, 1)
self.valor_cota = QtWidgets.QSpinBox(self.gridLayoutWidget_2)
self.Punto.addWidget(self.valor_cota, 2, 2, 1, 1)
ventana.setCentralWidget(self.widget_central)
ventana.show()
def except_hook(cls, exception, traceback):
sys.__excepthook__(cls, exception, traceback)
if __name__ == "__main__":
app = QtWidgets.QApplication(argv)
ventana = QtWidgets.QMainWindow()
ui = UiVentana()
sys.excepthook = except_hook
exit(app.exec_())
The pop statement should delete from the list the corresponding info about the label. I get an out of index range error, but i get a "RuntimeError: wrapped C/C++ object of type QLabel has been deleted" error if I pop the last statement. Full code: https://github.com/Jaime02/Proyecto-de-investigacion-2019-Dibujo-tecnico/blob/experimental/error (Lines 120-140)
Edit: The delete button only works once if two or more rows are created
Upvotes: 1
Views: 687
Reputation: 243955
Your code has at least the following errors:
If you are going to create an object within a loop, do not make it a member, for example in your case self.name and self.borrar are variables that will always point to the last QLabel and QPushButton, so when you delete only the last row will be deleted in a single occasion.
Your code is very messy since they are modifying variables in places where they are not due as they could cause problems such as tracking errors, for example the variable window and ui.
Considering the above I have rewritten your code implementing the logic of passing the widgets and deleting the widgets directly.
import sys
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
class UiVentana(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(UiVentana, self).__init__(parent)
self.puntos = []
self.visor = QtWidgets.QOpenGLWidget()
self.valor_do = QtWidgets.QSpinBox()
self.valor_cota = QtWidgets.QSpinBox()
self.valor_alej = QtWidgets.QSpinBox()
self.texto_nombre = QtWidgets.QLabel("Nombre")
self.nombre = QtWidgets.QLineEdit()
self.crear_punto = QtWidgets.QPushButton("Crear", clicked=self.crear_punto)
elementos_widget = QtWidgets.QWidget()
scroll_widget = QtWidgets.QWidget()
scroll = QtWidgets.QScrollArea(widgetResizable=True)
scroll.setWidget(scroll_widget)
vbox = QtWidgets.QVBoxLayout(scroll_widget)
vbox.addWidget(elementos_widget)
vbox.addStretch()
self.elementos = QtWidgets.QGridLayout(elementos_widget)
grid_layout = QtWidgets.QGridLayout()
grid_layout.addWidget(self.valor_do, 0, 0)
grid_layout.addWidget(self.valor_cota, 0, 1)
grid_layout.addWidget(self.valor_alej, 0, 2)
grid_layout.addWidget(self.texto_nombre, 1, 0)
grid_layout.addWidget(self.nombre, 1, 1)
grid_layout.addWidget(self.crear_punto, 1, 2)
grid_layout.addWidget(scroll, 2, 0, 1, 3)
for i in range(3):
grid_layout.setColumnStretch(i, 1)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QHBoxLayout(central_widget)
lay.addWidget(self.visor, stretch=1)
lay.addLayout(grid_layout)
self.resize(1280, 960)
def crear_punto(self):
do = self.valor_do.value()
cota = self.valor_cota.value()
alejamiento = self.valor_alej.value()
name = QtWidgets.QLabel(
"{}({}, {}, {})".format(self.nombre.text(), do, cota, alejamiento)
)
punto = (self.nombre.text(), do, cota, alejamiento)
borrar = QtWidgets.QPushButton("X")
wrapper = partial(self.borrar_punto, (name, borrar), punto)
borrar.clicked.connect(wrapper)
row = self.elementos.rowCount()
self.elementos.addWidget(name, row, 0)
self.elementos.addWidget(borrar, row, 1)
self.puntos.append(punto)
def borrar_punto(self, widgets, punto):
if self.puntos:
name, borrar = widgets
name.deleteLater()
borrar.deleteLater()
self.puntos.remove(punto)
print(self.puntos)
def except_hook(cls, exception, traceback):
sys.__excepthook__(cls, exception, traceback)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
sys.excepthook = except_hook
w = UiVentana()
w.show()
exit(app.exec_())
Upvotes: 2