python-3.x - 如何保存 qtablewidget 的当前值?
问题描述
需要保存 QTableWidget 的当前值。QTableWidget 将在 QTabWidget 内部,并且将有几个相邻的选项卡,其中包含多个表。在表格里面会有QCheckBox,QComoBox作为cellwidgetitem,这些值也需要保存。除此之外,我还需要保存网格布局内的 QSpinBox 和 QDoubleSpinBox 的值。我正在从https://gist.github.com/eyllanesc/be8a476bb7038c7579c58609d7d0f031获取代码的帮助,它将 QLineEdit 的值保存在 QFormLayout 中,其中 QFormLayout 在 QTabWidget 中。如果实例化了多个选项卡,则无法保存选项卡内的 QLineEdit 值。此外,如果在 QTabWidget 下方添加 QTableWidget,则 QTableWidget 的值也无法保存。
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtCore import QFileInfo, QSettings
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import qApp, QApplication, QMainWindow, QFormLayout, QLineEdit, QTabWidget, QWidget, QAction, QVBoxLayout, QTableWidget, QTableWidgetItem
def restore(settings):
finfo = QFileInfo(settings.fileName())
print(settings.fileName())
if finfo.exists() and finfo.isFile():
for w in qApp.allWidgets():
mo = w.metaObject()
if w.objectName() != "":
for i in range(mo.propertyCount()):
name = mo.property(i).name()
val = settings.value("{}/{}".format(w.objectName(), name), w.property(name))
w.setProperty(name, val)
def save(settings):
for w in qApp.allWidgets():
mo = w.metaObject()
if w.objectName() != "":
for i in range(mo.propertyCount()):
name = mo.property(i).name()
settings.setValue("{}/{}".format(w.objectName(), name), w.property(name))
class mainwindow(QMainWindow):
settings = QSettings("gui.ng", QSettings.IniFormat)
def __init__(self, parent=None):
super(mainwindow, self).__init__(parent)
self.setObjectName("MainWindow")
self.initUI()
restore(self.settings)
def initUI(self):
exitAction = QAction(QIcon('icon\\exit.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(self.close)
self.toolbar = self.addToolBar('Exit')
self.toolbar.setMovable(False)
self.toolbar.addAction(exitAction)
self.tab_widget = QTabWidget(self) # add tab
self.tab_widget.setObjectName("tabWidget")
self.tab2 = QWidget()
self.tab2.setObjectName("tab2")
self.tab3 = QWidget()
self.tab3.setObjectName("tab3")
self.tab_widget.addTab(self.tab2, "Tab_2")
self.tab_widget.addTab(self.tab3, "Tab_3")
self.tab2UI()
self.tab3UI()
self.vlay = QVBoxLayout()
self.vlay.addWidget(self.tab_widget)
self.qtable = QTableWidget()
self.qtable.setRowCount(3)
self.qtable.setColumnCount(3)
self.qtable.setItem(0, 0, QTableWidgetItem("text1"))
self.qtable.setItem(0, 1, QTableWidgetItem("text1"))
self.qtable.setItem(0, 2, QTableWidgetItem("text1"))
self.qtable.setItem(1, 0, QTableWidgetItem("text2"))
self.qtable.setItem(1, 1, QTableWidgetItem("text2"))
self.qtable.setItem(1, 2, QTableWidgetItem("text2"))
self.qtable.setItem(2, 0, QTableWidgetItem("text3"))
self.qtable.setItem(2, 1, QTableWidgetItem("text3"))
self.qtable.setItem(2, 2, QTableWidgetItem("text3"))
self.vlay.addWidget(self.qtable)
self.qVlayWidget = QWidget()
self.qVlayWidget.setLayout(self.vlay)
self.setCentralWidget(self.qVlayWidget)
def tab2UI(self):
self.layout_2 = QFormLayout()
nameLe = QLineEdit(self)
nameLe.setObjectName("nameLe_2")
self.layout_2.addRow("Name_2", nameLe)
addressLe = QLineEdit()
addressLe.setObjectName("addressLe_2")
self.layout_2.addRow("Address_2", addressLe)
self.tab2.setLayout(self.layout_2)
def tab3UI(self):
self.layout_3 = QFormLayout()
nameLe = QLineEdit(self)
nameLe.setObjectName("nameLe_3")
self.layout_3.addRow("Name_3", nameLe)
addressLe = QLineEdit()
addressLe.setObjectName("addressLe_3")
self.layout_3.addRow("Address_3", addressLe)
self.tab3.setLayout(self.layout_3)
def closeEvent(self, event):
save(self.settings)
QMainWindow.closeEvent(self, event)
def main():
app = QApplication(sys.argv)
ex = mainwindow()
ex.setGeometry(100, 100, 1000, 600)
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
解决方案
QLineEdit 数据被存储,问题是它没有显示。小部件的visible
属性取决于它的祖先[s];由于 QTabWidget 的每个选项卡都有一个 QWidget,因此只有当前一个可见,而另一个(包括它们的所有子级)不可见。QLineEdit 是一个复杂的小部件,如果您手动取消设置其所有内部组件的可见属性,它们将无法再次正确恢复。
如果您在将第二个选项卡设置为当前选项卡的情况下关闭窗口,这一点就会变得清晰:一旦您再次打开它,将显示第二个选项卡并正确显示其内容,而第一个 QLineEdit 不会。
一种解决方法是检查小部件是否“存储”为不可见并且具有父级。如果是这种情况,请不要应用 visible 属性。
def restore(settings):
# ...
for w in qApp.allWidgets():
mo = w.metaObject()
parent = w.parent()
if w.objectName() != "":
for i in range(mo.propertyCount()):
name = mo.property(i).name()
val = settings.value("{}/{}".format(w.objectName(), name), w.property(name))
if name == 'visible' and val == 'false' and parent:
continue
w.setProperty(name, val)
也就是说,这显然不是保存任何小部件数据的好方法,因为它保存了它拥有的每个属性:示例的标题是“保存和恢复小部件的功能”,而不是您需要的可编辑数据.
此外,QTableWidget 内容不能使用此方法存储,因为它的数据不是小部件属性的一部分(无论如何都没有保存任何其他内容,因为您没有设置它的对象名称)。
您必须找到自己的实现来保存这些内容,这可能类似于以下代码。
请注意,我使用 QByteArray 来存储表数据。您创建一个 QByteArray,然后创建一个 QDataStream,并将其作为参数,用于读取或写入。请注意,读取和写入都是相应的,因为数据总是在写入时附加或在每次读取时“弹出”。
class mainwindow(QMainWindow):
# ...
def save(self):
# using findChildren is for simplicity, it's probably better to create
# your own list of widgets to cycle through
for w in self.findChildren((QLineEdit, QTableWidget)):
name = w.objectName()
if isinstance(w, QLineEdit):
self.settings.setValue("{}/text".format(name), w.text())
elif isinstance(w, QTableWidget):
# while we could add sub-setting keys for each combination of
# row/column items, it's better to store the data in a single
# "container"
data = QByteArray()
stream = QDataStream(data, QIODevice.WriteOnly)
rowCount = w.rowCount()
columnCount = w.columnCount()
# write the row and column count first
stream.writeInt(rowCount)
stream.writeInt(columnCount)
# then write the data
for row in range(rowCount):
for col in range(columnCount):
stream.writeQString(w.item(row, col).text())
self.settings.setValue("{}/data".format(name), data)
def restore(self):
for w in self.findChildren((QLineEdit, QTableWidget)):
name = w.objectName()
if isinstance(w, QLineEdit):
w.setText(self.settings.value("{}/text".format(name), w.text()))
elif isinstance(w, QTableWidget):
data = self.settings.value("{}/data".format(name))
if not data:
continue
stream = QDataStream(data, QIODevice.ReadOnly)
# read the row and column count first
rowCount = stream.readInt()
columnCount = stream.readInt()
w.setRowCount(rowCount)
w.setColumnCount(columnCount)
# then read the data
for row in range(rowCount):
for col in range(columnCount):
cellText = stream.readQString()
if cellText:
w.item(row, col).setText(cellText)
推荐阅读
- mysql - Sql,将行值与该列中的行平均值进行比较
- model-view-controller - 使用 mockmvc 测试 Api REST
- python - 如何使用映射填充 pandas 数据框中的 NaN 或 Null 值?
- c - Clang-Format 用 ifdefs 中的函数头打破缩进
- docker - 如何理解气流容器的“不健康”状态
- python - 根据列表操作行值
- html - 将管理员添加到电子商务网站的页面
- ojs - 如何在 OJS 中更改发件人地址?
- sql - SQL Server - 在 UNPIVOT 期间冲突列类型
- javascript - javascript async 代码同步运行,而不是异步运行