删除 PyQt5 中动态创建的按钮
Delete dynamically create buttons in PyQt5
我创建了一个在垂直布局中创建按钮的按钮,名为 "elementos"。在每一行中,都有一个标签和一个应该删除该行的 X 按钮。有一个列表,其中包含名为 "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_())
pop 语句应该从列表中删除有关标签的相应信息。我收到超出索引范围的错误,但如果我弹出最后一条语句,则会收到 "RuntimeError: wrapped C/C++ object of type QLabel has been deleted" 错误。
完整代码:https://github.com/Jaime02/Proyecto-de-investigacion-2019-Dibujo-tecnico/blob/experimental/error(第 120-140 行)
编辑:删除按钮仅在创建了两行或更多行时有效一次
您的代码至少有以下错误:
如果你要在循环中创建一个对象,不要让它成为一个成员,例如在你的情况下 self.name 和 self.borrar 是变量,将永远指向最后一个QLabel和QPushButton,所以当你删除的时候只有最后一行会被一次删除。
你的代码很乱,因为他们在不应该的地方修改变量,因为它们可能会导致跟踪错误等问题,例如变量 window 和 ui.
考虑到以上情况,我重写了您的代码,实现了传递小部件和直接删除小部件的逻辑。
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_())
我创建了一个在垂直布局中创建按钮的按钮,名为 "elementos"。在每一行中,都有一个标签和一个应该删除该行的 X 按钮。有一个列表,其中包含名为 "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_())
pop 语句应该从列表中删除有关标签的相应信息。我收到超出索引范围的错误,但如果我弹出最后一条语句,则会收到 "RuntimeError: wrapped C/C++ object of type QLabel has been deleted" 错误。 完整代码:https://github.com/Jaime02/Proyecto-de-investigacion-2019-Dibujo-tecnico/blob/experimental/error(第 120-140 行)
编辑:删除按钮仅在创建了两行或更多行时有效一次
您的代码至少有以下错误:
如果你要在循环中创建一个对象,不要让它成为一个成员,例如在你的情况下 self.name 和 self.borrar 是变量,将永远指向最后一个QLabel和QPushButton,所以当你删除的时候只有最后一行会被一次删除。
你的代码很乱,因为他们在不应该的地方修改变量,因为它们可能会导致跟踪错误等问题,例如变量 window 和 ui.
考虑到以上情况,我重写了您的代码,实现了传递小部件和直接删除小部件的逻辑。
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_())