1 回答

TA貢獻1801條經驗 獲得超16個贊
每個代表不能只有一個唯一的編輯器,原因有兩個:
可能有更多的編輯器的活動實例(使用 打開
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)
添加回答
舉報