在闲逛一些带有C ++答案的帖子之后,这些帖子不适合我的问题,而且比解释我试图在这里提出的问题更令人困惑。
我正在尝试对QSqlTableModel进行子类化,因为我需要一些带有复选框的布尔列。完整的工作程序是:

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
import sys

class ImportFilter (QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        print("Welcome to StandardDialog")
        # Load the Window
        #self.ui = uic.loadUi("ImportFilter.ui",self)
        #self.ui.setModal(True)
        self.buttonBox = QDialogButtonBox()
        self.tableView_typeOfValues = QTableView()
        layout = QVBoxLayout()
        layout.addWidget(self.buttonBox)
        layout.addWidget(self.tableView_typeOfValues)
        self.setLayout(layout)

        # Init Environmment
        self.db = createConnection()

        # create Models
        self.setupModel()

        #setup Views
        self.setupView()

        # connect Signals
        self.buttonBox.clicked.connect(self.pushButton_Box_clicked)

        self.show()
        print("<- initUI")

    def setupView(self):
        print("-> setupView")
        self.tableView_typeOfValues.setModel(self.tableView_typeOfValues_Model)
        self.tableView_typeOfValues.setColumnWidth(0,10)
        self.tableView_typeOfValues.setColumnWidth(1,130)
        self.tableView_typeOfValues.setColumnWidth(2,130)
        self.tableView_typeOfValues.setColumnWidth(3,60)
        self.tableView_typeOfValues.setColumnWidth(4,60)
        self.tableView_typeOfValues.setColumnWidth(5,60)
        self.tableView_typeOfValues.setColumnWidth(6,60)

        self.tableView_typeOfValues.hideColumn(0)
        self.tableView_typeOfValues.hideColumn(3)
        print("<- setupView")

    def setupModel(self):
        print("-> setupModel")
        # own model
        self.tableView_typeOfValues_Model = ImportSqlTableModel()
        print("   tables:", self.db.tables())
        print('   Before .setTable("typeOfValue") and select()')
        self.tableView_typeOfValues_Model.info()
        self.tableView_typeOfValues_Model.setTable("typeOfValue")
        self.tableView_typeOfValues_Model.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.tableView_typeOfValues_Model.select()
        print('   After .setTable("typeOfValue") and select()')
        self.tableView_typeOfValues_Model.info()
        self.headerData()
        print("   Table:",self.tableView_typeOfValues_Model.tableName())
        print("   count:",self.tableView_typeOfValues_Model.rowCount())

        self.tableView_typeOfValues_Model.info()
        print("<- setupModel")

    def setupModelQRY(self):
        print("-> setupModel with Query")
        # works so far
        #self.tableView_typeOfValues_Model = QSqlTableModel()  # edit but no checkboxes
        self.tableView_typeOfValues_Model = ImportSqlTableModel(self.db) # no edit
        # SET query
        qry = QSqlQuery(self.db)
        sql = "SELECT ID, name, unit, source, Import, ImportIfZero, visible FROM typeOfValue"
        qry.prepare(sql)
        qry.exec_(sql)
        self.tableView_typeOfValues_Model.setQuery(qry)
        self.tableView_typeOfValues_Model.select()
        print("   Filter:",self.tableView_typeOfValues_Model.filter())
        print("   SELECT:", self.tableView_typeOfValues_Model.selectStatement())
        self.tableView_typeOfValues_Model.setEditStrategy(QSqlTableModel.OnFieldChange)
        print("<- setupModel")

    def headerData(self):
        print("-> headerData")
        self.tableView_typeOfValues_Model.setHeaderData(0,Qt.Horizontal, "ID")
        self.tableView_typeOfValues_Model.setHeaderData(1,Qt.Horizontal, "name")
        self.tableView_typeOfValues_Model.setHeaderData(2,Qt.Horizontal, "unit")
        self.tableView_typeOfValues_Model.setHeaderData(3,Qt.Horizontal, "source")
        self.tableView_typeOfValues_Model.setHeaderData(4,Qt.Horizontal, "Import")
        self.tableView_typeOfValues_Model.setHeaderData(5,Qt.Horizontal, "ImportIfZero")
        self.tableView_typeOfValues_Model.setHeaderData(6,Qt.Horizontal, "visible")
        print("<- headerData")


    ###################################################################################################
    #                        functions
    ###################################################################################################
    def pushButton_Box_clicked(self,signal):
        print("okButtonClicked")
        print("buttonBox_clicked",signal)
        self.tableView_typeOfValues_Model.submitAll()
        self.exitcode = "ok, but not implemented"
        sys.exit()

    def returnCode(self):
        return self.exitcode

#######################################################################################################################
#                                               C L A S S
#######################################################################################################################

class ImportSqlTableModel(QSqlTableModel):
    def __init__(self):
        super(ImportSqlTableModel, self).__init__()
        print("-> ImportSqlTableModel.__init__:")
        self.booleanSet =[4,5,6]
        self.readOnlySet = [1]
        print("   Inside:")
        self.info()
        print("<- ImportSqlTableModel.__init__:")


    def info(self):
        print("-> info")

        print("   ImportSqlTableModel tables inside :", self.database().tables())
        print("   ImportSqlTableModel self.db       :", self.database())
        print("   ImportSqlTableModel self.Table    :", self.tableName())
        print("   ImportSqlTableModel self.rowCount :", self.rowCount())
        print("   ImportSqlTableModel self.lastEror :", self.lastError().text())
        print("<- info")
    def columnCount(self, index):
        count = QSqlTableModel.columnCount(self, index)
        return count

    def dataChanged(self, QModelIndex, QModelIndex_1, Iterable, p_int=None, *args, **kwargs):
        print("-> Datachanged")

    def data(self, index, role=Qt.DisplayRole):
        print("-> ImportSqlModel.data",index, role)
        print("   1row   :", index.row())
        print("   col    :", index.column())
        print("   data   :", self.record().fieldName(index.column()))
        value = super(ImportSqlTableModel, self).data(index)
        print("  value2:",value)

        if index.column() in self.booleanSet:
            if role == Qt.CheckStateRole:
                if value == 2:
                    return QVariant(Qt.Unchecked)
                else:
                    return QVariant(Qt.Checked)
            else:
                QSqlTableModel.data(self, index, role)
        else:
            return QSqlTableModel.data(self, index, role)

    def setData(self, index, value, role=Qt.EditRole):
        # works with changing value, but not saving
        print("-> ImportSqlModel.setData",index,value,role)
        print("   value:", value)
        if not index.isValid():
            return False
        if role == Qt.EditRole:
            print("   = Qt.Editrole")
            QVariant(value)
            print("   Update table")
            self.select()
        if index.column() in self.booleanSet and role == Qt.CheckStateRole:
            print("   checkbox changed!")
            if value == Qt.Checked:
                print("   Qt.Checked")
                return QSqlTableModel.setData(self, index, 2 , Qt.EditRole)
            else:
                print("   not Qt.Checked")
                return QSqlTableModel.setData(self, index, 0 , Qt.EditRole)
        else:
            return QSqlTableModel.setData(self, index, value, role)

    def flags(self, index):
        print("-> ImportSqlModel.flags")
        print("   index.isValid()",index.isValid())
        if not index.isValid():
            return Qt.ItemIsEnabled
        if index.column() in self.booleanSet:
            return Qt.ItemIsUserCheckable  | Qt.ItemIsEnabled #  | Qt.ItemIsSelectable  | Qt.ItemIsEditable
        elif index.column() in self.readOnlySet:
            return Qt.ItemIsSelectable | Qt.ItemIsEnabled
        else:
            return QSqlTableModel.flags(self, index)
        print("<- ImportSqlModel.flags")


#######################################################################################################################
#                                               D E M O F U N C T I O N
#######################################################################################################################

def createConnection():
    db = QSqlDatabase.addDatabase('QSQLITE')
    db.setDatabaseName('memory')
    if not db.open():
        QMessageBox.critical(None, qApp.tr("Cannot open database"),
                             qApp.tr("Unable to establish a database connection.\n"
                                     "This example needs SQLite support. Please read "
                                     "the Qt SQL driver documentation for information "
                                     "how to build it.\n\n"
                                     "Click Cancel to exit."),
                             QMessageBox.Cancel)
        return False

    query = QSqlQuery()
    query.exec_("CREATE TABLE `typeOfValue` (`ID`   INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, "\
    "`name` TEXT NOT NULL,  `unit`  TEXT NOT NULL,`source` TEXT,`import` INTEGER,`importIfZero` INTEGER,"\
    "`visible`  INTEGER);")

    query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
                '("Sound", "dB", "live", 0,0,2)')
    query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
                '("Flow", "m/min", "live", 0,2,2)')
    query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
                '("Vibration", "mm/s", "live", 2,2,2)')
    query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
                '("Voltage", "V", "live", 0,0,0)')
    query.exec_('insert into typeOfValue (name, unit, source, import, importIfZero, visible) values '\
                '("Ampere", "A", "live", 2,0,2)')
    return db
#######################################################################################################################
#                                               M A I N
#######################################################################################################################

if __name__ == '__main__':
    createConnection()
    app = QApplication(sys.argv)
    prog = ImportFilter()
    prog.show()
    sys.exit(app.exec_())


我正在运行的问题是,当我使用查询来填充表时,我能够查看该表:

def setupModel(self):
    print("-> setupModel")
    # SET query
    qry = QSqlQuery(self.gVar.db)
    sql = "SELECT ID, name, unit, source, Import, ImportIfZero, visible FROM typeOfValue"
    qry.prepare(sql)
    qry.exec_(sql)
    self.tableView_typeOfValues_Model.setQuery(qry)


但是我发现了错误,那就是导致了只读表。手册中描述了不应执行的操作:请参见here
所以我改为.setTable("typeOfValue")#=表名

        self.tableView_typeOfValues_Model = ImportSqlTableModel(self.gVar.db)
        self.tableView_typeOfValues_Model.setTable("typeOfValue")
   self.tableView_typeOfValues_Model.setEditStrategy(QSqlTableModel.OnFieldChange)

        self.tableView_typeOfValues_Model.select()


但是现在我有一个空视图,如果我调用self.lastError().text(),我会得到一条消息,因为self.database().tables()(在模型内部被调用)带来了一个空列表,所以找不到该表。对我而言,这意味着数据库未正确初始化,但是self.database()带来了
结果为0x042C4D30处的PyQt5.QtSql.QSqlDatabase对象。

