使用 QSQLTable 模型和 QDataWidget 映射器在 Sqlite 表中插入记录时出现问题
我正在努力处理下面显示的代码,该代码使用带有 QDataWidget 映射器的 QSQLTable 模型从具有 3 列(“codice”(主键,自动增量)、“descrizione”、“peso”)的 SQLite 表加载数据。
我的问题是我定义了一个 QPushButton 来在这样的表中插入新记录,但我无法让它工作。我使用 self.model.insertRows 或 self.model.insertRecord 尝试了不同的方法,但没有成功。我没有收到任何错误,但未插入记录。
当然,存在我无法发现的概念错误。
import sys
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel
from PyQt5.QtWidgets import (
QApplication,
QComboBox,
QDataWidgetMapper,
QDoubleSpinBox,
QFormLayout,
QHBoxLayout,
QLabel,
QLineEdit,
QMainWindow,
QPushButton,
QSpinBox,
QTableView,
QVBoxLayout,
QWidget,
)
from connect_SQLITE import Database
db=Database.con
db.open()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
form = QFormLayout()
self.codice = QSpinBox()
self.codice.setRange(0, 2147483647)
self.codice.setDisabled(True)
self.descrizione = QLineEdit()
self.peso = QDoubleSpinBox()
self.peso.setDecimals(5)
self.peso.setRange(0, 9999.99999)
self.peso.setSingleStep(0.01)
form.addRow(QLabel("Codice Materiale"), self.codice)
form.addRow(QLabel("Nome Materiale"), self.descrizione)
form.addRow(QLabel("Peso specifico Materiale (Kg/dm3)"), self.peso)
self.model = QSqlTableModel(db=db)
self.mapper = QDataWidgetMapper()
self.mapper.setModel(self.model)
self.mapper.addMapping(self.codice, 0)
self.mapper.addMapping(self.descrizione, 1)
self.mapper.addMapping(self.peso, 2)
self.model.setTable("Prova")
self.model.select()
self.mapper.toFirst()
# tag::controls[]
self.setMinimumSize(QSize(400, 400))
controls = QHBoxLayout()
prev_rec = QPushButton("Precedente")
prev_rec.clicked.connect(self.mapper.toPrevious)
next_rec = QPushButton("Successivo")
next_rec.clicked.connect(self.mapper.toNext)
ins_rec = QPushButton("Inserimento")
ins_rec.clicked.connect(self.inserimento_materiale)
save_rec = QPushButton("Salvataggio modifiche")
save_rec.clicked.connect(self.mapper.submit)
controls.addWidget(prev_rec)
controls.addWidget(next_rec)
controls.addWidget(ins_rec)
controls.addWidget(save_rec)
layout.addLayout(form)
layout.addLayout(controls)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
# end::controls[]
def inserimento_materiale(self):
self.model.insertRows(self.model.rowCount(), 1)
self.model.setData(self.model.index(0,1), self.descrizione.text())
self.model.setData(self.model.index(0,2), self.peso)
self.model.submit()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
I'm struggling with the code shown below that loads data from a SQLite table which has 3 columns ("codice" (primary key, autoincrement), "descrizione", "peso") using QSQLTable model with QDataWidget mapper.
My problem is I defined a QPushButton to insert new record in such table but I'm not able to get it work. I tried different ways using self.model.insertRows or self.model.insertRecord but I was not successfully. I'm not getting any error but the record is not inserted.
For sure there are conceptual errors I can't catch.
import sys
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel
from PyQt5.QtWidgets import (
QApplication,
QComboBox,
QDataWidgetMapper,
QDoubleSpinBox,
QFormLayout,
QHBoxLayout,
QLabel,
QLineEdit,
QMainWindow,
QPushButton,
QSpinBox,
QTableView,
QVBoxLayout,
QWidget,
)
from connect_SQLITE import Database
db=Database.con
db.open()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
form = QFormLayout()
self.codice = QSpinBox()
self.codice.setRange(0, 2147483647)
self.codice.setDisabled(True)
self.descrizione = QLineEdit()
self.peso = QDoubleSpinBox()
self.peso.setDecimals(5)
self.peso.setRange(0, 9999.99999)
self.peso.setSingleStep(0.01)
form.addRow(QLabel("Codice Materiale"), self.codice)
form.addRow(QLabel("Nome Materiale"), self.descrizione)
form.addRow(QLabel("Peso specifico Materiale (Kg/dm3)"), self.peso)
self.model = QSqlTableModel(db=db)
self.mapper = QDataWidgetMapper()
self.mapper.setModel(self.model)
self.mapper.addMapping(self.codice, 0)
self.mapper.addMapping(self.descrizione, 1)
self.mapper.addMapping(self.peso, 2)
self.model.setTable("Prova")
self.model.select()
self.mapper.toFirst()
# tag::controls[]
self.setMinimumSize(QSize(400, 400))
controls = QHBoxLayout()
prev_rec = QPushButton("Precedente")
prev_rec.clicked.connect(self.mapper.toPrevious)
next_rec = QPushButton("Successivo")
next_rec.clicked.connect(self.mapper.toNext)
ins_rec = QPushButton("Inserimento")
ins_rec.clicked.connect(self.inserimento_materiale)
save_rec = QPushButton("Salvataggio modifiche")
save_rec.clicked.connect(self.mapper.submit)
controls.addWidget(prev_rec)
controls.addWidget(next_rec)
controls.addWidget(ins_rec)
controls.addWidget(save_rec)
layout.addLayout(form)
layout.addLayout(controls)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
# end::controls[]
def inserimento_materiale(self):
self.model.insertRows(self.model.rowCount(), 1)
self.model.setData(self.model.index(0,1), self.descrizione.text())
self.model.setData(self.model.index(0,2), self.peso)
self.model.submit()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是默认情况下映射器使用
AutoSubmit
submitPolicy()
:QSqlTableModel 使用
OnRowChange
editStrategy()
:
另外,您在第一行调用
setData()
,而不是 new。结果是,当调用
inserimento_materiale
并插入新行时,映射器的当前索引仍然是前一个(启动时的第一个,由于toFirst() 或
toPrevious()
或toNext()
之后的任何其他设置),setData()
在任何情况下都不起作用:AutoSubmit
政策,但尚未实际提交到数据库中,并且setData()
返回False
因为“对于 OnRowChange,仅当没有其他行具有缓存的更改时,索引才可能收到更改”;setData()
设置正确的行也不起作用,因为插入新行会导致映射器提交前一行中当前小部件的先前数据,并且不会正确更新新映射器指数;请注意,您的代码也有一个拼写错误:您尝试使用
self.peso
(这是一个小部件)调用setData()
。A可能的解决方案是在执行任何操作之前读取当前的小部件值,
revert()
模型数据(以避免将新数据保存在之前的索引上),将新数据提交到模型并在映射器中设置新索引:注意由于您有一个专用的提交按钮,因此您应该将映射器的提交策略更改为
ManualSubmit
,这会使事情变得更容易:The problem is that by default the mapper uses the
AutoSubmit
submitPolicy()
:And QSqlTableModel uses the
OnRowChange
editStrategy()
:Also, you're calling
setData()
on the first row, instead of the new one.The result is that when
inserimento_materiale
is called and a new row is inserted, the current index of the mapper is still the previous one (the first on startup, due totoFirst()
or any other set aftertoPrevious()
ortoNext()
),setData()
will not work in any case:AutoSubmit
policy, but it has not been actually submitted in the database, andsetData()
returnsFalse
because "For OnRowChange, an index may receive a change only if no other row has a cached change";setData()
will not work, as inserting a new row causes the mapper to submit the previous data of the current widgets in the previous row, and will not properly update the new mapper index;Be aware that your code also has a typo: you're trying to call
setData()
withself.peso
which is a widget.A possible solution is to read the current widget values before doing anything,
revert()
the model data (to avoid saving the new data on the previous index), submit the new data to the model and set the new index in the mapper:Note that since you have a dedicated submit button, you should change the mapper's submit policy to
ManualSubmit
, which makes things easier: