プラグインでの Qt の使用方法
 
 
 

開発者の準備作業

Maya に同梱されているのは、自身で使用する Qt ライブラリのサブセットのみです。Qt を使用する場合、プラグインの開発者は別途 Qt をインストールして、Maya に同梱のライブラリではなく Qt ヘッダー ファイルを使用できるようにしておくことが必要です。 Qt の適切なバージョンの設定、インストールの詳細については、Maya プラグインで使用するための Qt の設定を参照してください。

プラグインの作成

独自の Qt アプリケーションを一から作成するには、独自の QCoreApplication または QApplication のインスタンスを作成してそのアプリケーションのイベント ループを処理できるようにする必要があります。代わって、Maya プラグインの作成には、Qt の qApp マクロで読み出せる Maya 独自のアプリケーション オブジェクトを使用します。以下のサンプル コードでは、qApp マクロを使用して Maya のアプリケーション名を読み出しています。

QCoreApplication*  app = qApp;
if (app) {
    cout << "Application name is '" << app->applicationName().toStdString() << "'" << endl;
}

Qt を使用した新規ウィンドウやダイアログの作成は、Qt の標準的なアプリケーションの作成と同じ方法で行います。devkit の helixQtCmd プラグインにごく単純なサンプルが用意されています。このプラグインには、Qt ベースのボタンを作成する helixQt コマンドがあります。このボタンを押すと、常に API コールを使用してらせん状のカーブが作成されます。

このボタンは、カーブの作成を処理するために createHelix() スロットを追加した通常の Qt pushButton です。

class HelixButton : public QPushButton
{
   Q_OBJECT
public:
   HelixButton(const QString& text, QWidget* parent = 0); 
   virtual	~HelixButton();
public slots:
   void	createHelix(bool checked);
};

helixQt コマンドを実行すると、常に、まずそのボタンの有無が確認されます。ボタンがない場合は作成し、クリックした信号をその createHelix スロットにコネクトして、ボタンをクリックしたときにらせんを作成するコードが必ず実行されるようにします。

QPointer	HelixQtCmd::button;
MStatus HelixQtCmd::doIt(const MArgList& /* args */)
{
   if (button.isNull()) {
       button = new HelixButton("Create Helix");
       button->connect(button, SIGNAL(clicked(bool)), button, SLOT(createHelix(bool)));
       button->show();
       }

ボタンがある場合、このコマンドは、そのボタンを確実に表示して他のウィンドウの後ろに隠れないようにします。

   else {
       button->showNormal();
       button->raise();
       } 
   return MS::kSuccess;
}

Qt を使用して直接作成したコントロールは、通常、Maya の UI コマンドで認識されます。このようなコントロールは、 コマンドでは一覧表示されず、 など特定タイプのコントロールのコマンドでは認識もされません。ただし、汎用のコントロール コマンドは例外です。一意の名前を指定してさえいれば、 コマンドを使用してその有無をテストし、表示設定などコントロールに関する基本操作を実行できます。

たとえば、helixQtCmd プラグインの createHelix メソッドでボタンに「myButton」という一意の名前が指定されているとします。

   button = new HelixButton("Create Helix");
   button->setObjectName("myButton");

以下の MEL スクリプトを使用すると、このボタンを非表示にできます。

if (`control -q -exists myButton`) {
   control -e -visible false myButton;
}

ただし、同じコードで button コマンドを使用しても、動作しません。これは、button コマンドが自身が作成したボタンしか認識しないためです。

if (`button -q -exists myButton`) {      // Will always be false.
   button -e -visible false myButton;   // Will never be executed.
}

Qt を使用して Maya コマンドで作成した UI 要素に直接アクセスできるようにした方が望ましい場合もあります。 API クラスには、Maya のコントロール、レイアウト、ウィンドウ、メニュー項目の基本となる Qt オブジェクトを読み出すためのメソッドが用意されています。たとえば、以下の MEL スクリプトで作成した「myCheckBox」という名前の Maya checkBox コントロールがあるとします。

window;
columnLayout;
checkBox myCheckBox;
showWindow;

MQtUtil クラスを使用して checkBox の QWidget ポインタを読み出し、それにより checkBox のカレントの状態を定義することができます。

QWidget* control = MQtUtil::findControl("myCheckBox");
if (control) {
   QCheckBox* cb = qobject_cast(control);
   if (cb) {
      if (cb->isChecked()) {
          MGlobal::displayInfo("myCheckBox is checked");
      } else {
          MGlobal::displayInfo("myCheckBox is not checked");
      }
   }
}

前述の例では、MQtUtil を使用する場合は常に十分な注意が必要であることもわかります。このコードは、Maya の コマンドで QCheckBox ウィジェットまたは QCheckBox 由来の要素を作成する場合のみ動作します。これは Maya の現行バージョンの場合で、将来的には変更される可能性があります。Qt を使用して Maya のコマンドで作成した UI 要素に直接アクセスできるようにコードを記述しておくと、Maya の新しいリリースでも確実に意図した通りに動作します。

レイアウトは、注意して作成しなければ、さまざまな問題のもとになりかねません。

以上の問題やレイアウトに関する問題の詳細については、 を参照してください。

いずれの問題でも、最終手段としては MQtUtil の使用を検討してください。これは必要があれば使用できますが、適切な結果を得るには十分な注意と試行錯誤が欠かせません。

プラグインのビルド

