Python

[PyQt6] Save and Load Settings using QSettings

llHoYall 2023. 4. 6. 21:39

이번 포스팅에서는 QSettings를 사용하여 설정 정보를 저장하고 불러오는 방법을 살펴보겠습니다.

Example Application

import sys

from PyQt6.QtGui import QCloseEvent
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget


class MainWindow(QMainWindow):
    def __init__(self) -> None:
        super().__init__()

        widget = QWidget()

        self.setCentralWidget(widget)
        self.load_settings()

    def save_settings(self) -> None:
        print("Save")

    def load_settings(self) -> None:
        print("Load")

    def closeEvent(self, event: QCloseEvent) -> None:
        super().closeEvent(event)
        self.save_settings()


app = QApplication(sys.argv)
main = MainWindow()
main.show()
app.exec()

앞으로 다룰 내용의 기본이 되는 application을 작성하였습니다.

생성자가 호출되면 저장한 설정을 불러오도록 하였고, MainWindow가 종료될 때, 설정을 저장하도록 하였습니다.

추가로, type hinting을 사용하는 것은 아주 좋은 습관이니 염두해 두시면 좋을 것 같아요.

Save Settings

이제 설정을 저장해 봅시다.

from PyQt6.QtCore import QSettings


class MainWindow(QMainWindow):
    def __init__(self):
        self.settings = QSettings("HoYa", "Example")

    def save_settings(self):
        self.settings.setValue("geometry", self.saveGeometry())

추가된 부분만 표시를 해봤습니다.

먼저, 설정을 위해 QSettings 인스턴스를 만들어 줍니다. Organization 이름과 Application 이름을 적어주면 됩니다.

다음으로, setValue() method를 사용해서 원하는 정보를 저장합니다.

인자로 key와 value를 넣어주면 되고, key는 string으로 넣어주고, value는 어떤 object이던 다 됩니다.

예제로 application의 위치와 크기를 저장했습니다.

Load Settings

이제 설정을 불러옵니다.

def load_settings(self):
    if self.settings.contains("geometry"):
        self.restoreGeometry(self.settings.value("geometry"))
    else:
        self.setGeometry(100, 100, 1024, 768)

안전한 프로그래밍을 위해 항상 방어적으로 프로그래밍하세요.

위의 예에서도 먼저 contains() method를 사용하여 주어진 key가 존재하는 지 확인 후, value() method를 사용하여 그 key에 맞는 value를 얻어옵니다.

위의 경우, application의 geometry 정보를 불러왔으므로, 해당 정보로 application으 복원해줍니다.

else 부분은 만약 주어진 key가 존재하지 않다면, default value를 사용하겠다는 의미입니다.

이 부분은 생성자에 위치시켜도 되는 부분이기도 하니 각자의 방식대로 하시면 되요.

 

한 번, 실제로 동작시켜 보세요.

먼저, application의 크기를 변경한 후, application을 종료했다가 다시 실행해보면 이전 크기로 실행되는 것을 보실 수 있을 거에요.

Location of Saved Settings

기본적으로 저장한 설정은 다음 위치로 저장이 됩니다.

On MACOSX

~/Library/Preferences/com.ORGANIZATION.APPLICATION.plist

On WINDOWS

HKEY_CURRENT_USER/Software/ORGANIZATION/APPLICATION

몇몇 methods를 사용하면 다른 위치로 변경할 수도 있지만, 굳이 그럴 필요를 느낀 적은 없었습니다.

단, MAC의 경우 native 설정 system을 사용하기 때문에 해당 파일을 지워도 설정한 정보가 유지될 수 있습니다.

완전히 삭제를 하고 싶다면 terminal에서 다음의 명령을 입력합니다.

$ defaults delete com.ORGANIZATION.APPLICATION

Save and Load Array Values

몇몇 값들을 배열로 저장할 수도 있습니다.

개인적으로는 주로 동적으로 만들어진 QComboBox 같은 것을 저장할 때 사용하곤 했었어요.

from PyQt6.QtWidgets import QHBoxLayout, QComboBox


class MainWindow(QMainWindow):
    def __init__(self):
        self.combo = QComboBox()
        self.combo.addItems([f"Item {i}" for i in range(5)])

        layout = QHBoxLayout()
        layout.addWidget(self.combo)
        widget = QWidget()
        widget.setLayout(layout)

    def save_settings(self):
        self.settings.beginWriteArray("combo")
        for i in range(self.combo.count()):
            self.settings.setArrayIndex(i)
            self.settings.setValue("combo_item", self.combo.itemText(i))
        self.settings.endArray()

    def load_settings(self):
        if self.settings.contains("combo/size"):
            size = self.settings.beginReadArray("combo")
            for i in range(size):
                self.settings.setArrayIndex(i)
                self.combo.addItem(self.settings.value("combo_item"))
            self.settings.endArray()

최대한 간단히 설명드리기 위해 동적으로 생성하는 부분은 제거했습니다.

먼저 combo box를 만들어 아이템을 등록했습니다.

저장 부분을 보시면 beginWriteArray() ~ endArray() 형태로 되어 있는 것을 보실 수 있을 거에요.

마찬가지로 불러오는 부분은 beginReadArray() ~ endArray() 형태이고요.

이제 내부를 들여다보면 setArrayIndex() method를 사용하여, 하나의 key로 된 array의 index를 설정하고 해당 위치에서 setValue()value() methods를 사용하여 value들을 저장하고 불러옵니다.

사용한 key 부분만 확인해보세요.

 

테스트를 해보시려면 먼저, addItems()를 호출하도록 해서 combo box에 아이템을 채워주시고 application을 종료하여 값들을 저장해 줍니다.

이후 addItems() 부분을 삭제해서 빈 combo box로 만들어 주신 후 application을 실행하면 저장된 값들로 채워지는 것을 확인해보실 수 있습니다.

Save and Load Grouping Values

여러 값들을 하나의 group으로 저장할 수도 있습니다.

from PyQt6.QtWidgets import QLineEdit


class MainWindow(QMainWindow):
    def __init__(self):
        self.edit = QLineEdit()

        layout.addWidget(self.edit)

    def save_settings(self):
        self.settings.beginGroup("edit")
        self.settings.setValue("text", self.edit.text())
        self.settings.setValue("readonly", self.edit.isReadOnly())
        self.settings.setValue("visible", self.edit.isVisible())
        self.settings.endGroup()

    def load_settings(self):
        if self.settings.contains("edit/text"):
            self.edit.setText(self.settings.value("edit/text"))
        if self.settings.contains("edit/readonly"):
            self.edit.setReadOnly(self.settings.value("edit/readonly"))
        if self.settings.contains("edit/visible"):
            self.edit.setVisible(self.settings.value("edit/visible"))

예를 들기 위해 QLineEdit를 하나 만들어서, 사용자가 입력한 문자열, readonly 여부, visible 여부를 저장하도록 했습니다.

저장할 때는 beginGroup() ~ endGroup()으로 감싸주고, 불러올 때는 key로 명시를 하면 됩니다.

Wrap Up

이번에는 PyQt6QSettings에 대해 살펴보았습니다.

Application의 설정을 저장하고 다음번 실행 시 이를 불러와 이전에 사용하던 상태로 만들어 주기 위해 사용하는 기능입니다.

 

이 외에도 추가적인 method들이 좀 더 있긴 한데, 이 정도만 알면 기본적으로 사용하시는 데 충분하다고 생각됩니다.