QSqlTableModel проблема редактирования данных (подклассов) - PullRequest
1 голос
/ 03 апреля 2020

У меня проблемы с небольшим приложением, которое я пытаюсь написать в Python 3.7 и PyQt5.

Я довольно новичок в Python, и мои знания по C ++ близки к 0 (нулю).
В конце у моего проекта будет Tableview, модель которого - QsqlTableModel, связанная с QSlite. таблица базы данных.

Эта таблица состоит из трех столбцов. Меня интересует редактирование только 2-го столбца (индекс 1) со значением 0/1. В этом столбце я хотел бы поместить в качестве делегата (но с постоянным редактором) кнопку переключения, например здесь , чтобы обновить логическое значение (в конце приложение будет выглядеть как список задач).

Но проблема возникает только в начале. Я могу заполнить модель, и представление правильно отображает данные из таблицы, форматирование в порядке (только для целей тестирования), но когда я пытаюсь редактировать данные, он не будет изменять данные в модели все значения в отредактированная строка исчезает, и я получаю восклицательный знак в заголовке строки.

Это только из-за того, что я переопределил метод данных. Если я переопределю только метод 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__()

1 Ответ

0 голосов
/ 03 апреля 2020

Нет необходимости реализовывать пользовательскую модель для этого случая, достаточно просто 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_())
...