请,有人可以给我提示纠正QSqlTableModel的子类化。谢谢!

最佳答案

该问题是由未为布尔类型列启用的Qt.ItemIsEditable标志引起的,在指令中这是必需的:

if index.column() in self.booleanSet and role == Qt.CheckStateRole:
    print("   checkbox changed!")
    if value == Qt.Checked:
        print("   Qt.Checked")
        return QSqlTableModel.setData(self, index, 2 , Qt.EditRole)
    else:
        print("   not Qt.Checked")
        return QSqlTableModel.setData(self, index, 0 , Qt.EditRole)


因为它会验证该字段可以编辑。

因此解决方案是启用此标志,但为避免您可以写一些文本,我们将通过委托禁用编辑器:

class ReadOnlyDelegate(QItemDelegate):
    def createEditor(self, parent, option, index):
        lb = QLabel(parent)
        return lb


完整的例子:

import sys

from PyQt5.QtCore import QVariant, Qt
from PyQt5.QtSql import QSqlTableModel, QSqlDatabase
from PyQt5.QtWidgets import QApplication, QTableView, QLabel, QItemDelegate


class ImportSqlTableModel(QSqlTableModel):
    def __init__(self, *args, **kwargs):
        super(ImportSqlTableModel, self).__init__(*args, **kwargs)
        self.booleanSet = [4, 5, 6]  # column with checkboxes
        self.readOnlySet = [1]  # columns which must not be changed
        self.setTable("typeOfValue")
        self.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.select()

    def data(self, index, role=Qt.DisplayRole):
        value = super(ImportSqlTableModel, self).data(index)
        if index.column() in self.booleanSet:
            if role == Qt.CheckStateRole:
                return Qt.Unchecked if value == 2 else Qt.Checked
            else:
                return QVariant()
        return QSqlTableModel.data(self, index, role)

    def setData(self, index, value, role=Qt.EditRole):
        if not index.isValid():
            return False
        if index.column() in self.booleanSet:
            if role == Qt.CheckStateRole:
                val = 2 if value == Qt.Unchecked else 0
                return QSqlTableModel.setData(self, index, val, Qt.EditRole)
            else:
                return False
        else:
            return QSqlTableModel.setData(self, index, value, role)

    def flags(self, index):
        if not index.isValid():
            return Qt.NoItemFlags
        if index.column() in self.booleanSet:
            return Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsEditable
        elif index.column() in self.readOnlySet:
            return Qt.ItemIsSelectable | Qt.ItemIsEnabled
        else:
            return QSqlTableModel.flags(self, index)


class ReadOnlyDelegate(QItemDelegate):
    def createEditor(self, parent, option, index):
        lb = QLabel(parent)
        return lb


if __name__ == '__main__':
    app = QApplication(sys.argv)

    db = QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName("/path/of/your_database.db")
    if not db.open():
        sys.exit(-1)
    model = ImportSqlTableModel()
    w = QTableView()
    w.setModel(model)
    for col in model.booleanSet:
        w.setItemDelegateForColumn(col, ReadOnlyDelegate(w))
    w.show()
    sys.exit(app.exec_())

08-16 11:58