我已经将QStandardItemModel子类化了:
class PPSTableEditModel(QStandardItemModel):
def __init__(self, parent=None):
super(PPSTableEditModel, self).__init__(parent)
self.proxy = QSortFilterProxyModel()
self.proxy.setSourceModel(self)
self.proxy.setFilterKeyColumn(5)
self.proxy.setDynamicSortFilter(True)
self.proxy.setFilterFixedString("0")
self.editmode = None
self.history = []
def edit_record(self, qndx):
#qndx is passed from a QTableView class and contains view.currentIndex()
self.editmode = 2
del self.history[:]
for ndx in range(0, self.columnCount()):
self.history.append(self.item(qndx.row(),ndx).data(Qt.DisplayRole))
self.process_record(qndx) #<---- This works
#ix = self.index(qndx.row(),2)
#self.process_record(ix) #<---- This causes the error
def process_record(self, pndx):
self.parent().tbl_View.selectionModel().setCurrentIndex(pndx, QItemSelectionModel.Select)
self.parent().tbl_View.edit(pndx)
我遇到的问题来自将edit_record
传递给qndx
的{{1}}方法,视图正确进入了编辑模式;但是,如果尝试设置起始列(通过重新分配qndx),则会出现错误:
process_record
*编辑* 尝试映射到代理索引进行编辑,但仍然出现相同的错误:
edit: index was invalid
edit: editing failed
*编辑* MCVE:
def edit_record(self, qndx):
self.editmode = 2
del self.history[:]
for ndx in range(0, self.columnCount()):
self.history.append(self.item(qndx.row(),ndx).data(Qt.DisplayRole))
ix = qndx if not self.proxy else self.proxy.mapToSource(qndx)
self.process_record(ix)
*编辑*
尽管我无法确定import uuid,sys
from PyQt5.QtSql import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class PPSTableEditModel(QStandardItemModel):
model_loaded = pyqtSignal()
def __init__(self, parent=None):
super(PPSTableEditModel, self).__init__(parent)
self.proxy = None
def edit_record(self, qndx):
ix = qndx if not self.proxy else self.proxy.mapToSource(qndx)
self.process_record(ix)
def process_record(self, pndx):
self.parent().tbl_View.selectionModel().setCurrentIndex(pndx, QItemSelectionModel.Select)
self.parent().tbl_View.edit(pndx)
class SclDataModel(PPSTableEditModel):
def __init__(self, parent=None):
super(SclDataModel, self).__init__(parent)
self.proxy = QSortFilterProxyModel(self)
self.proxy.setSourceModel(self)
self.proxy.setFilterKeyColumn(5)
self.proxy.setDynamicSortFilter(True)
self.proxy.setFilterFixedString("0")
def load_data(self, parentid):
query = QSqlQuery()
query.prepare('SELECT * FROM scldata WHERE svcdataid=?')
query.addBindValue(parentid)
query.exec_()
while query.next():
record = []
for ndx in range(0, query.record().count()):
item = QStandardItem()
item.setData(query.value(ndx), Qt.DisplayRole)
record.append(item)
record.append(QStandardItem("0"))
self.insertRow(self.rowCount(), record)
self.model_loaded.emit()
class SclDataBrowse(QWidget):
def __init__(self, parent=None):
super(SclDataBrowse, self).__init__(parent)
self.resize(600, 297)
self.tbl_View = QTableView(self)
self.line = QFrame(self)
self.line.setFrameShape(QFrame.HLine)
self.line.setFrameShadow(QFrame.Sunken)
self.spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.view_layout = QVBoxLayout(self)
self.view_layout.setContentsMargins(0, 0, 0, 0)
self.view_layout.addWidget(self.tbl_View)
self.view_layout.addWidget(self.line)
self.model = SclDataModel(self)
self.parentid = None
self.setup_view()
self.setup_connections()
def setup_view(self):
self.tbl_View.setModel(self.model.proxy)
self.tbl_View.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.tbl_View.setSelectionMode(QAbstractItemView.SingleSelection)
self.tbl_View.setSelectionBehavior(QAbstractItemView.SelectRows)
self.tbl_View.verticalHeader().setVisible(False)
self.tbl_View.verticalHeader().setDefaultSectionSize(22)
def setup_connections(self):
self.tbl_View.doubleClicked.connect(self.edit_record)
self.model.model_loaded.connect(self.format_view)
def set_parent(self, parentid):
self.parentid = parentid
self.model.load_data(self.parentid)
def format_view(self):
if self.model.rowCount():
header = ["recorid", "svcdataid", "Start Amount", "End Amount", "Rate", "deleteflag"]
for n in range(0, len(header)):
self.model.setHeaderData(n, Qt.Horizontal, header[n])
self.tbl_View.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
self.tbl_View.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
self.tbl_View.setColumnWidth(4, 85)
self.tbl_View.setColumnHidden(0, True)
self.tbl_View.setColumnHidden(1, True)
self.tbl_View.setColumnHidden(5, True)
def set_parent_record(self, parentid):
self.parentid = parentid
self.model.load_data(self.parentid)
def edit_record(self):
qndx = self.tbl_View.currentIndex()
self.model.edit_record(qndx)
app = QApplication(sys.argv)
mainWin = SclDataBrowse()
db = QSqlDatabase.addDatabase("QMYSQL")
db.setHostName("myhost")
db.setUserName("myusr")
db.setPassword("mypassword")
db.setDatabaseName("mydbname")
db.open()
mainWin.show()
mainWin.set_parent("a5865717-e125-11e8-80c0-d4ae52cc00a8")
sys.exit(app.exec_())
似乎与QSortFilterProxyModel
有关。将索引传递给process_record
而不通过代理进行映射可以使我进行编辑,但是基础数据不正确。
*** EDIT ***
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
from PyQt5.QtWidgets import *
class PPSTableEditModel(QStandardItemModel):
model_loaded = pyqtSignal()
def __init__(self, parent=None):
super(PPSTableEditModel, self).__init__(parent)
self.proxy = None
def edit_record(self, qndx):
ix = qndx.sibling(qndx.row(), 2)
self.process_record(ix)
#ix = qndx if not self.proxy else self.proxy.mapToSource(qndx)
#self.process_record(ix)
def delete_record(self, qndx):
ix = qndx if not self.proxy else self.proxy.mapToSource(qndx)
self.item(ix.row(),5).setData("1",Qt.DisplayRole)
def process_record(self, pndx):
for ndx in range(0,self.columnCount()):
print('{0},{1}----->{2}'.format(pndx.row(),ndx,self.item(pndx.row(),ndx).data(Qt.DisplayRole)))
self.parent().tbl_View.selectionModel().setCurrentIndex(pndx, QItemSelectionModel.Select)
self.parent().tbl_View.edit(pndx)
class SclDataModel(PPSTableEditModel):
def __init__(self, parent=None):
super(SclDataModel, self).__init__(parent)
self.proxy = QSortFilterProxyModel(self)
self.proxy.setSourceModel(self)
self.proxy.setFilterKeyColumn(5)
self.proxy.setDynamicSortFilter(True)
self.proxy.setFilterFixedString("0")
def load_data(self, parentid):
data = (
{"recordid": "1", "svcdataid": 1, "samount": .01, "eamount": 5000, "rate": .065, "delflag": "0"},
{"recordid": "2", "svcdataid": 1, "samount": 5000.01, "eamount": 10000, "rate": .065, "delflag": "0"},
{"recordid": "3", "svcdataid": 1, "samount": 10000.01, "eamount": 15000, "rate": .060, "delflag": "0"},
{"recordid": "4", "svcdataid": 1, "samount": 15000.01, "eamount": 20000, "rate": .055, "delflag": "0"},
{"recordid": "5", "svcdataid": 1, "samount": 20000.01, "eamount": 99999, "rate": .05, "delflag": "0"}
)
for ndx,rec in enumerate(data):
record = []
for key in rec:
item = QStandardItem()
item.setData(rec[key], Qt.DisplayRole)
record.append(item)
self.insertRow(self.rowCount(), record)
self.model_loaded.emit()
class SclDataBrowse(QWidget):
def __init__(self, parent=None):
super(SclDataBrowse, self).__init__(parent)
self.resize(600, 297)
self.tbl_View = QTableView(self)
self.line = QFrame(self)
self.line.setFrameShape(QFrame.HLine)
self.line.setFrameShadow(QFrame.Sunken)
self.spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.view_layout = QVBoxLayout(self)
self.view_layout.setContentsMargins(0, 0, 0, 0)
self.view_layout.addWidget(self.tbl_View)
self.view_layout.addWidget(self.line)
self.btn_layout = QHBoxLayout()
self.btn_layout.setContentsMargins(6, 6, 6, 6)
self.btn_delete = QPushButton()
self.btn_delete.setText("Delete")
self.btn_layout.addWidget(self.btn_delete)
self.view_layout.addLayout(self.btn_layout)
self.model = SclDataModel(self)
self.parentid = None
self.setup_view()
self.setup_connections()
def setup_view(self):
self.tbl_View.setModel(self.model.proxy)
self.tbl_View.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.tbl_View.setSelectionMode(QAbstractItemView.SingleSelection)
self.tbl_View.setSelectionBehavior(QAbstractItemView.SelectRows)
self.tbl_View.verticalHeader().setVisible(False)
self.tbl_View.verticalHeader().setDefaultSectionSize(22)
def setup_connections(self):
self.tbl_View.doubleClicked.connect(self.edit_record)
self.btn_delete.clicked.connect(self.delete_record)
self.model.model_loaded.connect(self.format_view)
def set_parent(self, parentid):
self.parentid = parentid
self.model.load_data(self.parentid)
def format_view(self):
if self.model.rowCount():
header = ["recorid", "svcdataid", "Start Amount", "End Amount", "Rate", "deleteflag"]
for n in range(0, len(header)):
self.model.setHeaderData(n, Qt.Horizontal, header[n])
self.tbl_View.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
self.tbl_View.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
self.tbl_View.setColumnWidth(4, 85)
self.tbl_View.setColumnHidden(0, True)
self.tbl_View.setColumnHidden(1, True)
self.tbl_View.setColumnHidden(5, True)
def set_parent_record(self, parentid):
self.parentid = parentid
self.model.load_data(self.parentid)
def edit_record(self):
qndx = self.tbl_View.currentIndex()
self.model.edit_record(qndx)
def delete_record(self):
qndx = self.tbl_View.currentIndex()
self.model.delete_record(qndx)
app = QApplication(sys.argv)
mainWin = SclDataBrowse()
mainWin.show()
mainWin.set_parent("a5865717-e125-11e8-80c0-d4ae52cc00a8")
sys.exit(app.exec_())
使用此代码,表中有5个条目。例如,如果您删除了第二条记录,则过滤器将正确隐藏“已删除”记录。现在,双击第三行或第四行,在process_record
中输出的数据将报告正确的行,但与该行关联的数据不正确。
答案 0 :(得分:1)
根据您的代码,您要访问位于第二行但在同一行中的索引,也就是说,它是QModelIndex
的同级,因此必须使用同级功能:< / p>
def edit_record(self, qndx):
ix = qndx.sibling(qndx.row(), 2)
self.process_record(ix)
问题是因为您正在使用项目获取数据,QTableView
不知道k,它仅知道已建立的模型,即QSortFilterProxyModel
,因此要求edit()
和selectionModel().SetCurrentIndex()
的QModelIndex必须是QSortFilterProxyModel
,所以这就是我最初的解决方案起作用的原因,但是在您的印象中,您正在使用PPSTableEditModel
模型,因此解决方案是使用代理,但由于QModelIndex
将模型引用保存到归属所属,因此不必存储代理:
def process_record(self, pndx):
model = pndx.model()
for ndx in range(model.columnCount()):
print('{0},{1}----->{2}'.format(pndx.row(), ndx, model.index(pndx.row(),ndx).data(Qt.DisplayRole)))
self.parent().tbl_View.selectionModel().setCurrentIndex(pndx, QItemSelectionModel.Select)
self.parent().tbl_View.edit(pndx)