UI関連 ウィンドウ(ダイアログ)をチャンと閉じる


たまにやってくるスクリプトのお勉強会

今日のメモは既に開いていたウィンドウ(ダイアログ)を閉じる方法。

自前のツールなどでは今まで下の様な感じで
既に開いていたウィンドウ(ダイアログ)をtryを使って強引に閉じていた。

try(cui.FloatDialogBar myDialog)catch();
try(cui.unRegisterDialogBar myDialog)catch();
try(closeRolloutFloater myDialog) catch();
try(destroydialog myDialog)catch();

これはあまりイケてないので、
ちゃんとした方法に書き換えるとこうなる。
UIAccssorを使ってダイアログを取得して閉じる感じ。

function CloseDialogByName digName = (
    dig = UIAccessor.GetPopupDialogs();
    for d in dig do (
        winTxt = uiAccessor.getWindowText d;
        if (findstring winTxt digName) != undefined do (
            print(format "% is Close." winTxt);
            UIAccessor.CloseDialog d;
        )
    )
)

CloseDialogByName("MAXScript リスナー");

ちなみに、この方法だとmaxscriptで作ったdaialogと
Pysideで作ったウィンドウウィジット両方につかえる。

 

 

pythonというか、PySide(PySide2)でやるならば・・・

def close_tool_window(wname):
    widgets = QApplication.allWidgets()
    for w in widgets:
        if w.objectName() == wname:
            print("Closed : {}".format(w.objectName()))
            w.close()


close_tool_window("MyWindow")

見たいな感じで書けばいい。

ただし!
これはあくまでも閉じる(非表示になる)だけで
ウィンドウ

ウィジット自体は破棄されていない。

破棄するためには、ウィンドウが閉じた際のイベントで破棄を実行させる。
まとめて書くとこんな感じ。

r"""test window
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import MaxPlus

# この書き方は乱暴すぎる!非推奨
try:
    from PySide2.QtWidgets import *
    from PySide2.QtGui import *
    from PySide2.QtCore import *
    UNICODE = -1

except ImportError:
    from PySide.QtGui import *
    from PySide.QtCore import *
    UNICODE = QApplication.UnicodeUTF8


class MyWindow(QMainWindow):
    # QDockWidgetとするとドッキング可能になる QMainWindow
    def __init__(self, *args, **kw):
        QMainWindow.__init__(self, *args, **kw)
        self.setObjectName("MyWindow")
        self.setWindowTitle("MyWindow")

        # セントラルを作成
        self.centralwidget = QWidget(self)
        self.centralwidget.setObjectName("centralwidget")
        # たてレイアウト追加
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")

        self.reload = QPushButton(self)
        self.reload.setGeometry(QRect(4, 48, 120, 22))
        self.reload.setObjectName("Test")
        self.reload.setText("Test")
        self.verticalLayout.addWidget(self.reload)  # たてレイアウトに追加

        self.setCentralWidget(self.centralwidget)  # セントラルを最後に追加
        # Dialog.resize(148, ypos)
        QMetaObject.connectSlotsByName(self)

    def closeEvent(self, event):
        r"""close event override"""
        # ここがミソ、閉じたあとで破棄
        self.deleteLater()


class _GCProtector(object):
    r"""maxの場合は必要"""
    widgets = []


def close_tool_window(wname):
    widgets = QApplication.allWidgets()
    for w in widgets:
        if w.objectName() == wname:
            print("Closed : {}".format(w.objectName()))
            w.close()


def get_parent_window():
    r"""親となるウィンドウを取得する
    Max2018の場合はMaxPlus.GetQMaxMainWindow()で取得
    """
    ver = MaxPlus.Core.GetMaxVersion()
    if ver < 1300000000:
        parent_window = MaxPlus.GetQMaxWindow()
    else:
        parent_window = MaxPlus.GetQMaxMainWindow()
    return parent_window


def main():
    r"""main"""
    app = QApplication.instance()
    if not app:
        app = QApplication([])

    close_tool_window("MyWindow")
    win = MyWindow(get_parent_window())
    _GCProtector.widgets.append(win)
    # MaxPlus.MakeQWidgetDockable(win, 4)  # Maxではこれでドッキング可能になる
    # win.setFloating(True)  # dockingwidgetの場合はfloatをtrueにすると切り離しが出来る
    win.show()


if __name__ == '__main__':
    main()

こんな感じ。

ミソはウィンドウのcloseEventをオーバーライドして
そこにself.deleteLater()を追加してる部分。

これでwindowが閉じた際に自分自身を破棄しに行くので
windowが延々と残り続けることがない。

たぶんMayaでも同じような感じになると思う。
もしくは、ウィンドウのインスタンスを作成時にバッティングを確認して
既にウィンドウウィジットがあればソレを表示するか破棄してもいいかも。
結構色んな方法がありそう。
ちなみに破棄する際はparentを切ってから破棄すること。

 

と言うことで今日のメモでした~。

最近色んな言語で色んなUI作ってるからすごい面倒・・・。
もうpythonで一本化したいよ・・・

Leave a comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください