微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

qtableview 无法显示新插入的行

如何解决qtableview 无法显示新插入的行

使用QtableView + QsqlTableModel组合时,QtableView插入新行后无法正常显示插入行。

id 字段被隐藏。 EditStrategy 是 OnFieldChange。有一个按钮可以在模型的末尾插入一个新的空行。在用户填写所有字段并点击回车或点击其他行后,预期的行为是将行提交到数据库并且视图保留新行。然而,QsqlTableModel 成功将数据插入到数据库表中,但tableview 新插入的行变为空且字段不可编辑。

如果 id 字段未隐藏且明确提供,则行为会更改为所需的行为。然而,如果 id 未隐藏且未手动填充,则上述行为将再次失败。

为什么会这样?

这是最小的可重现代码。您将不得不更改数据库配置文件。并使用自动增量 id 连接到表:

import sys

from PyQt5 import QtCore,QtGui,QtWidgets
from PyQt5.QtCore import QModelIndex
from PyQt5.Qtsql import QsqlDatabase,QsqlTableModel
from PyQt5.QtWidgets import QPushButton


class Ui_main(object):
    def setupUi(self,main):
        main.setobjectName("main")
        main.resize(781,652)
        main.setContextMenuPolicy(QtCore.Qt.NoContextMenu)

        self.verticalLayoutWidget = QtWidgets.QWidget(main)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(10,10,761,631))
        self.verticalLayoutWidget.setobjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0,0)
        self.verticalLayout.setobjectName("verticalLayout")

        # Replace values with your database configurations
        # But the table you refer to must have autoincremented primary key
        database = QsqlDatabase.addDatabase('QPsql')
        database.setHostName('localhost')
        database.setPort(5432)
        database.setDatabaseName('some_database')
        database.setUserName('some_user')
        database.setPassword('some_password')
        database.open()

        button_add = QPushButton("AddRow")
        button_add.clicked.connect(self.addRow)
        self.verticalLayout.addWidget(button_add)

        self.tableView = QtWidgets.QTableView(self.verticalLayoutWidget)
        self.tableView.setobjectName("tableView")
        self.tableView.verticalHeader().setVisible(False)
        self.verticalLayout.addWidget(self.tableView)

        self.table_model = QsqlTableModel(self.tableView,database)
        table_name = 'some_table'
        self.table_model.setTable(table_name)

        self.table_model.setEditStrategy(QsqlTableModel.OnFieldChange)
        self.table_model.select()

        self.tableView.setModel(self.table_model)
        self.tableView.hideColumn(0)

        self.retranslateUi(main)
        QtCore.QMetaObject.connectSlotsByName(main)

    def retranslateUi(self,main):
        _translate = QtCore.QCoreApplication.translate
        main.setwindowTitle(_translate("main","main"))

    def addRow(self):
        count = self.table_model.rowCount(QModelIndex())
        self.table_model.insertRow(count)
        self.tableView.scrollToBottom()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    main_window = QtWidgets.QWidget()
    window = Ui_main()
    window.setupUi(main_window)
    main_window.show()
    sys.exit(app.exec_())

更新:

我现在使用的临时解决方法是从获取的表中找到最大 id 并将 max_id + 1 附加到新插入的行。因此,该行在提交到数据库时有一个 id。但是,这似乎不是正确的方法,因为数据库本身处理主键...

更新 2: 这是我的数据库表的样子:

设计:

book_of_accounts: table
+ columns
    id: bigint NN default nextval('book_of_accounts_id_seq'::regclass)
    code: varchar(256) NN
    name: varchar(1024) NN
    account_type: varchar(256) NN
    quantitative: boolean NN
    monetary: boolean NN
    subconoto_1: varchar(256)
    subconoto_2: varchar(256)
    subconoto_3: varchar(256)
+ indices
    book_of_accounts_pkey: unique (id)
    bookofaccounts_code: unique (code)
    bookofaccounts_name: index (name)
