QSettings не сохраняет информацию после закрытия программы
Программа с QTableView, вписываются в таблицу два параметра Name и Points. Пытался сохранять информацию при помощи QSettings, однако при выходе из программы ничего не сохраняется даже при наличии .ini файла.
Изменено: насколько я понял, я просто не подгружаю настройки. отсюда вопрос, как сделать сохранение и подгрузку настроек?
Counter.py
import sys
from random import randint
from PyQt5 import QtWidgets, QtCore, QtGui
class CustomTableView(QtWidgets.QTableView):
def __init__(self, parent=None):
super(CustomTableView, self).__init__(parent)
self.setSortingEnabled(True)
def KeyPressEvent(self, event: QtGui.QKeyEvent):
if event.key() == QtCore.Qt.Key_Enter:
print("Key_Enter ")
elif event.key() == QtCore.Qt.Key_Return:
print("Key_Return ")
class NumberSortModel(QtCore.QSortFilterProxyModel):
def lessThan(self, left_index: "QModelIndex",
right_index: "QModelIndex") -> bool:
left_var: str = left_index.data(QtCore.Qt.EditRole)
right_var: str = right_index.data(QtCore.Qt.EditRole)
try:
return float(left_var) < float(right_var)
except (ValueError, TypeError):
pass
try:
return left_var < right_var
except TypeError:
return True
class Counter(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Counter, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.Window)
QtWidgets.QMainWindow.__init__(self)
font = QtGui.QFont("Formula1", 10, QtGui.QFont.Bold)
self.setFont(font)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
grid_layout = QtWidgets.QGridLayout()
central_widget.setLayout(grid_layout)
self.model = QtGui.QStandardItemModel(self)
self.model.setHorizontalHeaderLabels(["Name" , "Points"])
self.proxy = NumberSortModel()
self.proxy.setSourceModel(self.model)
self.table = CustomTableView(self)
self.table.setModel(self.proxy)
self.table.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
update_button = QtWidgets.QPushButton("Update")
update_button.clicked.connect(self.on_update_button)
sort_button = QtWidgets.QPushButton("Sort")
self.qlineedit_name = QtWidgets.QLineEdit()
self.qlineedit_name.resize(24, 80)
self.qlineedit_points = QtWidgets.QLineEdit()
self.qlineedit_points.resize(24, 80)
horisontal_layout = QtWidgets.QHBoxLayout()
horisontal_layout.addWidget(self.qlineedit_name, stretch=1)
horisontal_layout.addWidget(self.qlineedit_points, stretch=1)
horisontal_layout.addStretch(1)
horisontal_layout.addWidget(update_button)
horisontal_layout.addWidget(sort_button)
horisontal_layout.setAlignment(QtCore.Qt.AlignRight)
grid_layout.addLayout(horisontal_layout, 0, 0)
grid_layout.addWidget(self.table, 1, 0)
settings = QtCore.QSettings("settings.ini", QtCore.QSettings.IniFormat)
settings.setValue("Name", "Points")
settings.sync()
def on_update_button(self):
name = self.qlineedit_name.text().strip()
point = self.qlineedit_points.text().strip() if self.qlineedit_points.text().strip() else '0'
if not point.isdigit():
msg = QtWidgets.QMessageBox.information(self, 'ВНИМАНИЕ', 'Заполните правильно поле ввода Points!')
return msg
if not name:
msg = QtWidgets.QMessageBox.information(self, 'ВНИМАНИЕ', 'Заполните поле ввода Name!')
return msg
rows = self.table.model().rowCount()
add_record = True
for row in range(rows):
if name == self.proxy.data(self.proxy.index(row, 0)):
#print(name)
add_record = False
row_edit = row
break
if add_record:
if self.table.selectedIndexes():
row = self.table.selectedIndexes()[-1].row()
self.model.insertRow(row+1, [QtGui.QStandardItem(name),
QtGui.QStandardItem(point)])
else:
self.model.appendRow([QtGui.QStandardItem(name),
QtGui.QStandardItem(point)])
else:
self.model.setData(self.model.index(row_edit, 1), point, QtCore.Qt.EditRole)
self.qlineedit_name.clear()
self.qlineedit_points.clear()
if __name__ == "__main__":
application = QtWidgets.QApplication([])
window = Counter()
window.setWindowTitle("Counter")
window.setMinimumSize(480, 380)
window.show()
sys.exit(application.exec_())
Ответы (1 шт):
Я немного изменил ваше приложение:
- перешел с виджета
QTableViewна виджетQTableWidget; - реализовал свою сортировку по столбцу "Points" используя класс
QStyledItemDelegate; - добавил функциональность по нажатию кнопки "Sort";
- реализовал сохранение настроек приложения используя класс
QSettings.
QSettings - это абстракция позволяющая вам сохранять и восстанавливать параметры приложения
в портативном режиме. Он также поддерживает пользовательские форматы хранения.
Я добавил некоторую раскраску ячеек таблицы, когда значение point больше 777,
для того, чтобы продемонстрировать сохранение настроек, в том числе и цвета ячейки.
Объекты, задействованные в сохранение настроек, помечены комментарием # QSettings.
Пробуйте, но помните, что порядок написанных строк - имеет значение:
import sys
import contextlib
from random import randint
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.Qt import *
class SettingsManager: # QSettings
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.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.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() == "tableWidget":
widget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
widget.setRowCount(0) #(1)
widget.setColumnCount(2)
@contextlib.contextmanager # QSettings
def settingsContext(filename):
manager = SettingsManager(filename)
try:
yield manager
finally:
manager.release()
class Delegate(QStyledItemDelegate):
colorChanged = pyqtSignal(int, int, int)
def __init__(self, parent=None):
QStyledItemDelegate.__init__(self, parent)
self.parent = parent
def createEditor(self, parent, options, index):
if index.column() == 1:
value = index.data()
editor = QLineEdit(parent)
return editor
def setEditorData(self, editor, index):
if index.column() == 1:
value = index.model().data(index, Qt.EditRole)
try: value = int(value)
except: value = 0
editor.setText(f'{value:>20}')
def updateEditorGeometry(self, editor, options, index):
editor.setGeometry(options.rect)
def setModelData(self, editor, model, index):
if index.column() == 1:
try: value = int(editor.text())
except: value = 0
value = f'{value:>20}'
model.setData(index, value, Qt.EditRole)
self.colorChanged.emit(index.row(), index.column(), int(value))
class Counter(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
self.tableWidget = QTableWidget(0, 2)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setHorizontalHeaderLabels(["Name" , "Points"])
self.tableWidget.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
delegate = Delegate(self)
delegate.colorChanged.connect(self.color_changed)
self.tableWidget.setItemDelegate(delegate)
update_button = QtWidgets.QPushButton("Update")
update_button.clicked.connect(self.on_update_button)
self.sort_button = QtWidgets.QPushButton("Sort")
self.sort_button.setCheckable(True)
self.sort_button.toggled.connect(self.on_sort_button)
self.qlineedit_name = QtWidgets.QLineEdit()
self.qlineedit_name.resize(24, 80)
self.qlineedit_points = QtWidgets.QLineEdit()
self.qlineedit_points.resize(24, 80)
horisontal_layout = QtWidgets.QHBoxLayout()
horisontal_layout.addWidget(self.qlineedit_name, stretch=1)
horisontal_layout.addWidget(self.qlineedit_points, stretch=1)
horisontal_layout.addStretch(1)
horisontal_layout.addWidget(update_button)
horisontal_layout.addWidget(self.sort_button)
horisontal_layout.setAlignment(QtCore.Qt.AlignRight)
grid_layout = QtWidgets.QGridLayout(central_widget)
grid_layout.addLayout(horisontal_layout, 0, 0)
grid_layout.addWidget(self.tableWidget, 1, 0)
self.read_settings() # QSettings
self.tableWidget.setSortingEnabled(True)
self.tableWidget.sortItems(1, Qt.DescendingOrder)
def color_changed(self, row, col, value):
if value > 777:
color = QColor(qrand() % 256, qrand() % 256, qrand() % 256)
self.tableWidget.item(row, col).setBackground(color)
self.tableWidget.item(row, col).setFont(QFont("Consolas", 10, QFont.Bold))
else:
self.tableWidget.item(row, col).setBackground(QColor("#fff"))
self.tableWidget.item(row, col).setFont(QFont("Consolas", 10))
def on_update_button(self):
name = self.qlineedit_name.text().strip()
point = self.qlineedit_points.text().strip() if self.qlineedit_points.text().strip() else '0'
if not point.isdigit():
msg = QtWidgets.QMessageBox.information(
self, 'ВНИМАНИЕ', 'Заполните правильно поле ввода Points!')
return msg
if not name:
msg = QtWidgets.QMessageBox.information(
self, 'ВНИМАНИЕ', 'Заполните поле ввода Name!')
return msg
self.tableWidget.setSortingEnabled(False)
rows = self.tableWidget.rowCount()
add_record = True
for row in range(rows):
if name == self.tableWidget.item(row, 0).text():
#print(name)
add_record = False
row_edit = row
break
if add_record:
if self.tableWidget.selectedIndexes():
row = self.tableWidget.selectedIndexes()[-1].row()
self.tableWidget.insertRow(row+1)
self.tableWidget.setItem(row+1, 0, QTableWidgetItem(name))
self.tableWidget.setItem(row+1, 1, QTableWidgetItem(f'{point:>20}'))
self.color_changed(row+1, 1, int(point))
else:
self.tableWidget.insertRow(rows)
self.tableWidget.setItem(rows, 0, QTableWidgetItem(name))
self.tableWidget.setItem(rows, 1, QTableWidgetItem(f'{point:>20}'))
self.color_changed(rows, 1, int(point))
else:
self.tableWidget.setItem(row_edit, 1, QTableWidgetItem(f'{point:>20}'))
self.color_changed(row_edit, 1, int(point))
self.qlineedit_name.clear()
self.qlineedit_points.clear()
self.tableWidget.setSortingEnabled(True)
def on_sort_button(self, state):
if state: self.tableWidget.sortItems(1, Qt.DescendingOrder)
else: self.tableWidget.sortItems(1, Qt.AscendingOrder)
def closeEvent(self, event): # QSettings
self.tableWidget.setSortingEnabled(False)
self.write_settings()
super().closeEvent(event)
def read_settings(self): # QSettings
with settingsContext("data_table_widget.ini") as m:
for children in self.findChildren(QtWidgets.QWidget):
if children.objectName():
m.read(children)
def write_settings(self): # QSettings
with settingsContext("data_table_widget.ini") as m:
for children in self.findChildren(QtWidgets.QWidget):
if children.objectName():
m.write(children)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
app.setFont(QtGui.QFont("Consolas", 10))
app.setStyle('Fusion')
w = Counter()
w.setWindowTitle("Counter")
w.setMinimumSize(480, 380)
w.show()
sys.exit(app.exec_())