Maya が提供する Qt ライブラリにはカスタマイズが含まれているものもあるため、Qt でプラグインにリンクする場合、Maya の Qt ライブラリはリンク パスで別途インストールした Qt の前に記述する必要があります。これには、Maya devkit にある Makefile.qt を使用してコマンド ラインからプラグインをビルドするのが最も簡単です。たとえば、次のようになります。

Makefile.qt は Qt の qmake コマンドを使用してプラグインのビルドを制御します。これには、プラグインに拡張子 .pro で終わる qmake プロジェクト ファイルが必要です。

以下に示す helixQtCmd.pro は、devkit で helixQtCmd プラグインに用意されているプロジェクト ファイルです。これで、大部分のプロジェクト ファイルは単純な構成であることが良くわかります。

include(qtconfig)
TARGET = helixQtCmd
HEADERS += helixQtCmd.h
SOURCES += helixQtCmd.cpp
LIBS += -lOpenMayaUI

TARGET 設定には、プラットフォーム固有の拡張子を除いたプラグインの名前を記述します。

HEADERS 設定には、プラグインの一部であるすべてのヘッダー ファイルの一覧をスペースで区切って記述します。

SOURCES 設定には、プラグインの一部であるすべてのソース ファイルの一覧をスペースで区切って記述します。

デフォルトでは、プラグインは Maya の Foundation ライブラリと OpenMaya ライブラリに自動的にリンクされます。他のライブラリが必要な場合は、LIBS 設定に追加します。 ライブラリの名前の前には「-l」を付け、追加ライブラリのディレクトリは「-L」で指定する必要があります。たとえば、次のようになります。

LIBS += -L/usr/local/lib -lxml

さらに複雑な事例の場合は、Qt qmake のマニュアルを参照してください。

デバッグ

Qt のサンプル プラグインは、すべてリリース(非デバッグ)モードでビルドされています。デバッグ用にビルドするには、.pro ファイルで以下の手順に従って qmake のデバッグ構成パラメータをオンにします。

CONFIG += debug

Linux と OS X でのデバッグ用にプラグインをビルドする場合はこれで十分です。ただし、残念ながら、Windows の場合は、デバッグ構成の設定はデバッグ情報付きのプラグインをコンパイルするだけではなく、デバッグ バージョンの Qt ライブラリに強制的にリンクします。このため、Qt ライブラリのリリース バージョンでリンクされた Maya との互換性が失われてしまいます。プラグインに使用する Qt のクラスによっては、Maya にロードできたりできなかったりしますが、ロードされた場合でも、正しく動作しないと思われます。これは、Maya の QCoreApplication またはその他の Qt のグローバル値にアクセスできないためです。この問題を回避するには、debug 構成パラメータを前述のように設定し、以下のコマンドを使用して myPlugin のプラグイン名を置き換えて中間的な makefile をビルドします。

nmake /f Makefile.qt myPlugin.mak

これは特に、プラグイン用の .mak.Debug ファイル(myPlugin.mak.Debug など)を生成します。生成されたファイルを編集してLIBS 行を探し、ファイル名の末尾の d を削除してすべてのデバッグ用の Qt ライブラリを非デバッグ バージョンに置き換えます。たとえば、helixQtCmd.mak.DebugLIBS 業の冒頭は以下のようになります。

LIBS = /LIBPATH:..\..\lib ..\..\lib\OpenMaya.lib ..\..\lib\Foundation.lib ..\..\lib\OpenMayaUI.lib c:\qt-adsk-4.7.1\lib\QtGuid4.lib c:\qt-adsk-4.7.1\lib\QtCored4.lib`

QtGuid4.libQtGui4.libQtCored4.libQtCore4.lib に置き換えると、以下のようになります。

LIBS = /LIBPATH:..\..\lib ..\..\lib\OpenMaya.lib ..\..\lib\Foundation.lib ..\..\lib\OpenMayaUI.lib c:\qt-adsk-4.7.1\lib\QtGui4.lib c:\qt-adsk-4.7.1\lib\QtCore4.lib`

ここで、変更した .mak.Debug ファイルを使用し、以下のようにプラグインを明示的にビルドします。

nmake /f myPlugin.mak.Debug debug\myPlugin.mll

これでも、Windows の場合はまだ問題が残ります。Qt の QList テンプレート クラスには、Qt オブジェクトを作成、破棄できるインライン メソッドがあります。 このメソッドはインライン化されているため、デバッグ用にビルドしたプラグイン コードによってコールされると、作成または削除したすべてのオブジェクトが Microsoft の C Runtime Library のデバッグ バージョンからメモリ アロケータを使用します。メソッドを Maya 内でコールした場合、C Runtime Library のリリース バージョンが使用されます。したがって、Maya 内でリリース バージョンのランタイム ライブラリを使用してオブジェクト割り当てて、デバッグ バージョンのランタイム ライブラリで削除する、またはその逆の状況が考えられます。ところが、Microsoft の C Runtime Library のリリース バージョンとデバッグ バージョンでは互換性がないため、このような操作を行うとクラッシュしてしまいます。

現在のところ、このような問題の可能性が確認されている Qt クラスはQList だけですが、他の Qt テンプレート クラスでも同様の問題が発生する可能性はあります。これに対する現段階での回避策は、コードに Qt テンプレート クラスを使用しないこと、または Windows ではプラグインのビルドをリリース モードでのみ行うことのいずれかです。