问题描述
我使用的是 Python 3.9.5。
我在我的项目中遇到了一些严重的问题,这里是一个最低限度的可重现示例代码,以及一些描述。
from PyQt6.QtCore import *
from PyQt6.QtGui import *
from PyQt6.QtWidgets import *
class Editor(QTextEdit):
doubleClicked = pyqtSignal(QTextEdit)
def __init__(self):
super().__init__()
self.setReadOnly(True)
def mouseDoubleClickEvent(self,e: QMouseEvent) -> None:
self.doubleClicked.emit(self)
class textcell(qgroupbox):
def __init__(self,text):
super().__init__()
self.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
self.label = QLabel(text)
self.apply = makebutton('Apply')
self.apply.hide()
self.editor = Editor()
self.editor.doubleClicked.connect(lambda: self.editor.setReadOnly(False))
self.editor.doubleClicked.connect(self.apply.show)
self.hBox = QHBoxLayout()
self.hBox.addspacerItem(spacer)
self.hBox.addWidget(self.apply)
self.vBox = QVBoxLayout()
self.vBox.addWidget(self.label)
self.vBox.addWidget(self.editor)
self.vBox.addLayout(self.hBox)
self.setLayout(self.vBox)
self.apply.clicked.connect(self.on_ApplyClick)
def on_ApplyClick(self):
self.editor.setReadOnly(True)
self.apply.hide()
def makebutton(text):
button = QPushButton()
button.setFixedSize(60,20)
button.setText(text)
return button
class songpage(qgroupbox):
def __init__(self,texts):
super().__init__()
self.init(texts)
self.setCheckable(True)
self.setChecked(False)
def init(self,texts):
self.vBox = QVBoxLayout()
artist = textcell('Artist')
artist.editor.setText(texts[0])
album = textcell('Album')
album.editor.setText(texts[1])
title = textcell('Title')
title.editor.setText(texts[2])
self.vBox.addWidget(artist)
self.vBox.addWidget(album)
self.vBox.addWidget(title)
self.setLayout(self.vBox)
spacer = QSpacerItem(0,20,QSizePolicy.Policy.Expanding,QSizePolicy.Policy.Minimum)
class Ui_MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.resize(405,720)
self.setwindowTitle('example')
frame = self.frameGeometry()
center = self.screen().availableGeometry().center()
frame.moveCenter(center)
self.move(frame.topLeft())
self.centralwidget = QWidget(self)
vBox = QVBoxLayout(self.centralwidget)
hBox = QHBoxLayout()
add = makebutton('Add')
delete = makebutton('Delete')
hBox.addWidget(add)
hBox.addspacerItem(spacer)
hBox.addWidget(delete)
vBox.addLayout(hBox)
self.scrollArea = QScrollArea(self.centralwidget)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBaralwaysOn)
self.verticalLayout = QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.scrollArea.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop)
vBox.addWidget(self.scrollArea)
self.setCentralWidget(self.centralwidget)
add.clicked.connect(self.addobj)
delete.clicked.connect(self.deleteObj)
def addobj(self):
Obj = songpage(('AAA','BBB','CCC'))
self.verticalLayout.addWidget(Obj)
def deleteObj(self):
item = self.verticalLayout.itemAt(0)
widget = item.widget()
self.verticalLayout.removeItem(item)
self.verticalLayout.removeWidget(widget)
app = QApplication([])
window = Ui_MainWindow()
window.show()
app.exec()
问题很简单,如果我点击添加按钮,小部件将被添加并且一切正常,如果我双击一个 QTextEdit,它的应用按钮将会显示并且它会从只读变为可编辑。
>点击应用按钮后,按钮将隐藏,相应的 QTextEdit 将再次只读。
我终于设法向 QTextEdit 添加了 doubleClicked 信号。
而且,问题是,如果我单击删除按钮,而不是按预期删除内容,它会使整个应用程序崩溃。
很抱歉,最小可重现示例太长了,但我只设法用所有代码重现了问题,我真的不知道出了什么问题。
那么如何解决呢?
解决方法
好吧,我已经弄清楚了,这是由我添加到使用固定大小按钮的每个水平布局中的间隔项引起的。
所有这些布局都使用相同的间隔项,完全相同的间隔项,而不是完全相同。
据我观察,间隔项都是对同一个对象的引用,它们都是同一个对象的回声,该对象位于固定的内存地址。
老实说,我不明白这样的事情是如何工作的,同一个对象不仅可以添加到多个布局中并同时出现在所有布局中,还可以多次添加到同一个布局中,但它始终保持不变原始对象,而不是自身的副本。
我想当我将相同的间隔项添加到多个布局时,我没有添加原始间隔项,而是添加了原始项的副本,它们相同但位于不同的内存地址,显然这不是 Python 的方式有效。
因此,当我删除一个小部件时,其中的所有内容、布局中的所有内容都将被删除,并且间隔项也将被删除。
因为所有布局中的所有间隔项都是对原始间隔项的引用,所以当我删除其中一个布局时,原始间隔项也被删除,并且间隔项从所有其他布局中删除,但其阴影仍然存在,并且该项目没有从所有其他布局中正确删除,布局包含对不再存在的对象的引用,因此应用程序崩溃。
通过删除间隔项的定义并将添加的间隔项替换为.addStretch()
,修复了该错误。