1 回答
TA贡献1801条经验 获得超15个赞
每个代表不能只有一个唯一的编辑器,原因有两个:
可能有更多的编辑器的活动实例(使用 打开
openPersistentEditor
),例如一个表,其中一列的每一行都有一个组合框。每次编辑器将其数据提交给模型时,如果它不是持久编辑器,它就会被销毁。考虑当一个 Qt 对象被分配给一个 Python 变量/属性时,它实际上是一个指向由 Qt 创建的底层 C++ 对象的指针。这意味着虽然
self.editor
仍然作为 python 对象存在,但它指向一个在编辑器被委托关闭时实际删除的对象。
正如函数名所说,createEditor()
创建一个编辑器,所以解决方法是每次createEditor()
调用都创建一个新实例。
更新
但是,这里有一个重要问题:一旦您打开对话框,委托编辑器就会失去焦点。对于一个项目视图,这与单击另一个项目(更改焦点)相同,这将导致数据提交和编辑器破坏。
“简单”的解决方案是在要打开对话框时阻止委托信号(最重要的closeEditor()
是会调用),然后再解除阻止。destroyEditor()
class BrowseEdit(QtWidgets.QLineEdit):
@QtCore.pyqtSlot()
def on_btnaction(self):
self.delegate.blockSignals(True)
selected_path = QtWidgets.QFileDialog.getOpenFileName(self.window(), self.opendialogtitle, self.opendialogdir, self.filefilters)
self.delegate.blockSignals(False)
if not selected_path[0]: return
selected_path = selected_path[0].replace('/', os.sep)
# THIS CAUSES ERROR ('self' GETS DELETED BEFORE THIS LINE!)
self.setText(selected_path)
class BrowseEditDelegate(QtWidgets.QStyledItemDelegate):
# ...
def createEditor(self, parent: QtWidgets.QWidget, option: QtWidgets.QStyleOptionViewItem,
index: QtCore.QModelIndex) -> QtWidgets.QWidget:
try:
if self.model_indices and index in self.model_indices:
editor = BrowseEdit(parent=parent)
editor.delegate = self
return editor
else:
return super().createEditor(parent, option, index)
except Exception as err:
print(err)
return None
也就是说,这是一个hack。虽然它有效,但不能保证它会在未来版本的 Qt 中,当可能引入其他信号或它们的行为发生变化时。
更好更优雅的解决方案是创建一个在单击浏览按钮时调用的信号,然后项目视图(或其任何父项)将负责浏览,如果文件对话框结果有效则设置数据并再次开始编辑该字段:
class BrowseEditDelegate(QtWidgets.QStyledItemDelegate):
browseRequested = QtCore.pyqtSignal(QtCore.QModelIndex)
# ...
def createEditor(self, parent: QtWidgets.QWidget, option: QtWidgets.QStyleOptionViewItem,
index: QtCore.QModelIndex) -> QtWidgets.QWidget:
try:
if self.model_indices and index in self.model_indices:
editor = BrowseEdit(parent=parent)
editor.btnaction.triggered.connect(
lambda: self.browseRequested.emit(index))
return editor
else:
return super().createEditor(parent, option, index)
except Exception as err:
print(err)
return None
class Window(QtWidgets.QWidget):
def __init__(self):
# ...
delegate = BrowseEditDelegate(indices)
self.tv_plugins_3party.setItemDelegate(delegate)
delegate.browseRequested.connect(self.browseRequested)
def browseRequested(self, index):
selected_path = QtWidgets.QFileDialog.getOpenFileName(self.window(), 'Select file', index.data())
if selected_path[0]:
self.model_plugins_3party.setData(index, selected_path[0])
self.tv_plugins_3party.edit(index)
添加回答
举报