如何保存 qtablewidget 的当前值? [复制]
Posted
技术标签:
【中文标题】如何保存 qtablewidget 的当前值? [复制]【英文标题】:how to save current values of qtablewidget? [duplicate] 【发布时间】:2019-09-01 11:22:57 【问题描述】:需要保存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()
【问题讨论】:
【参考方案1】:QLineEdit 数据被存储,问题是它没有显示出来。小部件的visible
属性取决于它的祖先[s];由于 QTabWidget 的每个选项卡都有一个 QWidget,因此只有当前一个可见,而另一个(包括 all 它们的子级)不可见。 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)
【讨论】:
您的回答很有趣,但可能有一个小问题,QTableWidgetItem 不仅可以保存文本,还可以保存颜色、字体等。您可以使用“>>”和“***.com/a/56317981/6622587 是的,我最初使用它,但由于问题的性质,我选择了“更简单”的解决方案。如果以后有时间,我也会对其进行编辑以解释这一点。以上是关于如何保存 qtablewidget 的当前值? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何将所选项目从 QListWidget、QTableWidget 保存到 Qsettings
如何使用openpyxl将qtablewidget数据保存到excel文件中
兄弟或兄弟AtRow()函数如何从QTableWidget中的隐藏列中检索值?