如何解决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)
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 举报,一经查实,本站将立刻删除。