본문 바로가기
목차
Python

[PySide] QtCore.QSettings 사용법

by ds31x 2025. 5. 12.
728x90
반응형

PySide6에서의 QSettings 가이드: 

QSettings는 Qt 프레임워크에서 애플리케이션 설정을 저장하고 불러오는 데 사용되는 클래스임.


1. 생성 및 파일 위치 및 형식

1-1. QSettings 생성자:

다음과 같은 3가지 방식이 존재함.

QSettings(organization: str, application: str)
QSettings(filename: str, format: QSettings.Format)
QSettings(
    format: QSettings.Format, 
    scope: QSettings.Scope, 
    organization: str, 
    application: str = ''
)

 

사용례는 다음과 같음 (3번째 방법은 Format과 Scope를 지정하는 방식으로 "참고: Format과 Scope 지정 방식"을 참고)

from PySide6.QtCore import QSettings

# 기본 방식
settings = QSettings("회사명", "애플리케이션명")

# 또는 특정 파일 사용
settings = QSettings("설정파일.ini", QSettings.IniFormat)

1-2. 설정 파일 저장 위치

QSettings는 기본방식으로 사용할 경우, 운영체제에 따라 설정 파일이 다른 위치에 저장됨:

  • Windows:
    • 레지스트리: HKEY_CURRENT_USER\Software\회사명\애플리케이션명
    • INI 파일 사용 시: C:\Users\사용자명\AppData\Roaming\회사명\애플리케이션명.ini
  • macOS:
    • ~/Library/Preferences/com.회사명.애플리케이션명.plist
  • Linux/Unix:
    • ~/.config/회사명/애플리케이션명.conf

1-3. 파일 이름을 직접 지정한 경우의 저장 위치

파일 이름을 직접 지정하면

  • 상대 경로일 경우 현재 작업 디렉토리(Current Working Directory)를 기준으로 저장됨.
  • 절대 경로를 사용하면 지정된 위치에 정확히 저장됩니다.

1-3-1. 파일 이름 지정 방식:

QSettings(filename: str, format: QSettings.Format)
  • 주로 INI 파일로 저장됨: text로 저장하는 방식.

1-3-2. 사용예

이 방식의 간단한 사용례는 아래와 같음.

# 상대 경로 사용 (현재 작업 디렉토리 기준)
relative_settings = QSettings("settings.ini", QSettings.IniFormat)
print(f"상대 경로 설정 파일: {relative_settings.fileName()}")
# 출력 예: 상대 경로 설정 파일: /현재/작업/디렉토리/settings.ini

# 절대 경로 사용
import os
absolute_path = os.path.join(os.path.expanduser("~"), "Documents", "myapp_settings.ini")
absolute_settings = QSettings(absolute_path, QSettings.IniFormat)
print(f"절대 경로 설정 파일: {absolute_settings.fileName()}")
# 출력 예: 절대 경로 설정 파일: /Users/사용자명/Documents/myapp_settings.ini

참고: 현재 작업 디렉토리 확인하기

현재 작업 디렉토리가 어디인지 확인하고 싶다면:

import os
print(f"현재 작업 디렉토리: {os.getcwd()}")

# 만약 PyQt 애플리케이션에서 실행 파일의 디렉토리를 기준으로 설정 파일을 저장하고 싶다면:
import sys
app_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
app_settings_path = os.path.join(app_dir, "app_settings.ini")
app_settings = QSettings(app_settings_path, QSettings.IniFormat)
print(f"애플리케이션 디렉토리 기준 설정 파일: {app_settings.fileName()}")
  • __file__ dunder는 현재 실행 중인 스크립트 파일의 경로를 가리키므로 이를 대신 사용가능함.
  • 단, 패키징된 애플리케이션에서는 __file__은 동작하지 않을 수 있으므로 sys.argv[0]를 사용할 것.
  • 패키징된 경우, sys.argv[0]는 exe파일에 해당됨.

1-4. Format과 Scope 지정 방식

1-4-1. QSettings.Format 열거형 값:

QSettings.NativeFormat    # 운영체제 기본 형식 (Windows: 레지스트리, macOS: plist 등)
QSettings.IniFormat       # INI 파일 형식
QSettings.InvalidFormat   # 유효하지 않은 형식

1-4-2. QSettings.Scope 열거형 값:

QSettings.UserScope       # 현재 사용자만을 위한 설정
QSettings.SystemScope     # 모든 사용자를 위한 설정

1-4-3. 사용예

사용 방법은 다음 코드를 확인할 것.

from PySide6.QtCore import QSettings

# Format과 Scope 지정 방식
settings = QSettings(QSettings.IniFormat, QSettings.UserScope, "회사명", "애플리케이션명")

# 이 설정은 다음과 같은 위치에 INI 파일로 저장됩니다:
# Windows: C:\Users\사용자명\AppData\Roaming\회사명\애플리케이션명.ini
# macOS: ~/Library/Preferences/회사명/애플리케이션명.ini
# Linux: ~/.config/회사명/애플리케이션명.ini

print(f"설정 파일 경로: {settings.fileName()}")

# SystemScope 사용 예제 (관리자 권한이 필요할 수 있음)
system_settings = QSettings(QSettings.IniFormat, QSettings.SystemScope, "회사명", "애플리케이션명")

# 이 설정은 다음과 같은 위치에 저장됩니다:
# Windows: C:\ProgramData\회사명\애플리케이션명.ini
# macOS: /Library/Preferences/회사명/애플리케이션명.ini
# Linux: /etc/xdg/회사명/애플리케이션명.ini

print(f"시스템 설정 파일 경로: {system_settings.fileName()}")

1-5. 저장형식

1-5-1. INI 형식 (QSettings.IniFormat):

  • 텍스트 기반 형식으로 저장.
  • 키-값 쌍이 일반 텍스트로 저장되어 사람이 읽고 편집할 수 있음.

1-5-2. 네이티브 형식 (QSettings.NativeFormat):

  • Windows: 레지스트리에 바이너리 형태로 저장.
  • macOS: XML 기반 Property List (.plist) 형식으로 저장 (실제로는 바이너리 형식이라 pluitl 등을 사용해야 텍스트로 확인 가능).
  • Linux/Unix: INI와 유사한 텍스트 기반 .conf 파일로 저장.

다시 한번 강조하지만 파일 경로를 직접 지정할 경우 기본적으로 INI 형식(텍스트 기반)으로 저장됨.

❯❯ plutil -p ~/Library/Preferences/com.imagebrowser.Settings.plist
{
  "lastDirectory" => "/Users/dsaint31/Desktop"
  "recentDirectories" => [
    0 => "/Users/dsaint31/Desktop"
    1 => "/Users/dsaint31/Pictures"
  ]
}

2. 기본 사용법

2-1. 현재 설정 파일 경로 확인

2-1-1. fileName 메서드:

fileName() -> str
  • QSettings 객체의 메서드임.
file_path = settings.fileName()
print(f"설정 파일 경로: {file_path}")

2-2. 설정 저장하기

2-2-1. setValue 메서드:

설정값을 키와 값의 쌍으로 저장.

setValue(key: str, value: Any) -> None

2-2-2. sync 메서드:

현재 변경사항을 storage에 저장.

sync() -> None

2-2-3. Example Code

# 다양한 타입의 값 저장
settings.setValue("category/text", "Hello World")
settings.setValue("category/number", 42)
settings.setValue("category/boolean", True)
settings.setValue("category/list", [1, 2, 3, 4])
settings.setValue("category/dict", {"key": "value"})

# 변경사항 storage에 저장
settings.sync()

2-3. 설정 불러오기

2-3-1. value 메서드:

설정값을 키를 통해 가져옴. 없을 경우 defaultValue에 설정된 값이 반환됨.

value(key: str, defaultValue: Any = None) -> Any

2-3-2. Example Code

# 기본값을 지정하면서 설정 불러오기
text = settings.value("category/text", "기본값")
number = settings.value("category/number", 0)
boolean = settings.value("category/boolean", False)

# 타입 지정 (PySide6에서는 타입 변환이 필요할 수 있음)
number = int(settings.value("category/number", 0))
boolean = bool(settings.value("category/boolean", False))

2-4. 그룹으로 관리하기:

2-4-1. beginGroup 메서드:

beginGroup 메서드는

  • 설정 키에 공통 접두사를 지정하여 관련 설정들을 논리적으로 그룹화하고,
  • 설정 키의 계층 구조를 쉽게 관리할 수 있게 해줌.

/로 직접 지정도 가능하지만, 여러개를 한꺼번에 다룰 때는 beginGroup이 보다 편함.

beginGroup(prefix: str) -> None

2-4-2. endGroup 메서드:

beginGroup메서드로 시작된 그룹의 prefix를 끝낼 때 사용함.

endGroup() -> None

2-4-3. Example Code:

# 그룹 시작
settings.beginGroup("UserPreferences")

# 그룹 내 값 설정
settings.setValue("theme", "dark")
settings.setValue("fontSize", 12)
settings.setValue("showToolbar", True)

# 그룹 종료
settings.endGroup()

# 그룹 내 값 읽기
settings.beginGroup("UserPreferences")
theme = settings.value("theme", "light")
fontSize = int(settings.value("fontSize", 10))
settings.endGroup()

# 슬래시(/)를 사용하여 직접 그룹 구조로 설정
settings.setValue("UserPreferences/theme", "dark")

# 그룹 외부에서 동일한 값에 접근하려면 전체 경로 필요
theme = settings.value("UserPreferences/theme", "light")

2-4. 배열 저장하기:

QSettings의 배열 저장 기능은 인덱스가 있는 동일한 타입의 여러 설정 값을 구조화된 방식으로 관리할 수 있음.

  • beginWriteArray() 메서드로 배열 작성을 시작
  • setArrayIndex()로 인덱스를 지정한 후
  • setValue()를 호출하면, 내부적으로는 각 인덱스에 해당하는 고유 키가 생성되어 값이 저장됨.
  • endArray() 메서드로 배열 작성 종료.

2-4-1. beginWriteArray 메서드:

beginWriteArray(prefix: str, size: int = -1) -> None

2-4-2. setArrayIndex 메서드:

setArrayIndex(i: int) -> None

2-4-3. endArray 메서드:

endArray() -> None

2-4-4. Example Code

items = ["항목1", "항목2", "항목3"]

settings.beginWriteArray("recentItems")
for i, item in enumerate(items):
    settings.setArrayIndex(i)
    settings.setValue("name", item)
settings.endArray()

2-5. 배열 불러오기

작성과 사용이 유사하나, beginWriteArray() 대신 beginReadArray 메서드로 배열 읽기를 시작.

읽을 때는 value메서드를 사용함.

2-5-1. beginReadArray 메서드:

beginReadArray(prefix: str) -> int

2-5-2. Example Code

size = settings.beginReadArray("recentItems")
items = []
for i in range(size):
    settings.setArrayIndex(i)
    item = settings.value("name")
    items.append(item)
settings.endArray()

print(f"최근 항목: {items}")

2-6. 배열 직접 사용하기.

다음과 같이 직접 /와 index를 통해 배열을 사용하는 방법도 가능.

# 배열 크기 저장
items = ["항목1", "항목2", "항목3"]
settings.setValue("recentItems/size", len(items))

# 각 배열 요소 저장
for i, item in enumerate(items):
    settings.setValue(f"recentItems/{i}/name", item)

# 배열 불러오기
size = int(settings.value("recentItems/size", 0))
loaded_items = []
for i in range(size):
    item = settings.value(f"recentItems/{i}/name", "")
    loaded_items.append(item)

2-7. 설정 제거하기

2-7-1. remove 메서드:

키를 통해 특정 설정을 제거.

remove(key: str) -> None

2-7-2. clear 메서드:

전부 삭제.

clear() -> None

2-7-3. Example Code

# 특정 키 제거
settings.remove("category/text")

# 모든 설정 제거
settings.clear()

2-8. 그 외 메서드와 기능

2-8-1. contains 메서드:

현재 그룹 내의 키와 함께 모든 하위 그룹의 키도 검색 대상에 포함하여 지정된 키의 존재 여부를 확인.

즉, 전체 경로를 포함하여 검색하므로 "그룹/하위그룹/키" 형태로 지정된 중첩된 키의 존재도 확인할 수 있음.

contains(key: str) -> bool
  • 특정 키가 존재하는지 확인함.
# 특정 키가 존재하는지 확인
if settings.contains("ui/theme"):
    print("테마 설정이 존재합니다!")
else:
    print("테마 설정이 없습니다. 기본값을 사용합니다.")

그룹 관련된 메서드를 사용하면 해당 그룹의 여러 키에 대한 확인이 보다 편해짐:

# 그룹 설정
settings.beginGroup("UserPreferences")

# 직계 키 확인 - 그룹명 없이 바로 키 이름만 사용
if settings.contains("theme"):
    print("테마 설정이 존재합니다")

# 하위 그룹의 키 확인 - 하위 그룹명을 포함한 경로 사용
if settings.contains("colors/background"):
    print("배경색 설정이 존재합니다")

settings.endGroup()

# 그룹 외부에서는 전체 경로 필요
if settings.contains("UserPreferences/theme"):
    print("테마 설정이 존재합니다")

2-8-2. allKeys 메서드:

현재 그룹을 포함한 모든 하위 그룹의 키들을 포함하여 계층 구조 내의 모든 키를 완전한 경로("그룹/하위그룹/키" 형식)와 함께 문자열 리스트로 반환

allKeys() -> List[str]
  • 모든 키 목록을 확인.
# 모든 키 목록 가져오기
all_keys = settings.allKeys()
print("저장된 모든 설정 키:")
for key in all_keys:
    print(f" - {key}")

2-8-3. childGroups 메서드:

현재 그룹 내에 있는 모든 직계 하위 그룹의 이름을 문자열 리스트로 반환

childGroups() -> List[str]
  • 자식 그룹을 반환함.
# 모든 그룹 이름 가져오기
groups = settings.childGroups()
print("설정 그룹 목록:")
for group in groups:
    print(f" - {group}")

2-8-4. childKeys 메서드:

현재 그룹 내에 존재하는 모든 키의 목록을 문자열 리스트로 반환

childKeys() -> List[str]
  • 현재 그룹의 모든 키를 가져옴.
# 현재 그룹의 모든 키 가져오기
settings.beginGroup("UserPreferences")
keys = settings.childKeys()
print("UserPreferences 그룹의 키 목록:")
for key in keys:
    print(f" - {key}")
settings.endGroup()

2-8-5. status 메서드:

QSettings.status() 메서드는 현재 QSettings 객체의 오류 상태를 QSettings.Status 열거형 값으로 반환

  • 설정 파일 작업 중 발생할 수 있는 문제를 감지하는 데 사용됨.
status() -> QSettings.Status
  • 상태 확인.
  • 반환되는 상태 값은 다음과 같음:
    • QSettings.NoError (오류 없음),
    • QSettings.AccessError (파일 접근 권한 문제),
    • QSettings.FormatError (파일 형식 손상)
# 설정 상태 확인
status = settings.status()
if status == QSettings.NoError:
    print("설정 파일에 문제가 없습니다.")
elif status == QSettings.AccessError:
    print("설정 파일 접근 오류!")
elif status == QSettings.FormatError:
    print("설정 파일 형식 오류!")

3. 예제 코드

3-1. 활용 예제: 다양한 설정 파일 사용하기:

다음 코드는 다양한 위치와 범위의 설정 파일을 관리하는 ConfigManager 클래스를 구현함.

이를 통해 애플리케이션에서 여러 설정을 4개의 다른 위치에 생성 및 관리함

  • 사용자별 기본 설정,
  • 애플리케이션 폴더 내 휴대용 설정,
  • 모든 사용자를 위한 시스템 설정, 그리고
  • 사용자 문서 폴더 내 설정
from PySide6.QtCore import QSettings, QStandardPaths
import os

class ConfigManager:
    def __init__(self):
        # 1. 기본 사용자 설정 (운영체제 기본 위치)
        self.user_settings = QSettings("MyCompany", "MyApp")

        # 2. 휴대용 설정 (애플리케이션 폴더 내 INI 파일)
        app_dir = os.path.dirname(os.path.abspath(__file__))
        portable_path = os.path.join(app_dir, "portable_settings.ini")
        self.portable_settings = QSettings(portable_path, QSettings.IniFormat)

        # 3. 시스템 전체 설정 (모든 사용자용)
        self.system_settings = QSettings(QSettings.IniFormat, QSettings.SystemScope, 
                                        "MyCompany", "MyApp")

        # 4. 사용자 문서 폴더 내 설정
        docs_dir = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation)
        docs_config = os.path.join(docs_dir, "MyApp", "config.ini")
        os.makedirs(os.path.dirname(docs_config), exist_ok=True)
        self.docs_settings = QSettings(docs_config, QSettings.IniFormat)

        print(f"기본 사용자 설정 위치: {self.user_settings.fileName()}")
        print(f"휴대용 설정 위치: {self.portable_settings.fileName()}")
        print(f"시스템 설정 위치: {self.system_settings.fileName()}")
        print(f"문서 폴더 설정 위치: {self.docs_settings.fileName()}")

# 사용 예
config_manager = ConfigManager()

3-2. 실제 예제: 간단한 애플리케이션 설정 관리:

다음 코드는 QSettings를 활용하여 사용자 설정을 저장하고 불러오는 기능을 갖춘 간단한 PySide6 애플리케이션 예제임.

  1. 사용자가 색상을 선택하여 배경색을 변경하고 저장할 수 있음.
  2. 창의 위치와 상태가 저장되어 애플리케이션을 다시 실행했을 때 이전 상태를 그대로 복원함.
  3. 또한 설정 파일이 저장되는 경로를 화면에 표시하여 사용자가 어디에 설정이 저장되는지 확인할 수 있음.
import sys
from PySide6.QtCore import QSettings
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QPushButton, QLabel, QColorDialog

class SettingsExample(QMainWindow):
   def __init__(self):
       # 부모 클래스 초기화
       super().__init__()

       # 윈도우 기본 설정
       self.setWindowTitle("QSettings 예제")  # 윈도우 제목 설정
       self.resize(400, 300)  # 윈도우 초기 크기 설정 (너비 400px, 높이 300px)

       # QSettings 객체 생성 - 회사명과 애플리케이션명 기반으로 설정 저장 위치 결정
       # 운영체제별로 다른 위치에 설정이 저장됨:
       # - Windows: 레지스트리 HKEY_CURRENT_USER\Software\MyCompany\SettingsExample
       # - macOS: ~/Library/Preferences/com.MyCompany.SettingsExample.plist
       # - Linux: ~/.config/MyCompany/SettingsExample.conf
       self.settings = QSettings("MyCompany", "SettingsExample")

       # 중앙 위젯 설정 - QMainWindow는 중앙 위젯이 필요함
       central_widget = QWidget()

       # 수직 레이아웃 생성 및 중앙 위젯에 설정
       layout = QVBoxLayout(central_widget)

       # 색상 표시 레이블 생성
       # load_color() 메서드를 호출하여 저장된 색상을 가져오거나 기본값 사용
       self.color_label = QLabel("색상 설정")
       # 스타일시트를 사용하여 배경색 설정 - 저장된 색상 또는 기본값(흰색)
       self.color_label.setStyleSheet(f"background-color: {self.load_color()};")

       # 색상 변경 버튼 생성
       change_color_btn = QPushButton("색상 변경")
       # 버튼 클릭 시 change_color 메서드가 호출되도록 시그널 연결
       change_color_btn.clicked.connect(self.change_color)

       # 창 위치 저장 버튼 생성
       save_position_btn = QPushButton("창 위치 저장")
       # 버튼 클릭 시 save_window_geometry 메서드가 호출되도록 시그널 연결
       save_position_btn.clicked.connect(self.save_window_geometry)

       # 설정 파일 경로를 표시하는 레이블 생성
       # fileName() 메서드로 현재 설정 파일의 실제 경로를 가져옴
       path_label = QLabel(f"설정 파일 경로: {self.settings.fileName()}")

       # 위젯들을 레이아웃에 순서대로 추가
       layout.addWidget(self.color_label)
       layout.addWidget(change_color_btn)
       layout.addWidget(save_position_btn)
       layout.addWidget(path_label)

       # 중앙 위젯 설정
       self.setCentralWidget(central_widget)

       # 애플리케이션 시작 시 저장된 창 위치 불러오기
       # 이전에 저장된 위치가 있으면 해당 위치로 창을 이동
       self.load_window_geometry()

   def change_color(self):
       """
       색상 선택 대화상자를 열고 선택된 색상으로 레이블 배경색을 변경한 후 설정에 저장
       """
       # QColorDialog를 사용하여 색상 선택 대화상자 표시
       color = QColorDialog.getColor()

       # 사용자가 유효한 색상을 선택했는지 확인 (취소 버튼을 누르지 않았는지)
       if color.isValid():
           # 선택한 색상으로 레이블의 배경색 변경
           self.color_label.setStyleSheet(f"background-color: {color.name()};")

           # 선택한 색상을 설정에 저장 ("ui/backgroundColor" 키 사용)
           # color.name()은 "#RRGGBB" 형식의 16진수 색상 코드 반환
           self.settings.setValue("ui/backgroundColor", color.name())

   def load_color(self):
       """
       설정에서 저장된 배경색을 불러옴. 저장된 값이 없으면 흰색(#ffffff)을 기본값으로 사용

       Returns:
           str: 16진수 색상 코드 ("#RRGGBB" 형식)
       """
       # "ui/backgroundColor" 키에 저장된 값을 불러오고, 없으면 흰색(#ffffff)을 기본값으로 사용
       return self.settings.value("ui/backgroundColor", "#ffffff")

   def save_window_geometry(self):
       """
       현재 창의 위치, 크기, 상태를 설정에 저장
       """
       # QWidget.geometry()는 창의 위치와 크기를 포함하는 QRect 객체 반환
       self.settings.setValue("window/geometry", self.geometry())

       # QWidget.windowState()는 창의 상태를 나타내는 Qt.WindowState 반환
       # (일반, 최대화, 최소화, 전체화면 등)
       self.settings.setValue("window/state", self.windowState())

   def load_window_geometry(self):
       """
       설정에서 저장된 창의 위치, 크기, 상태를 불러와 적용
       저장된 설정이 없으면 기본값(생성자에서 설정한 값) 유지
       """
       # 저장된 창 위치 및 크기 불러오기
       geometry = self.settings.value("window/geometry")

       # 저장된 값이 있으면 적용
       if geometry:
           self.setGeometry(geometry)

       # 저장된 창 상태 불러오기 (최대화, 최소화 등)
       state = self.settings.value("window/state")

       # 저장된 값이 있으면 적용
       if state:
           self.setWindowState(state)

# 메인 애플리케이션 실행 코드
if __name__ == "__main__":
   # QApplication 인스턴스 생성 - 모든 Qt 애플리케이션에 필요
   app = QApplication(sys.argv)

   # SettingsExample 창 인스턴스 생성
   window = SettingsExample()

   # 창 표시
   window.show()

   # 애플리케이션 이벤트 루프 시작
   # app.exec()는 애플리케이션이 종료될 때 반환값을 제공
   # sys.exit()은 이 반환값을 시스템에 전달하여 애플리케이션 종료 상태를 알림
   sys.exit(app.exec())

4. 주의사항 및 팁

4-1. 타입 변환:

  • PySide6에서는 값을 불러올 때 타입 변환이 자동으로 이루어지지 않을 수 있음.
  • 특히 bool과 Numeric Types (int, float)은 명시적으로 변환을 권장.
# 명시적 타입 변환
number = int(settings.value("number", 0))
is_enabled = settings.value("enabled", False) in [True, "true", "1", 1]

4-3. 설정 동기화:

  • 중요한 설정을 변경한 후에는 sync() 메서드를 호출하여 즉시 디스크에 반영할 것.

4-4. 설정 백업과 복원:

QSettings 객체를 사용하여 애플리케이션 설정을 안전하게 백업하고 복원하는 과정을 보여주는 예제임.

  • 자세한 예외 처리 및
  • 파일 잠금 방지 메커니즘을 사용함.

사용된 shutil은 Python 표준 라이브러리에 포함되어 있는 모듈로서
파일 복사, 이동, 삭제 등의 고수준 파일 작업을 제공함.

이 모듈은
셸(명령 프롬프트나 터미널)에서 수행할 수 있는
파일 및 디렉토리 작업을 Python 코드로 제공하는 유틸리티 모듈임.

def backup_settings(settings, backup_path):
    """
    QSettings 객체가 관리하는 설정 파일을 백업합니다.

    Args:
        settings (QSettings): 백업할 설정 객체
        backup_path (str): 백업 파일이 저장될 경로

    Returns:
        bool: 백업 성공 시 True, 실패 시 False
    """
    import shutil
    import os

    try:
        # 현재 설정 파일의 경로를 얻습니다.
        source_path = settings.fileName()

        # 설정 파일이 존재하는지 확인합니다.
        if not os.path.exists(source_path):
            print(f"오류: 설정 파일이 존재하지 않습니다. ({source_path})")
            return False

        # 백업 파일이 저장될 디렉토리가 존재하는지 확인하고, 없으면 생성합니다.
        backup_dir = os.path.dirname(backup_path)
        if backup_dir and not os.path.exists(backup_dir):
            os.makedirs(backup_dir)

        # 설정 파일을 백업 경로로 복사합니다. 
        # copy2는 메타데이터(수정 시간 등)까지 함께 복사합니다.
        shutil.copy2(source_path, backup_path)

        print(f"설정이 {backup_path}에 성공적으로 백업되었습니다.")
        return True

    except Exception as e:
        # 예외가 발생하면 오류 메시지를 출력하고 False를 반환합니다.
        print(f"백업 중 오류 발생: {str(e)}")
        return False


def restore_settings(backup_path, organization=None, application=None, settings_file=None):
    """
    백업된 설정 파일을 복원합니다.

    이 함수는 기존 QSettings 객체를 사용하지 않고, 새로운 QSettings 객체를 생성하여 반환합니다.
    파일 잠금 문제를 방지하기 위해 기존 객체는 사용하지 않습니다.

    Args:
        backup_path (str): 백업 파일의 경로
        organization (str, optional): 조직 이름. settings_file이 None일 때 필요합니다.
        application (str, optional): 애플리케이션 이름. settings_file이 None일 때 필요합니다.
        settings_file (str, optional): 설정 파일 경로. 이 값이 제공되면 organization과 
                                       application은 무시됩니다.

    Returns:
        QSettings: 복원된 설정을 가진 새 QSettings 객체, 실패 시 None
    """
    import shutil
    import os
    from PySide6.QtCore import QSettings, QSettings

    try:
        if not os.path.exists(backup_path):
            print(f"오류: 백업 파일이 존재하지 않습니다. ({backup_path})")
            return None

        # 대상 설정 파일의 경로를 결정합니다.
        if settings_file:
            # 특정 파일 경로가 제공된 경우
            target_settings = QSettings(settings_file, QSettings.IniFormat)
            target_path = settings_file
        elif organization and application:
            # 조직 및 애플리케이션 이름이 제공된 경우
            temp_settings = QSettings(organization, application)
            target_path = temp_settings.fileName()
            # 임시 객체는 더 이상 필요하지 않으므로 해제합니다.
            del temp_settings
        else:
            print("오류: 설정 파일 경로 또는 조직/애플리케이션 이름이 필요합니다.")
            return None

        # 대상 디렉토리가 존재하는지 확인하고, 없으면 생성합니다.
        target_dir = os.path.dirname(target_path)
        if target_dir and not os.path.exists(target_dir):
            os.makedirs(target_dir)

        # 백업 파일을 원래 위치로 복사합니다.
        shutil.copy2(backup_path, target_path)

        print(f"설정이 {backup_path}에서 {target_path}로 성공적으로 복원되었습니다.")

        # 복원된 설정으로 새 QSettings 객체를 생성하여 반환합니다.
        if settings_file:
            return QSettings(settings_file, QSettings.IniFormat)
        else:
            return QSettings(organization, application)

    except Exception as e:
        # 예외가 발생하면 오류 메시지를 출력하고 None을 반환합니다.
        print(f"복원 중 오류 발생: {str(e)}")
        return None


# 사용 예제
def example_usage():
    """설정 백업 및 복원 사용 예제"""
    from PySide6.QtCore import QSettings
    import os

    # 1. 기본 사용법
    settings = QSettings("MyCompany", "MyApp")
    settings.setValue("example/value", "test data")
    settings.sync()  # 변경사항을 디스크에 즉시 기록

    # 설정 파일 경로 확인
    original_path = settings.fileName()
    print(f"원본 설정 파일: {original_path}")

    # 백업 경로 설정 (현재 작업 디렉토리 사용)
    backup_path = os.path.join(os.getcwd(), "settings_backup.ini")

    # 2. 설정 백업
    success = backup_settings(settings, backup_path)
    if success:
        # 기존 값 변경
        settings.setValue("example/value", "changed data")
        settings.sync()
        print(f"설정 값 변경됨: {settings.value('example/value')}")

        # 3. 설정 복원 (기존 객체는 사용하지 않음)
        # 참고: 복원할 때는 원본 QSettings 객체를 사용하지 않고 새로 생성
        restored_settings = restore_settings(backup_path, "MyCompany", "MyApp")

        if restored_settings:
            # 복원된 값 확인
            print(f"복원된 설정 값: {restored_settings.value('example/value')}")

    # 4. 특정 파일 경로를 사용한 백업/복원
    file_settings = QSettings("custom_settings.ini", QSettings.IniFormat)
    file_settings.setValue("custom/option", "file-based setting")
    file_settings.sync()

    file_backup_path = os.path.join(os.getcwd(), "custom_backup.ini")

    if backup_settings(file_settings, file_backup_path):
        # 파일 경로를 직접 지정하여 복원
        restored_file_settings = restore_settings(file_backup_path, 
                                                 settings_file="custom_settings.ini")
        if restored_file_settings:
            print(f"복원된 파일 설정 값: {restored_file_settings.value('custom/option')}")

4-5. 설정 파일 위치 지정:

애플리케이션별 설정 디렉토리를 생성하여 사용하는 방법 중 권장되는 것은 QStandardPaths를 이용하는 것임.

QStandardPaths

  • 운영체제별 표준 디렉토리 경로를 제공하는 클래스임.
  • 이를 통해 애플리케이션은 플랫폼에 독립적인 방식으로 시스템의 표준 위치에 접근할 수 있음.

유용한 QStandardPaths 위치 상수들:

  • AppDataLocation: 사용자의 애플리케이션 데이터를 저장하기 위한 표준 디렉토리 위치
  • DesktopLocation: 사용자의 데스크톱 디렉토리
  • DocumentsLocation: 사용자의 문서 디렉토리
  • MusicLocation: 사용자의 음악 디렉토리
  • MoviesLocation: 사용자의 동영상 디렉토리
  • PicturesLocation: 사용자의 사진 디렉토리
  • TempLocation: 임시 파일용 디렉토리
  • HomeLocation: 사용자의 홈 디렉토리
  • ConfigLocation: 애플리케이션별 설정 파일의 위치(QSettings의 기본 저장 위치)
  • CacheLocation: 애플리케이션 캐시 데이터용 디렉토리
  • GenericDataLocation: 공유 데이터를 저장하는 디렉토리
  • RuntimeLocation: 런타임 데이터를 저장하는 디렉토리
from PySide6.QtCore import QStandardPaths, QSettings
import os

# 플랫폼 독립적인 방식으로 애플리케이션 설정 디렉토리 경로 찾기
# QStandardPaths.AppDataLocation은 각 OS에 맞는 설정 디렉토리를 반환:
# - Windows: C:\Users\사용자명\AppData\Local\MyApp
# - macOS: ~/Library/Application Support/MyApp
# - Linux: ~/.local/share/MyApp
app_data_dir = QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)

# 애플리케이션 이름으로 하위 디렉토리 생성
# 여러 설정 파일을 체계적으로 관리하기 위한 전용 폴더
config_dir = os.path.join(app_data_dir, "MyApp")

# 디렉토리가 없으면 생성, 이미 존재하면 오류 발생하지 않음
# exist_ok=True 파라미터는 디렉토리가 이미 존재해도 예외를 발생시키지 않음
os.makedirs(config_dir, exist_ok=True)

# 설정 파일의 전체 경로 구성
# INI 형식의 설정 파일을 생성할 경로 지정
config_path = os.path.join(config_dir, "settings.ini")

# 지정된 경로에 INI 형식의 QSettings 객체 생성
# 이 방식은 설정 파일의 위치를 명시적으로 제어할 수 있어 
# 포터블 애플리케이션이나 사용자 지정 위치에 설정을 저장할 때 유용
settings = QSettings(config_path, QSettings.IniFormat)

 


4-6. 다국어 지원:

다국어 설정을 관리하는 방법:

  • 언어 코드(예: 'ko', 'en', 'ja')를 경로의 일부로 사용하여 각 언어별로 메시지를 구조적으로 분리해 저장.
  • 저장된 메시지는 사용자가 선택한 언어(user_language)에 따라 해당 언어 그룹에서 값을 불러오며,
  • 만약 해당 키에 대한 번역이 없을 경우 기본값을 반환하도록 구현.
# 언어별 설정 분리
settings.beginGroup(f"language/{current_language}")
settings.setValue("welcome_message", "환영합니다")
settings.endGroup()

# 언어 불러오기
settings.beginGroup(f"language/{user_language}")
welcome = settings.value("welcome_message", "Welcome")
settings.endGroup()

 

current_language 변수는 애플리케이션에서 현재 사용 중인 언어 코드를 나타내며, 일반적으로 다음과 같은 방법으로 설정

# 애플리케이션 시작 시 기본값 설정
current_language = "en"  # 기본값으로 영어 설정

def initializeLanguage():
    global current_language

    # 저장된 설정에서 언어 불러오기
    settings = QSettings("MyCompany", "MyApp")
    saved_language = settings.value("preferences/language", "")

    if saved_language:
        current_language = saved_language
    else:
        # 시스템 언어 사용
        system_lang = QLocale.system().name()[:2] # 'ko_KR' 등에서 'ko'만 추출
        # 지원하는 언어 목록
        supported_languages = ["en", "ko", "ja", "fr", "de"]

        if system_lang in supported_languages:
            current_language = system_lang
        # 아니면 기본값 유지 (en)
728x90

'Python' 카테고리의 다른 글

[Py] SymPy (Symbolic Python) - Symbolic Computation  (1) 2025.06.05
[Ex] scope 이해.  (0) 2025.05.12
[Programming] SOLID 원칙  (0) 2025.04.28
[DL] default collate_fn - PyTorch  (0) 2025.04.26
[Py] importlib.metadata: Package 정보 확인  (0) 2025.04.23