插入记录后使QTableView和数据库同步的最佳方法是什么?

问题描述 投票:1回答:3

假设我有一个带有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_()
python pyqt pyqt4
3个回答
2
投票

您仍然可以使用QSqlTableModel。您可以关闭表格视图中的所有编辑触发器,然后将模型传递到数据捕获表单,并使用QDataWidgetMapper让小部件绑定到模型,确保将提交模式设置为手动,以便您可以首先验证字段。


2
投票

RobbieE是对的,我可以使用表单编辑(通过QDataWidgetMapper)来代替直接单元格编辑,但是我的问题不是关于表单或单元格编辑。


1
投票

正如我在评论中已经提到的那样,您的第一种方法比第二种方法更有利,因为它可以防止您进行不必要的工作。但是,如果您担心QSqlTableModel.select传输的数据量(可能会使您的应用程序变慢),则可以改用QSqlTableModel.insertRecord(有关详细信息,请参见下面的示例)。这将尝试在数据库中插入记录,并且即使插入失败,它也会同时在模型中注册。因此,您必须通过QSqlTableModel.revertAll()再次手动将其删除(如果发生故障)。

© www.soinside.com 2019 - 2024. All rights reserved.