如何将所选项目从 QListWidget、QTableWidget 保存到 Qsettings
Posted
技术标签:
【中文标题】如何将所选项目从 QListWidget、QTableWidget 保存到 Qsettings【英文标题】:How to save selected Items to Qsettings from QListWidget, QTableWidget 【发布时间】:2019-05-24 12:10:29 【问题描述】:我正在使用 PyQt5 和 Py3.7,我正在尝试遍历我的所有 Qlistwidgets 并保存它们的字符串数据,但也保存该小部件上的所有选定项目。我从here 稍微修改了循环,但是在使用listwidget 数组循环保存和恢复所选项目时遇到了一些麻烦。我检查了文档,但似乎无法理解如何从 SetArrayIndex 的 Qt 文档here 中将其他选项添加到数组中(例如保存所有选定的项目)。
我的 listWidgets 已将 selectionMode 设置为 MultiSelection。 我目前正在使用这个保存:
def save_list_data(self):
self.settings = QSettings("data.ini", QSettings.IniFormat)
for name, obj in inspect.getmembers(self):
if isinstance(obj, QListWidget):
name = obj.objectName()
self.settings.beginWriteArray(name)
for i in range(obj.count()):
self.settings.setArrayIndex(i)
self.settings.setValue(name, obj.item(i).text())
self.settings.endArray()
然后使用以下方法恢复 listWidget 数据:
def open_list_data(self):
self.settings = QSettings("data.ini", QSettings.IniFormat)
for name, obj in inspect.getmembers(self):
if isinstance(obj, QListWidget):
name = obj.objectName()
size = self.settings.beginReadArray(name)
for i in range(size):
self.settings.setArrayIndex(i)
value = self.settings.value(name)
if value != None:
obj.addItem(value)
self.settings.endArray()
这适用于数据,但我怎样才能从 ListWidgets 中获取 selectedItems 以保存和恢复?
【问题讨论】:
我正在使用 PyQt5。 【参考方案1】:对于我的解决方案,请考虑以下几点:
使用检查模块可能对其他库有益,但对于 Qt,小部件不一定是该类的成员,因此最好使用 Qt 内省本身使用 findChildren。
在您使用的示例中,您仅保存文本,但 QListWidgetItem 可以包含与角色相关的更多信息,例如背景色、前景色等。因此,我将使用 QDataStream 运算符,因为这需要并保存获取项目信息。
我将使用“objectname/property”格式来保存信息,因为同一个小部件可以有多个您要保存的属性。
要保存选中项的信息,只需要保存行即可。
综合以上情况,解决办法是:
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.listwidget_1 = QtWidgets.QListWidget(
objectName="listwidget_1",
selectionMode=QtWidgets.QAbstractItemView.MultiSelection
)
listwidget_2 = QtWidgets.QListWidget(
objectName="listwidget_2",
selectionMode=QtWidgets.QAbstractItemView.MultiSelection
)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.listwidget_1)
lay.addWidget(listwidget_2)
self.read_settings()
def closeEvent(self, event):
self.write_settings()
super().closeEvent(event)
def read_settings(self):
settings = QtCore.QSettings("data.ini", QtCore.QSettings.IniFormat)
childrens = self.findChildren(QtWidgets.QWidget)
for children in childrens:
if isinstance(children, QtWidgets.QListWidget) and children.objectName():
settings.beginGroup(children.objectName())
items = settings.value("items")
selecteditems = settings.value("selecteditems")
selectionMode = settings.value("selectionMode", type=QtWidgets.QAbstractItemView.SelectionMode)
children.setSelectionMode(selectionMode)
# In the first reading the initial values must be established
if items is None:
if children.objectName() == "listwidget_1":
for i in range(10):
children.addItem(QtWidgets.QListWidgetItem(str(i)))
elif children.objectName() == "listwidget_2":
for i in "abcdefghijklmnopqrstuvwxyz":
children.addItem(QtWidgets.QListWidgetItem(i))
else:
stream = QtCore.QDataStream(items, QtCore.QIODevice.ReadOnly)
while not stream.atEnd():
it = QtWidgets.QListWidgetItem()
stream >> it
children.addItem(it)
stream = QtCore.QDataStream(selecteditems, QtCore.QIODevice.ReadOnly)
while not stream.atEnd():
row = stream.readInt()
it = children.item(row)
it.setSelected(True)
settings.endGroup()
def write_settings(self):
settings = QtCore.QSettings("data.ini", QtCore.QSettings.IniFormat)
childrens = self.findChildren(QtWidgets.QWidget)
for children in childrens:
if isinstance(children, QtWidgets.QListWidget) and children.objectName():
settings.beginGroup(children.objectName())
items = QtCore.QByteArray()
stream = QtCore.QDataStream(items, QtCore.QIODevice.WriteOnly)
for i in range(children.count()):
stream << children.item(i)
selecteditems = QtCore.QByteArray()
stream = QtCore.QDataStream(selecteditems, QtCore.QIODevice.WriteOnly)
for it in children.selectedItems():
stream.writeInt(children.row(it))
settings.setValue("items", items)
settings.setValue("selecteditems", selecteditems)
settings.setValue("selectionMode", children.selectionMode())
settings.endGroup()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
加:
import contextlib
from PyQt5 import QtCore, QtGui, QtWidgets
class SettingsManager:
def __init__(self, filename):
self.m_settings = QtCore.QSettings(filename, QtCore.QSettings.IniFormat)
@property
def settings(self):
return self.m_settings
def read(self, widget):
self.settings.beginGroup(widget.objectName())
if isinstance(widget, QtWidgets.QAbstractItemView):
selectionMode = self.settings.value(
"selectionMode", type=QtWidgets.QAbstractItemView.SelectionMode
)
widget.setSelectionMode(selectionMode)
if isinstance(widget, QtWidgets.QListWidget):
items = self.settings.value("items")
selecteditems = self.settings.value("selecteditems")
# In the first reading the initial values must be established
if items is None:
self.read_defaults(widget)
else:
stream = QtCore.QDataStream(items, QtCore.QIODevice.ReadOnly)
while not stream.atEnd():
it = QtWidgets.QListWidgetItem()
stream >> it
widget.addItem(it)
stream = QtCore.QDataStream(
selecteditems, QtCore.QIODevice.ReadOnly
)
while not stream.atEnd():
row = stream.readInt()
it = widget.item(row)
if it is not None:
it.setSelected(True)
if isinstance(widget, QtWidgets.QTableWidget):
rowCount = self.settings.value("rowCount", type=int)
columnCount = self.settings.value("columnCount", type=int)
widget.setRowCount(rowCount)
widget.setColumnCount(columnCount)
items = self.settings.value("items")
if items is None:
self.read_defaults(widget)
else:
stream = QtCore.QDataStream(items, QtCore.QIODevice.ReadOnly)
while not stream.atEnd():
it = QtWidgets.QTableWidgetItem()
i = stream.readInt()
j = stream.readInt()
stream >> it
widget.setItem(i, j, it)
selecteditems = self.settings.value("selecteditems")
stream = QtCore.QDataStream(
selecteditems, QtCore.QIODevice.ReadOnly
)
while not stream.atEnd():
i = stream.readInt()
j = stream.readInt()
it = widget.item(i, j)
if it is not None:
it.setSelected(True)
self.settings.endGroup()
def write(self, widget):
self.settings.beginGroup(widget.objectName())
if isinstance(widget, QtWidgets.QAbstractItemView):
self.settings.setValue("selectionMode", widget.selectionMode())
if isinstance(widget, QtWidgets.QListWidget):
items = QtCore.QByteArray()
stream = QtCore.QDataStream(items, QtCore.QIODevice.WriteOnly)
for i in range(widget.count()):
stream << widget.item(i)
self.settings.setValue("items", items)
selecteditems = QtCore.QByteArray()
stream = QtCore.QDataStream(
selecteditems, QtCore.QIODevice.WriteOnly
)
for it in widget.selectedItems():
stream.writeInt(widget.row(it))
self.settings.setValue("selecteditems", selecteditems)
if isinstance(widget, QtWidgets.QTableWidget):
self.settings.setValue("rowCount", widget.rowCount())
self.settings.setValue("columnCount", widget.columnCount())
items = QtCore.QByteArray()
stream = QtCore.QDataStream(items, QtCore.QIODevice.WriteOnly)
for i in range(widget.rowCount()):
for j in range(widget.columnCount()):
it = widget.item(i, j)
if it is not None:
stream.writeInt(i)
stream.writeInt(j)
stream << it
self.settings.setValue("items", items)
selecteditems = QtCore.QByteArray()
stream = QtCore.QDataStream(
selecteditems, QtCore.QIODevice.WriteOnly
)
for it in widget.selectedItems():
# print(it.row(), it.column())
stream.writeInt(it.row())
stream.writeInt(it.column())
self.settings.setValue("selecteditems", selecteditems)
self.settings.endGroup()
def release(self):
self.m_settings.sync()
def read_defaults(self, widget):
if widget.objectName() == "listwidget_1":
widget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
for i in range(10):
widget.addItem(QtWidgets.QListWidgetItem(str(i)))
elif widget.objectName() == "listwidget_2":
widget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
for i in "abcdefghijklmnopqrstuvwxyz":
widget.addItem(QtWidgets.QListWidgetItem(i))
elif widget.objectName() == "tablewidget":
widget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
widget.setRowCount(10)
widget.setColumnCount(10)
for i in range(widget.rowCount()):
for j in range(widget.columnCount()):
it = QtWidgets.QTableWidgetItem("-".format(i, j))
widget.setItem(i, j, it)
@contextlib.contextmanager
def settingsContext(filename):
manager = SettingsManager(filename)
try:
yield manager
finally:
manager.release()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.listwidget_1 = QtWidgets.QListWidget(objectName="listwidget_1")
listwidget_2 = QtWidgets.QListWidget(objectName="listwidget_2")
tablewidget = QtWidgets.QTableWidget(objectName="tablewidget")
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.listwidget_1)
lay.addWidget(listwidget_2)
lay.addWidget(tablewidget)
self.read_settings()
def closeEvent(self, event):
self.write_settings()
super().closeEvent(event)
def read_settings(self):
with settingsContext("data.ini") as m:
for children in self.findChildren(QtWidgets.QWidget):
if children.objectName():
m.read(children)
def write_settings(self):
with settingsContext("data.ini") as m:
for children in self.findChildren(QtWidgets.QWidget):
if children.objectName():
m.write(children)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
【讨论】:
这个方法只对静态项有效吗?我的列表中总会有不同的数据。因此,在您的评论initial values must be established
中的部分在我的情况下不起作用。有什么方法可以只识别选定的项目吗?基本上为 listWidgets 中的数据创建保存/恢复功能。除了选择之外,一切都在那里。
@Laylor010 我没有说这些项目是静态的,但必须有一个初始值。如果在应用程序的执行过程中动态添加项目,我的解决方案就可以工作。
能够让它工作,仍然对children.objectName()
和children.addItem
部分感到困惑。像这样的东西也适用于 tableWidgets 吗?
@Laylor010 如果你不告诉我你的困惑是什么我帮不了你,另一方面我已经创建了一个如何实现 QTableWidget 逻辑的示例
我将通过文档进一步查看它,感谢您的回答和 TableWidgets 的附加信息。以上是关于如何将所选项目从 QListWidget、QTableWidget 保存到 Qsettings的主要内容,如果未能解决你的问题,请参考以下文章
C#将所选项目从ListBox1添加到ListBox2,相反[关闭]