Python + MaxScriptのツール開発入門(Max2020版)その13

2021年9月3日

 その10で掲げた改善点のうち、まだ改善できていない残りの二つを改善しましょう。

  • ダイアログのタイトルがDialogなのをなんとかする
  • ダイアログの上にある謎の「?」を表示しないようにする

の二つです。

ダイアログのタイトルを変更する

 ダイアログのタイトルは、QWidget クラスが持っているsetWindowTitle() というメソッドを使用して簡単に変更することができます。

# ウィンドウタイトルを指定
self.setWindowTitle("GridCopy")

 これをGridCopy クラスのコンストラクタ(__init__()) の中で実行するだけです。

images/ss25.png

 これまでの流れに比べてあまりにもあっけないですが、これだけなのでありました。

ダイアログの上にある謎の「?」を表示しないようにする

 これですね。気になる人は最初からずっとこれが気になっていたかもしれません。

images/ss26.png

 これをなんとかしましょう。これは本来、押すとその画面に関するヘルプが表示される、というボタンです。もちろん何かしら実装しない限り何も起こりません。ヘルプを表示する動作を実装するか、または何も起こらないのであればボタン自体を外しておいた方がわかりやすいですね。

 ヘルプの実装はまた別の機会に譲るとして、ここではこの?を非表示にする方向でいきましょう。

 この?ボタンは、QtDesigner でこの窓を作ったときのことを思い出してもらうとわかりますが、私たちが自分で配置したものではありません。もちろんその隣にある×のボタンも、私たちが配置したものではありません。QDialog がもともと持っているものです。

 このような、QWidget クラス(とそれを継承しているクラス)が元から持っている機能は、WindowFlags という機能を使ってOn/Off を操作するようになっています。WindowFlags を操作するにはQtCore というモジュールで定義されている列挙体が必要です。

QtCore をインポートする

 そこでまず、QtCore をインポートします。

from PySide2 import QtCore

 これはコードの上部、いろいろなインポートを書いてある部分に書けば良いですが、やはりPySide2関連のものはまとめておくと見やすいと思います。

from PySide2 import QtCore, QtWidgets

のように、同じパッケージに含まれている複数のモジュールを並べて書くこともできます。

WindowFlags を操作する

 windowFlags はあらかじめセットされていて、それによって現在表示されているQDialog の様子が決定されています。そこで、まず今設定されているフラグを取得します。中身はややこしいことになっているはずですが、今のところそれを全部理解する必要はありません。

# 現在のwindowFlags を取得する
wf = self.windowFlags()

 次に問題の?ボタンですが、これはWindowContextHelpButtonHint という項目で定義されています。つまり、現在のQDialog に?ボタンが表示されているということは、今取得したwindowFlags ではこの項目のフラグが立っているということになります。非表示にするにはそのフラグを倒せばよい、ということになりそうです。

 フラグはビット列の操作になるため、倒したいフラグの反転(~はビット演算のNOT演算子です)と論理積を取れば、このフラグ以外は元の状態のまま、このフラグだけを倒すことができますね。

# 取得したwindowFlags のWindowContextHelpButtonHint だけを倒す
wf &= ~QtCore.Qt.WindowContextHelpButtonHint

 あとはこのようにしてできたこのwindowFlags を、元のQDialog に戻してやれば完成です。この部分は全体として次のようになります。

# もとのwindowFlags を取得
wf = self.windowFlags()
# それを操作する
wf &= ~QtCore.Qt.WindowContextHelpButtonHint
# できたものを再度セットする
self.setWindowFlags(wf)

 この処理をGridCopy クラスのコンストラクタで行えば良いでしょう。

images/ss27.png

 これで意図通り、「?」ボタンを消すことができました。

番外編:カスタムUI化する

 さて、ここまでの処理で目的はすべて達したわけですが、このwindowFlags の操作、毎回やるのは面倒ですね。これから作るツールの大半で、この「?」ボタンが不要だとしたら、最初から表示されない状態をデフォルトにできたら楽です。

 そこで、これが表示されないオレオレQDialog を作りましょう。

 ここでのポイントは、オレオレクラスは自分しか使わないにしろ、なるべく使いまわしが利くようになっていた方が良い、ということです。つまりあまり特殊なものは盛り込まず、しょっちゅう使うような機能を盛り込みましょう。

from __future__ import absolute_import, print_function, division
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QDialog

class MyDialog(QDialog):
    def __init__(self, parent):
        super(MyDialog, self).__init__(parent)
        wf = self.windowFlags()
        wf &= ~Qt.WindowContextHelpButtonHint
        self.setWindowFlags(wf)

 こんなふうに書いてみました。必要なものをインポートし、QDialog を継承したMyDialog クラスを定義します。コンストラクタ内でwindowFlags の操作をしているだけです。

 そしてGridCopy クラスの定義で、QDialog ではなく、このMyDialog を継承します。もちろん継承する前にインポートしておかないとエラーになります。私はMyDialog.py というファイルにMyDialog クラスの定義を書いたのでコードは以下のようになりました。

from MyDialog import MyDialog
class GridCopy(MyDialog, UI.Ui_Dialog):
    def __init__(self, parent, f_path):
        super(GridCopy, self).__init__(parent)
        self.setupUi(self)

 こんな具合です。QtWidgets.QDialog を継承していたところをMyDialog に置き換えただけです。MyDialog はQDialog を継承しているので、これで本来の機能もすべて損なわれずに備えたGridCopy が出来上がります。次からはこのMyDialogをベースにUIを作れば、あの「?」ボタンのことは気にしなくても良くなります。

まとめ

  • ウィンドウタイトルはsetWindowTitle() で変更できる
  • ウィンドウがもともと持っている機能はwindowFlags でOn/Off を管理する
  • もとからあるUIのクラスを拡張したクラスを作って使用することができる