我在尝试使用Python 3.7和PyQt5编写的小型应用程序遇到麻烦。
我对Python还是很陌生,我对C ++的了解接近于0(零)。最后,我的项目将有一个Tableview,其模型是链接到QSlite数据库表的QsqlTableModel。
该表由三列组成。我对仅编辑具有0/1值的第二列(索引1)感兴趣。在本专栏中,我想作为代表(但使用持久化编辑器)放置一个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__()
在这种情况下,无需实现自定义模型,只需具有自定义委托的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):
value = 1 if editor.isChecked() else 0
model.setData(index, value)
def setEditorData(self, editor, index):
value = bool(index.data())
editor.setChecked(value)
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_())