読者です 読者をやめる 読者になる 読者になる

はんぎょねこの憂鬱

耳から変な汁が出てきた

PySide: Save and Restore QDockWidgets

Dockの生成削除込みでQSettings保存

適当に調べた
  • QSettingsを使用してWidgetの位置やサイズを保存できる
  • 復元する前にWidgetを生成してobjectNameを設定しておく必要がある
  • DockWidgetを追加・削除できるプログラムではその状況も保存する必要がある
  • QMainWindow::restoreDockWidget関数はコレジャナイ感
  • あっ、もしかしてDockWidgetの復元は自分でやらないといけない?
必要な処理
  1. 初期化時に設定ファイルがあったら前回の内容を復元

    1. 前回生成されていたDockWidgetの復元
    2. restoreGeometry
    3. restoreState
  2. 終了時に設定ファイルを保存

    1. 全部のDockWidgetの型とobjectName(とりあえず毎回上書き)を保存
    2. saveGeometry
    3. saveState
コードこんな感じ
class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        # 復元
        if os.path.exists(path_to_ini):
            s = QtCore.QSettings(path_to_ini, QtCore.QSettings.IniFormat)
            self._restoreDockWidgets(s.value('dockwidgets'))
            self.restoreGeometry(s.value('geometry'))
            self.restoreState(s.value('state'))

    def closeEvent(self, event):
        # 保存
        s = QtCore.QSettings(path_to_ini, QtCore.QSettings.IniFormat)
        s.setValue('dockwidgets', self._saveDockWidgets())
        s.setValue('geometry', self.saveGeometry())
        s.setValue('state', self.saveState())

        super().closeEvent(event)

    def createDockWidget(self, widget_type) -> QtGui.QDockWidget:
        # 渡されたWidgetをDockにいれて返す
        dock = QtGui.QDockWidget()
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock)
        dock.setWidget(widget_type())
        dock.setWindowTitle(dock.widget().windowTitle())
        dock.setFloating(True)
        return dock

    def _saveDockWidgets(self):
        # DockWidgetにユニークな名前を付けて型名と一緒に保存
        # 実際に保存する型名はDockWidgetに設定されたWidgetのもの
        a = [x for x in self.children() if isinstance(x, QtGui.QDockWidget)]
        for x in a:
            x.setObjectName(str(uuid.uuid1()))
        # 保存されるデータは "型名:名前,型名:名前..." になる
        return ','.join(
            [type(x.widget()).__name__ + ':' + x.objectName() for x in a])

    def _restoreDockWidgets(self, value):
        # 設定ファイルから型と名前を取得してDockWidgetを復元
        # ここではwidgetsモジュール内にDock化される型をまとめている前提
        for t, name in [x.split(':') for x in value.split(',')]:
            if hasattr(widgets, t):
                d = self.createDockWidget(getattr(widgets, t))
                d.setObjectName(name)

他に良い方法知ってたら教えてください