一半君的总结纸

听话只听一半君

#101 如何找到一个窗口(window)并查询他所有的子layout 和控件(controls)?

你可以用 “lsUI” 命令来得到所有的MEL windows和controls, 如果加上’-type‘ flag,你就可以只返回window:

string $allWindows[] = `lsUI -type "window"`;
// Result: CommandWindow MayaWindow //

你可以通过查询window的标题栏的名字(title)来猜出他是什么window:

window -q -title $allWindows[0];
// Result: Script Editor //

但是如果你想反过来 – 已经知道title,想找到window的UI的名字:

proc string findWindowByTitle( string $windowTitle )
{
  // 先给返回值赋予一个默认的空string以表示找不到对应的 window .
  //
  string $windowUI = "";
  string $allWindows[] = `lsUI -type "window"`;

  for ( $w in $allWindows )
  {
    // 比较指定的 title 是不是和当前查询的窗口相同.
    //
    if ( $windowTitle == `window -q -title $w` )
    {
      // 找到!
      //
      $windowUI = $w;
      break;
    }
  }

  return $windowUI;
}

试运行:

string $windowUI = findWindowByTitle( "Script Editor" );
print ( "The window titled \"" + $windowTitle + "\" is: " + $windowUI + "\n" );

// Result: The window titled "Script Editor" is: CommandWindow //

显然下一步就是使用已经拿到的window UI的名字来查询他有哪些子controls(child controls). 这里你可能会碰到点障碍,因为 “window” 命令并没有一个叫做 ‘-childArray‘ 的flag, 而且没有什么直接的方法能查询一个window里用了哪些 layout 或者 controls . 因此, 只好使用下面的“反向”查找的方法.

global proc string findWindowLayout( string $windowUI )
{
  // 穷举法: 首先得到所有的 control layouts, 然后再来看他是不是
  // 指定的 window 的 child.
  //
  string $controls[] = `lsUI -l -controlLayouts`;

  // 在window的名字后面加个通配符*, 给"gmatch" 命令用.
  //
  string $pattern = $windowUI + "*";

  // 给返回值先赋一个空字符串,表示没有找到匹配的 layout.
  //
  string $layout = "";

  for ( $ui in $controls )
  {
    // 比较上面的通配符pattern和当前的control.
    //
    if ( `gmatch $ui $pattern` )
    {
      // 找到!
      //
      string $tokens[];
      int $numTokens = `tokenize $ui "|" $tokens`;
      if ( $numTokens > 1 )
      {
        // 这里返回control的路径(path), 他的parent是 window .
        // 在访问UI controls的时候最好始终使用完整路径(full path).
        //
        $layout = $tokens[0] + "|" + $tokens[1];

        break;
      }
    }
  }

  return $layout;
}

使用示例:

string $windowUI = "MayaWindow";
string $layout = findWindowLayout( $windowUI );

if ( "" != $layout )
{
  // 找到layout.
  //
  print ( "Layout for window \"" + $windowUI + "\": " + $layout + "\n" );

  // 查询所有的 child controls.
  //
  string $ca[] = `layout -q -ca $layout`;
  print ( "Layout controls:\n" );

  for ( $c in $ca )
  {
    // 始终显示 UI control 的完整路径(full path).
    //
    print ( $layout + "|" + $c + "\n" );
  }
}
else
{
  print ( "Layout for \"" + $windowUI + "\" not found.\n" );
}

Layout for window "MayaWindow": MayaWindow|mayaMainWindowForm
Layout controls:
MayaWindow|mayaMainWindowForm|formLayout1
MayaWindow|mayaMainWindowForm|formLayout2
MayaWindow|mayaMainWindowForm|formLayout3
MayaWindow|mayaMainWindowForm|TimeSliderForm
MayaWindow|mayaMainWindowForm|formLayout4
MayaWindow|mayaMainWindowForm|formLayout5
MayaWindow|mayaMainWindowForm|formLayout6
MayaWindow|mayaMainWindowForm|formLayout7

现在你已经知道这个window有哪些layout,下一步你就可以查询每个layout有哪些children了. 你不需要知道具体是什么layout,因为可以用通用的 “layout” 命令来查询子controls(child array),返回值是一个字符串数组.

string $ca[] = `layout -q -childArray $layout`;

但是,如果你想查询某些layout特有的属性的话,那通用的”layout” 命令就不行了. 不过你可以用 “objectTypeUI” 命令来查询感兴趣的layout是什么类型, 然后再对不同的layout分别查询他们特有的属性.

if ( `layout -q -exists $layout` )
{
  string $layoutType = `objectTypeUI $layout`;

  switch ( $layoutType )
  {
    case "formLayout":
    {
      // 用 "formLayout" 命令来继续查询.
      //
      break;
    }
    case "frameLayout":
    {
      // 用 "frameLayout" 命令来继续查询.
      //
      break;
    }
    case "shelfLayout":
    {
      // 用 "shelfLayout" 命令来继续查询.
      //
      break;
    }
    default:
    {
      // 不支持的...
    }
}

下面是一个 findWindowLayout() 的应用示例, 按层级关系打印出Maya主窗口(main window)下的所有子layout :

proc printLayoutHierarchy( string $layout, string $parent, int $tab )
{
  string $bars = "| | | | | | | | | | | | | | | | | | | | | | | | | | | ";

  // Note: 你必须指定一个control的完整路径以避免重名造成的错误结果
  //       (否则这里会出现无限循环卡死 (infinite loop)的情形).
  //
  string $path = ( $parent + "|" + $layout );

  if ( `layout -q -exists $path` )
  {
    // 打印树形( pseudo-tree )结构.
    //
    if ( $tab > 1 ) print ( `substring $bars 1 (($tab-1)*2)` );
    if ( $tab > 0 ) print ( "+ " );
    print ( $layout + "\n" );

    // 查询这个layout的所有 children .
    //
    string $ca[] = `layout -q -ca $path`;

    // And recurse...
    //
    for ( $c in $ca )
    {
      printLayoutHierarchy( $c, $path, $tab+1 );
    }
  }
}

// 找到这个 layout control 在 Maya的 main window下的完整路径.
//
string $windowUI = "MayaWindow";
string $path = findWindowLayout( $windowUI );

// 把返回的完整路径分割成路径和layout name两部分 (以便于下面print).
//
string $layout = `match "[^|]*$" $path`;
string $parent = `substitute "|[^|]*$" $path ""`;

// 构建一个层级树形结构.
//
printLayoutHierarchy( $layout, $parent, 0 );

下面是输出结果的示意:

mayaMainWindowForm
+ formLayout1
| + formLayout12
| | + formLayout13
| | | + formLayout40
| | | | + formLayout41
| | | | | + presetForm
| | | | | + masksForm
| | | | | + selectMaskForm
| | | | | | + hierarchyIcons
| | | | | | | + hierPickMenuLayout
| | | | | | + objectMaskIcons
| | | | | | | + objPickMenuLayout
| | | | | | + componentMaskIcons
| | | | | | | + compPickMenuLayout
| | | | | + snapIcons
| | | | | + historyLayout
| | | | | | + formLayout42
| | | | | | + formLayout43
| | | | + formLayout44
+ formLayout2
| + formLayout14
| | + formLayout15
| | | + formLayout49
| | | | + frameLayout4
| | | | | + formLayout50
| | | | + ShelfLayout
| | | | | + Admin
| | | | | + Animation
| | | | | + Colouring
| | | | | + Develop
| | | | | + LevelTools
| | | | | + Polygon
| | | | | + Primitives
| | | | | + Render
| | | | | + Tools
| | | | | + UI
+ formLayout3
| + viewPanes
| | + modelPanel1
| | + modelPanel2
| | + modelPanel3
| | + modelPanel4
| + formLayout8
| | + formLayout26
| | | + formLayout27
| | | | + frameLayout6
| | | | | + gridLayout2
| | | | + frameLayout7
| | | | | + ToolboxConfigurationGrid
| | | | | | + ToolboxConfigurationForm
| | | | | | | + ToolboxContentFrame0
| | | | | | | + ToolboxContentFrame1
| | | | | | | + ToolboxContentFrame2
| | | | | | | + ToolboxContentFrame3
| + formLayout9
| | + formLayout28
| | | + formLayout29
| | | | + formLayout34
| | | | | + AEmenuBarLayout
| | | | | | + AErootLayout
| | | | | | | + AENothingSelectedLayout
| | | | | | | + AEbaseFormLayout
| | | | | | | | + AEheaderLayout
| | | | | | | | | + AEtabLayout
| | | | | | | | + AEnodeNameHeaderLayout
| | | | | | | | + AEcontrolFormLayout
| | | | | | | + AEselectAndCloseButtonLayout
| + formLayout10
| | + formLayout30
| | | + formLayout31
| | | | + tabLayout1
| | | | | + columnLayout1
| + formLayout11
| | + formLayout32
| | | + formLayout33
| | | | + formLayout35
| | | | + ChannelsLayersPaneLayout
| | | | | + formLayout36
| | | | | | + menuBarLayout1
| | | | | | | + frameLayout1
| | | | | + formLayout37
| | | | | | + menuBarLayout2
| | | | | | | + formLayout38
| | | | | | | | + DisplayLayerUITabLayout
| | | | | | | | | + DisplayLayerTab
| | | | | | | | | | + LayerEditorDisplayLayerLayout
| | | | | | | | | + RenderLayerTab
| | | | | | | | | | + LayerEditorRenderLayerLayout
| | | | + formLayout39
+ TimeSliderForm
| + formLayout16
| | + formLayout17
| | | + formLayout45
| | | | + frameLayout2
| | | | + gridLayout1
+ formLayout4
| + formLayout18
| | + formLayout19
| | | + formLayout46
| | | | + frameLayout3
| | | | + formLayout47
+ formLayout5
| + formLayout20
| | + formLayout21
| | | + formLayout48
| | | | + commandLine1
+ formLayout6
| + formLayout22
| | + formLayout23
| | | + frameLayout5
| | | | + formLayout51
+ formLayout7
| + formLayout24
| | + formLayout25

19 Feb 2005

加强版:

其实还有个更方便的办法可以知道Maya自己UI各个部分的名字,知道之后就可以随便乱改Maya界面了,会用到这个工具guihelper,这是大师Jo Jurgens编的一个便于script作者修改界面用的辅助小工具,但是自2003年以后就没有更新了,我在2014里试了下,随便乱加了几个新的control,去掉了不存在的几个control,貌似可以正常工作,但是我没有仔细去看。初步试验工作正常,我把我修改过的放在了这里.

详细使用方法见script内说明,这里举一个例子.运行

guiHelper_addMenuToAll MayaWindow;

之后他会给所有能识别出来的control上加一个右键菜单,然后你可以方便的找到这个control的完整路径
假如你想让toolbox最下方的自动桌按钮按了之后不是打开自动桌官网,而是运行你自己的某工具,那么可以在toolbox空白区域右击鼠标,选择guiList,在新弹出的窗口中可见那个UI的名字叫做mayaWebButton,由于这显然是一个特意起的名字,所以你访问他的时候不需要全路径 比如

guiHelper

# 由于我不知道这个按钮是什么control,所以我先查询一下
objectTypeUI mayaWebButton;
// Result: iconTextButton //

# 我先看看为什么按了他会开Maya在线帮助
iconTextButton -q -c mayaWebButton
// Result: showHelp -absolute "http://www.autodesk.com/maya" //

# 然后我去看了看showHelp的帮助,我决定按这个按钮开PyMel帮助
iconTextButton -e -c "showHelp -docs \"PyMel/index.html\"" mayaWebButton

# 我还可以给他换个图标,至于我是如何找到图标的名字的以后会有一篇单独介绍
iconTextButton -e -i "greasePencilHelpOff.png" mayaWebButton

toolbox效果2008-toolbox如左图所示,黑色的截图是MAYA 2014, 白色的是当年在MAYA 2008里我在做解算cloth的时候的工作界面,如图所示,你可以添加任意UI controls到toolbox里

我总得写点什么把下面这一大片白填满,还没想到有什么可以写的

Related How-To’s

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: