ツールのオプションを表示して、あれこれ設定して、実行して、、、また表示したら、、、
アレ設定残らないの?
(;´∀`)
なんて経験ございませんか?地味なところだと、毎回ウインドウが邪魔な位置に表示される、、、とかもあると思います。
PySide(Qt)で作ったウインドウに、色々なパラメータを設定するWidgetをおいていると思いますが、ただ作っただけでは、使用者にとってはいまいちなんですよね(´;ω;`)
そこで、今回は、ウインドウの位置、大きさ、状態、各種Widgetに入力された値って勝手に保存されて、次回以降復元される、、、ってところをご紹介したいと思います!(`・ω・´)ゞ
保存するには?
ウインドウを閉じた時に、色々処理を実行するには「closeEvent」をオーバーライドするのが便利かと思います。「closeEvent」は、「QWidget」から派生しているもので使うことができます(*´ω`*)b
クラスの骨格
まずは、元となるクラスの骨格を見てみたいと思います!
import os from PySide import QtGui from PySide import QtCore from maya import OpenMayaUI import shiboken def mainWindow(): ptr = OpenMayaUI.MQtUtil.mainWindow() return shiboken.wrapInstance(long(ptr), QtGui.QWidget) class MainWindow(QtGui.QMainWindow): def __init__(self, parent=None, flags=QtCore.Qt.WindowFlags()): if parent is None: parent = mainWindow() super(MainWindow, self).__init__(parent, flags) def restore(self): pass def show(self): super(MainWindow, self).show() def closeEvent(self, event): super(MainWindow, self).closeEvent(event)
まず、ウインドウの大きさと位置の保存と言うものは、使用頻度が高い内容かと思います。せっかくですのでこれから作るクラス「MainWindow」を継承して使われることを前提に見ていきたいと思います!
「restore」「show」「closeEvent」については、実装しながら解説したいと思います!(`・ω・´)ゞ
データを出し入れする入れ物
PySide(Qt)には、データを保存したり、読み込んだりする便利な「QSettings」がありますので、コチラを使った例でご紹介したいと思います。JSONやXMLなどといった汎用フォーマットを使用したい場合は、オリジナルのロジックに変更していただければOKです!
Windowsでの「QSettings」は、「レジストリー」という特殊な領域に保存する方法と、INIという汎用フォーマットで保存する方法の2種類があります。レジストリーにガンガンデータを保存するのは、気持ち悪いっという人が多そうなので、INIを使ってみたいと思います。
import os from PySide import QtGui from PySide import QtCore from maya import OpenMayaUI import shiboken def mainWindow(): ptr = OpenMayaUI.MQtUtil.mainWindow() return shiboken.wrapInstance(long(ptr), QtGui.QWidget) class MainWindow(QtGui.QMainWindow): settingFileName = 'mainWindow.ini'# ※1 def __init__(self, parent=None, flags=QtCore.Qt.WindowFlags()): if parent is None: parent = mainWindow() super(MainWindow, self).__init__(parent, flags) filename = os.path.join( os.getenv('MAYA_APP_DIR'), 'myTool', self.settingFileName )# ※1 self.__settings = QtGui.QSettings(filename, QtGui.QSettings.IniFormat) self.__settings.setIniCodec('utf-8') def restore(self): pass def show(self): super(MainWindow, self).show() def closeEvent(self, event): super(MainWindow, self).closeEvent(event)
QSettingsは、ファイル名と、フォーマットを指定してインスタンスを作成します。「setIniCodec」を使って文字コードを「utf-8」を指定すると、日本語があった場合にいい感じになります!
ウインドウの位置と大きさの保存
では、早速「ウインドウの位置と大きさ」を保存してみましょう!
import os from PySide import QtGui from PySide import QtCore from maya import OpenMayaUI import shiboken def mainWindow(): ptr = OpenMayaUI.MQtUtil.mainWindow() return shiboken.wrapInstance(long(ptr), QtGui.QWidget) class MainWindow(QtGui.QMainWindow): settingFileName = 'mainWindow.ini' def __init__(self, parent=None, flags=QtCore.Qt.WindowFlags()): if parent is None: parent = mainWindow() super(MainWindow, self).__init__(parent, flags) filename = os.path.join( os.getenv('MAYA_APP_DIR'), 'myTool', self.settingFileName ) self.__settings = QtGui.QSettings(filename, QtGui.QSettings.IniFormat) self.__settings.setIniCodec('utf-8') def restore(self): pass def show(self): super(MainWindow, self).show() def closeEvent(self, event): self.__settings.setValue('geometry', self.saveGeometry()) super(MainWindow, self).closeEvent(event)
QSettingsを使って、データを保存するには「setValue」を使い、「名前と値」を指定することで保存できます。ウインドウの位置と大きさっと聞くと、「pos」と「size」かなー?っと思った方もいるかもしれませんが、「saveGeometry」を使うと保存に適したデータを一発で取得することができます!
データを保存する時に指定した名前は、読み込みの時にも使います!
保存されたデータを見てみると、こんな感じで保存されます!
[General] geometry=@ByteArray(\x1ÙÐË\0\x1\0\0\0\0\0±\0\0\x1'\0\0\x2\x1a\0\0\x2\x3\0\0\0¹\0\0\x1\x46\0\0\x2\x12\0\0\x1û\0\0\0\0\0\0)
読み込むには?
保存と違い、読み込みは、ちょっとややっこしいです。
継承することを前提に考えると、「__init__」で復元するのは好ましくありません。継承したクラスAでも「__init__」を定義すると思います。そしてすぐに「super」を使って基底クラスの「__init__」を実行することになると思います。
っということは!
- クラスAで「__init__」の定義
- クラスAの「super」が実行
- 基底クラスの「__init__」が実行
- ウインドウの位置と大きさを復元
- クラスAの「__init__」の処理
もし、サイズの指定や位置の指定があると、復元した意味がなくなる
っとなるわけです(;´∀`)
これを踏まえて、実装していきましょう!
import os from PySide import QtGui from PySide import QtCore from maya import OpenMayaUI import shiboken def mainWindow(): ptr = OpenMayaUI.MQtUtil.mainWindow() return shiboken.wrapInstance(long(ptr), QtGui.QWidget) class MainWindow(QtGui.QMainWindow): settingFileName = 'mainWindow.ini' def __init__(self, parent=None, flags=QtCore.Qt.WindowFlags()): if parent is None: parent = mainWindow() super(MainWindow, self).__init__(parent, flags) filename = os.path.join( os.getenv('MAYA_APP_DIR'), 'myTool', self.settingFileName ) self.__settings = QtGui.QSettings(filename, QtGui.QSettings.IniFormat) self.__settings.setIniCodec('utf-8') def restore(self): self.restoreGeometry(self.__settings.value('geometry')) def show(self): self.restore() super(MainWindow, self).show() def closeEvent(self, event): self.__settings.setValue('geometry', self.saveGeometry()) super(MainWindow, self).closeEvent(event)
まずはメソッド「restore」から見ていきたいと思います。このメソッドは、設定ファイルからデータを読み込み復元する、オリジナルのメソッドです。
QSettingsで保存したデータを読み込むには「value」に保存した時の名前を指定すると取り出すことができます。取り出したデータは「restoreGeometry」を使うと前回の位置や大きさに戻すことが簡単にできます。「saveGeometry」と「restoreGeometry」がセットになっているわけですね!(*´ω`*)v
このままでは、メソッド「restore」が実行されないので、元に戻すことができません。継承されたクラスで「restore」を実行してもらう手もありますが、メンドイ!!
そこで、メソッド「show」をオーバーライドして、表示する前に設定を復元してから表示する!っという流れにしました。
継承して使うには?
継承して使う場合は、ファイル名が重複しないように、オーバーライドを忘れないようにしましょう!
class MyToolWindow(MainWindow): settingFileName = 'MyToolWindow.ini' def __init__(self, *args, **kwargs): super(MyToolWindow, self).__init__(*args, **kwargs)