假设我有一个带有QSqlTableModel / Database的QTableView。我不想让用户编辑QTableView中的单元格。有CRUD按钮可以打开新的对话框形式,并且用户应该输入数据。用户单击对话框的“确定”按钮后,将新记录插入数据库并进行查看(使其同步)的最佳方法是什么,因为此时数据库可能不可用(例如,在连接互联网时插入远程数据库)问题)?
我主要关心的是,我不想在视图中显示幻像记录,并且我希望用户知道该记录未输入数据库中。
我放置了一些python代码(但是对于Qt,我的问题是相同的)来说明这一点,并且在注释中还有其他一些问题:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtSql import *
class Window(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.model = QSqlTableModel(self)
self.model.setTable("names")
self.model.setHeaderData(0, Qt.Horizontal, "Id")
self.model.setHeaderData(1, Qt.Horizontal, "Name")
self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)
self.model.select()
self.view = QTableView()
self.view.setModel(self.model)
self.view.setSelectionMode(QAbstractItemView.SingleSelection)
self.view.setSelectionBehavior(QAbstractItemView.SelectRows)
#self.view.setColumnHidden(0, True)
self.view.resizeColumnsToContents()
self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.view.horizontalHeader().setStretchLastSection(True)
addButton = QPushButton("Add")
editButton = QPushButton("Edit")
deleteButton = QPushButton("Delete")
exitButton = QPushButton("Exit")
hbox = QHBoxLayout()
hbox.addWidget(addButton)
hbox.addWidget(editButton)
hbox.addWidget(deleteButton)
hbox.addStretch()
hbox.addWidget(exitButton)
vbox = QVBoxLayout()
vbox.addWidget(self.view)
vbox.addLayout(hbox)
self.setLayout(vbox)
addButton.clicked.connect(self.addRecord)
#editButton.clicked.connect(self.editRecord) # omitted for simplicity
#deleteButton.clicked.connect(self.deleteRecord) # omitted for simplicity
exitButton.clicked.connect(self.close)
def addRecord(self):
# just QInputDialog for simplicity
value, ok = QInputDialog.getText(self, 'Input Dialog', 'Enter the name:')
if not ok:
return
# Now, what is the best way to insert the record?
# 1st approach, first in database, then model.select()
# it seems like the most natural way to me
query = QSqlQuery()
query.prepare("INSERT INTO names (name) VALUES(:name)")
query.bindValue( ":name", value )
if query.exec_():
self.model.select() # now we know the record is inserted to db
# the problem with this approach is that select() can be slow
# somehow position the view to newly added record?!
else:
pass
# message to user
# if the record can't be inserted to database,
# there's no way I will show that record in view
# 2nd approach, first in view (model cache), then in database
# actually, I don't know how to do this
# can somebody instruct me?
# maybe:
# record = ...
# self.model.insertRecord(-1, record) #
# submitAll()
# what if database is unavailable?
# what if submitAll() fails?
# in that case, how to have view and model in sync?
# is this the right approach?
# 3. is there some other approach?
app = QApplication(sys.argv)
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(":memory:")
db.open()
query = QSqlQuery()
query.exec_("DROP TABLE names")
query.exec_("CREATE TABLE names(id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, name TEXT)")
query.exec_("INSERT INTO names VALUES(1, 'George')")
query.exec_("INSERT INTO names VALUES(2, 'Rita')")
query.exec_("INSERT INTO names VALUES(3, 'Jane')")
query.exec_("INSERT INTO names VALUES(4, 'Steve')")
query.exec_("INSERT INTO names VALUES(5, 'Maria')")
query.exec_("INSERT INTO names VALUES(6, 'Bill')")
window = Window()
window.resize(600, 400)
window.show()
app.exec_()
您仍然可以使用QSqlTableModel
。您可以关闭表格视图中的所有编辑触发器,然后将模型传递到数据捕获表单,并使用QDataWidgetMapper
让小部件绑定到模型,确保将提交模式设置为手动,以便您可以首先验证字段。
RobbieE是对的,我可以使用表单编辑(通过QDataWidgetMapper)来代替直接单元格编辑,但是我的问题不是关于表单或单元格编辑。
正如我在评论中已经提到的那样,您的第一种方法比第二种方法更有利,因为它可以防止您进行不必要的工作。但是,如果您担心QSqlTableModel.select
传输的数据量(可能会使您的应用程序变慢),则可以改用QSqlTableModel.insertRecord
(有关详细信息,请参见下面的示例)。这将尝试在数据库中插入记录,并且即使插入失败,它也会同时在模型中注册。因此,您必须通过QSqlTableModel.revertAll()
再次手动将其删除(如果发生故障)。