+ keys
    book_of_accounts_pkey: PK (id)

sql

create table if not exists book_of_accounts
(
    id bigserial not null
        constraint book_of_accounts_pkey
        primary key,code varchar(256) not null,name varchar(1024) not null,account_type varchar(256) not null,quantitative boolean not null,monetary boolean not null,subconoto_1 varchar(256),subconoto_2 varchar(256),subconoto_3 varchar(256)
);

alter table book_of_accounts owner to hamlet;

create unique index if not exists bookofaccounts_code
    on book_of_accounts (code);

create index if not exists bookofaccounts_name
    on book_of_accounts (name);

解决方法

好的,所以问题似乎是(引用自 Qt docs):

注意:为了防止仅将部分初始化的行插入数据库,对于新插入的行,OnFieldChange 的行为将类似于 OnRowChange。

要更新表格并显示新插入的行,您可以在数据更改时调用模型的 submitAll() 方法。

完整的更新代码(注释中标记的更新):

import sys

from PyQt5 import QtCore,QtGui,QtWidgets
from PyQt5.QtCore import QModelIndex
from PyQt5.QtSql import QSqlDatabase,QSqlTableModel
from PyQt5.QtWidgets import QPushButton

class Ui_main(object):
    def setupUi(self,main):
        main.setObjectName("main")
        main.resize(781,652)
        main.setContextMenuPolicy(QtCore.Qt.NoContextMenu)

        self.verticalLayoutWidget = QtWidgets.QWidget(main)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(10,10,761,631))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0,0)
        self.verticalLayout.setObjectName("verticalLayout")

        # Replace values with your database configurations
        # But the table you refer to must have autoincremented primary key
        database = QSqlDatabase.addDatabase('QPSQL')
        database.setHostName('localhost')
        database.setPort(5432)
        database.setDatabaseName('dbname')
        database.setUserName('postgres')
        database.setPassword('password')
        database.open()

        button_add = QPushButton("AddRow")
        button_add.clicked.connect(self.addRow)
        self.verticalLayout.addWidget(button_add)

        self.tableView = QtWidgets.QTableView(self.verticalLayoutWidget)
        self.tableView.setObjectName("tableView")
        self.tableView.verticalHeader().setVisible(False)
        self.verticalLayout.addWidget(self.tableView)

        self.table_model = QSqlTableModel(self.tableView,database)
        table_name = 'units'
        self.table_model.setTable(table_name)

        self.table_model.setEditStrategy(QSqlTableModel.OnFieldChange)
        self.table_model.select()
        ## ========== ADDED ========== ##
        self.table_model.sort(0,0)    # DEFAULT SORT TO SEE NEW ITEMS AT END       
        self.table_model.dataChanged.connect(self.on_dataChanged) # CONNECT DATA CHANGE SIGNAL TO CUSTOM SLOT
        ## =========================== ##

        self.tableView.setModel(self.table_model)
        self.tableView.hideColumn(0)

        self.retranslateUi(main)
        QtCore.QMetaObject.connectSlotsByName(main)

    def retranslateUi(self,main):
        _translate = QtCore.QCoreApplication.translate
        main.setWindowTitle(_translate("main","main"))

    def addRow(self):
        count = self.table_model.rowCount(QModelIndex())
        self.table_model.insertRow(count)
        self.tableView.scrollToBottom()

    ## ========== ADDED ========== ##
    # SLOT FIRED WHEN DATA CHANGES
    def on_dataChanged(self,topLeft,bottomRight,roles):
        self.table_model.submitAll()  # COMMIT TO DB
        self.table_model.select()     # RESELECT FROM DB
        self.table_model.sort(0,0)   # SORT
    ## =========================== ##

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    main_window = QtWidgets.QWidget()
    window = Ui_main()
    window.setupUi(main_window)
    main_window.show()
    sys.exit(app.exec_())

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。