2018年12月3日月曜日

リストをフィルタリングしたい

自作のツールを作るとき、リストを表示するレイアウトには treeView を良く利用しているのですが、大量にアイテムが並んでいたりすると項目を選ぶのに苦労します。
そんなこんなで、Outliner に付いている文字を入力したら表示物を絞れる機能を付けたいなぁと思ってしまうのでした。

Outliner に付いているってのは、こんなヤツです。




文字を入力することで、たぶん後方一致のノード名だけにフィルタリングされます。

ノードが大量にあった場合、所定のものを探し出すのに便利です。


このコントローラはなんなのかと調べてみたら単なる textField のようです。
コマンドヘルプで確認したところ、-searchField(-sf)というフラグが見つかりました。
普通に textField; を実行した場合は、こんな感じになりますが、


textField -sf; で実行すると・・・

簡単にアウトライナにくっ付いているコントローラみたいになりました。
文字を入力してみるとフィールドにバツアイコンも自動で表示されるようになっています。

でも、もっと本家に似せるとなると、ここから色々と付け加える必要がありそうです。


自前でコード化するのは大変そうなので、このコントローラを使用しているツールをコマンドログなどから解析してみると、filterUI.mel というスクリプトに辿り着きました。

filterUICreateField() というプロシージャで作成しているようです。
余計なウンチクは抜きにしてサンプルコードを書いてみます。

global proc myProc(
    int $isEnter )
{
    // エンターを押した場合は何もしない
    if( $isEnter ) return;
    
    // GUI名の設定
    global string $gMySearchField;
    global string $gMyTreeView;
    string $field=$gMySearchField;
    string $view =$gMyTreeView;
    
    // フィルター文字列を取得
    string $filter=`textField -q -tx $field`;
    
    // シンボルの更新
    filterUIUpdateFilterStatus( $view,(0<`size $filter`) );
    
    
    // フィルター文字列の確認
    if(""==$filter)
    {
        filterUIClearFilter( $view );
        return;
        
    }
    
    
    // treeView 内のフィルタリング
    string $ca[]=`treeView -q -ch "" $view`;
    for( $e in $ca )
    {
        int $vis=0;
        if(`gmatch $e ($filter+"*")`) $vis=1;
        treeView -e -iv $e $vis $view;
        
    }
    
}



global proc test()
{
    global string $gMySearchField;
    global string $gMyTreeView;
    
    string $window=`window`;
    
    // レイアウト作成
    string $form=`formLayout`;
        string $tree=`treeView`;
            string $sea=filterUICreateField( $tree,$form );
            string $ca[]=`formLayout -q -ca $sea`;
            $searchField=$ca[0];
            textField -e -tcc "myProc 0" $searchField;
            textField -e -cc  "myProc 1" $searchField;// filterUIでのコマンドを上書き
            setParent $form;
        
        
    // 配置調整
    formLayout -e
        -af $sea  "left" 0 -af $sea  "right" 0 -af $sea  "top" 0
        -af $tree "left" 0 -af $tree "right" 0 -ac $tree "top" 0 $sea -af $tree "bottom" 0
        $form;
    
    
    // treeViewにアイテム追加
    treeView -e -ai "testA" "" $tree;
    treeView -e -ai "testB" "" $tree;
    treeView -e -ai "sampleA" "" $tree;
    treeView -e -ai "sampleB" "" $tree;
    
    
    showWindow $window; 
    
    
    // GUI名をグローバル変数へ
    $gMySearchField=$searchField;
    $gMyTreeView=$tree;
    
}



実行すると、こんなウィンドウが出てきます。

文字を入力するときちんとフィルタリングもされていますねぇ。

スバラシイ。

57行目の部分はちょっと重要で、filterUI.mel で指定された changeCommand を上書きしておかないと挙動が乱れます。
なんか Outliner 系レイアウトを使用しているともっと簡単にフィルタリングしてくれるみたいなんですが、他のレイアウトだと textField へ自作のプロシージャを登録しないとイケナイみたいです(56行目)。

Outliner に倣って後方一致にしていますが、前方一致にも対応させたい場合、34行目の gmatch を ("*"+$filter+"*") に修正ですね。
更に、Maya は大文字・小文字を厳密に区別するため、もっとザックリと一致させたい場合は、tolowe() とか使うのもアリです。


そんなこんなで、Paint Skin Weights ツールで filterUIUpdateFilterStatus() を使用していないと云うバグを見つけてしまいましたとさ。


0 件のコメント:

コメントを投稿