QTableView编辑模式

时间:2018-11-12 18:29:22

标签: python python-3.x pyqt pyqt5

我已经将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中输出的数据将报告正确的行,但与该行关联的数据不正确。

1 个答案:

答案 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)