QSqlTableModel数据编辑(子类化)问题

2024-04-25 09:50:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图用Python3.7和PyQt5编写一个小应用程序,但遇到了麻烦

我对Python很陌生,我对C++的知识接近0(零)。 最后,我的项目将有一个Tableview,其模型是链接到QSlite数据库表的QsqlTableModel

那张表由三列组成。我只想编辑第二列(索引1),它的值为0/1。在本专栏中,我想作为委托(但使用persisten编辑器)放置一个类似here的开关按钮来更新布尔值(最后应用程序将类似于ToDo列表)

但问题仅仅出现在一开始。我可以填充模型,视图可以正确显示表中的数据,格式可以(仅用于测试目的),但是当我尝试编辑数据时,它不会更改模型中的数据。编辑行中的所有值都会消失,并且行标题中会出现感叹号

这只出现在我重新实现数据方法时。如果我只重新实现flags方法,一切都可以

我肯定我犯了一个愚蠢的错误,但我找不到问题所在

这是我的密码

main.py

from MyClass import MyConnection, TableView, Model
from PyQt5 import QtWidgets, QtCore, QtGui
import sys


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    MyConnection('data22.db')
    model = Model('tabella_di_test')
    table = TableView(model)
    table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
    table.show()
    sys.exit(app.exec())

MyClass.py

from PyQt5.QtSql import QSqlDatabase, QSqlTableModel
from PyQt5.QtWidgets import QTableView, QItemDelegate
from PyQt5.QtCore import Qt, QModelIndex, QRect, QAbstractTableModel, QVariant
from PyQt5.QtGui import QFont, QPainter, QPixmap
import typing
import sys

COL_DEL = 1 #column that receive delegate in the future
COL_ICON = 2


class MyConnection:
    def __init__(self, name):
        super(MyConnection, self).__init__()
        self.db = QSqlDatabase().addDatabase("QSQLITE")
        self.db.setDatabaseName(name)
        if self.db.open():
            print("Connection Opened...")
        else:
            sys.exit("Errore nella connessione al DB...")


class TableView(QTableView):
    def __init__(self, model):
        super(TableView, self).__init__()
        self.setAlternatingRowColors(True)
        self.setModel(model)


class Model(QSqlTableModel):
    def __init__(self, name):
        super(Model, self).__init__()
        self.setTable(name)
        self.select()
        print(self.rowCount())

    def flags(self, index: QModelIndex):
        if not index.isValid():
            print('Flags ==> Index is not valid!')
            return QVariant()
        if index.column() == COL_DEL:
            print('Flags ==> Index({},{}) '.format(index.row(), index.column()))
            return Qt.NoItemFlags | Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
        else:
            return Qt.NoItemFlags | Qt.ItemIsEnabled

    def data(self, index: QModelIndex, role=None) -> typing.Any:
        if not index.isValid():
            print('Index is not valid!')
            return QVariant()
        if role == Qt.TextAlignmentRole:
            return Qt.AlignCenter
        if role == Qt.DisplayRole:
            return super(Model, self).data(index, role)
        if role == Qt.FontRole and index.column() == COL_DEL:
            font = QFont()
            font.setBold(True)
            font.setPixelSize(16)
            return font


class Delegate(QItemDelegate):
    def __init__(self):
        super(Delegate, self).__init__()

Tags: namefromimportselfindexmodelreturnif
1条回答
网友
1楼 · 发布于 2024-04-25 09:50:50

在这种情况下,无需实现自定义模型,只需使用带有自定义委托的QSqlTableModel即可:

import os

from PyQt5 import QtCore, QtGui, QtWidgets, QtSql

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
COL_DEL = 1


def create_connection(name):
    db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName(name)
    if db.open():
        print("Connection Opened...")
        return True
    print("Errore nella connessione al DB...")
    return False


class MySwitch(QtWidgets.QPushButton):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setCheckable(True)
        self.setMinimumWidth(66)
        self.setMinimumHeight(22)

    def paintEvent(self, event):
        label = "ON" if self.isChecked() else "OFF"
        bg_color = (
            QtGui.QColor(QtCore.Qt.green)
            if self.isChecked()
            else QtGui.QColor(QtCore.Qt.red)
        )

        radius = 10
        width = 32
        center = self.rect().center()

        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.translate(center)
        painter.setBrush(QtGui.QColor(0, 0, 0))

        pen = QtGui.QPen(QtCore.Qt.black)
        pen.setWidth(2)
        painter.setPen(pen)

        painter.drawRoundedRect(
            QtCore.QRect(-width, -radius, 2 * width, 2 * radius), radius, radius
        )
        painter.setBrush(QtGui.QBrush(bg_color))
        sw_rect = QtCore.QRect(-radius, -radius, width + radius, 2 * radius)
        if not self.isChecked():
            sw_rect.moveLeft(-width)
        painter.drawRoundedRect(sw_rect, radius, radius)
        painter.drawText(sw_rect, QtCore.Qt.AlignCenter, label)


class CustomDelegate(QtWidgets.QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super().initStyleOption(option, index)
        font = QtGui.QFont()
        font.setBold(True)
        font.setPixelSize(16)
        option.font = font
        option.displayAlignment = QtCore.Qt.AlignCenter

    def paint(self, painter, option, index):
        if (
            isinstance(option.widget, QtWidgets.QAbstractItemView)
            and index.column() == COL_DEL
        ):
            option.widget.openPersistentEditor(index)
            return
        super().paint(painter, option, index)

    def createEditor(self, parent, option, index):
        if index.column() == COL_DEL:
            editor = MySwitch(parent)
            editor.toggled.connect(lambda *args, e=editor: self.commitData.emit(e))
            return editor

    def setModelData(self, editor, model, index):
        if index.column() == COL_DEL:
            value = 1 if editor.isChecked() else 0
            model.setData(index, value)
        else:
            super().setModelData(editor, model, index)

    def setEditorData(self, editor, index):
        if index.column() == COL_DEL:
            value = bool(index.data())
            editor.setChecked(value)
        else:
            super().setEditorData(editor, index)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    if not create_connection(os.path.join(CURRENT_DIR, "data22.db")):
        sys.exit(-1)

    w = QtWidgets.QTableView()
    delegate = CustomDelegate(w)
    w.setItemDelegate(delegate)
    model = QtSql.QSqlTableModel()
    model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
    model.setTable("tabella_di_test")
    model.select()
    w.setModel(model)
    w.resize(640, 480)
    w.show()

    sys.exit(app.exec_())

相关问题 更多 >