一半君的总结纸

听话只听一半君

中古时代的用MEL写UI的方法总结纸

这是最基本方法,现在已经过时了,除非你想改Maya自带的某些ui(也许会用到),或者你想在没有pymel或者python的很老的Maya里写ui. 现在就算你用pymel写也还是用类似的方法,只是语法变一下.

想要有一个窗口,最少需要两行

window;
showWindow;

mel_window_basic

你看帮助里的例子都是这么写,但他是为了举例简短,如果你真写的时候显然不能这么写,你得放在proc里.

意思就是你得这样:

global proc fuckme(){
    window;
    showWindow;
}

如何source并运行script

然后你把他存在比如C:\Users\loser\Documents\maya\2014-x64\scripts里,或者存在MAYA_SCRIPT_PATH指定的路径里,比如在C:\Users\loser\Documents\maya\2014-x64\maya.env里加上一行

MAYA_SCRIPT_PATH=D:\holyshit

然后你把上面的脚本存成fuckme.mel放在d:\holyshit里面就可以了,(注意一般你的文件名要和你的主proc名一样),然后重启maya你就可以用fuckme来调用你的ui了,如果不想重启maya,也可以在script editor里运行

rehash;

这会刷新Maya已经知道的.mel文件列表,或者你也可以source那个.mel文件,又或者直接在script editor里ctrl+enter先框选再运行一下,以上三种方法效果一样.总之你source过后只要运行fuckme(); 就可以显示出窗口了.

注意: 每次你改了你的.mel文件之后,你得重新source过。这取决于你怎么写,有些人只在script editor里写,因为不太长,那你可以

global proc fuckme(){
    ...
}
fuckme();

每次都框选上面的全部运行即可,

另外有些人因为要写长的,所以他是用某些编辑器比如editplus/jedit/notepad++等等,那他们可能会在外面修改过.mel文件之后保存,然后到Maya里source fuckme.mel,然后运行fuckme(); 当然这两步可以合成一步,放到shelf上,所以最后就变成 在外面改改,然后到Maya里点下shelf按钮,看看那里不对,需要再去外面改的….如此往复.(ps:这里忽略了从外部编辑器直接发送命令到Maya的情形,另行讨论)

如何保证始终只有一个window

但是你会发现个问题,如果你运行两次fuckme,你会发现出来两个window,越运行越多

mel_window_basic2

这是因为你每次运行fuckme,他都会新建一个window,因为你没告诉他要把之前已经有的删掉(一般你写一个工具都是希望当用的人再点一次shelf button的时候,始终只有一个窗口的吧),所以你得给新建的窗口一个名字先

global proc fuckme(){
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
    showWindow;
}

像上面这样写之后,你会发现

mel_window_fuckme

第一次运行显然没问题,但是第二次运行会有错误提示

fuckme();
fuckme();
// Error: line 2: Object's name 'fuckMeWnd' is not unique. //

这是因为window不能有重名的
正确写法是

global proc fuckme(){
    // 如果已经有一个叫做fuckMeWnd的window了,就先把他删了
    if (`window -ex fuckMeWnd`)
        deleteUI fuckMeWnd;
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
    showWindow;
}

这样就能始终保持只有一个window了

如何添加按钮和layout

global proc fuckme(){
    if (`window -ex fuckMeWnd`)
        deleteUI fuckMeWnd;
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
    columnLayout;
        button -l "Make Cube" -c "polyCube";
        button -l "Make Sphere" -c "polySphere";
    showWindow;
}

mel_window_button

ui的基本层级是 window -> layout -> controls … 一般你写一个工具只有一个窗口,所以window只出现一次,window里面可以有layout,常用的layout有 rowLayout / columnLayout / formLayout, layout就是决定你的按钮等controls要怎么放置,横向排列,纵向排列 等等, controls就是各种按钮 滑动条 输入框等等.

mel_layout

以菜单 Skin -> Bind Skin -> Smooth Bind 为例

layout_ui

由上图可见,最外层的 columnLayout 里面有两个内层layout, 分别是上部的frameLayout , 和下部的rowLayout (三个按钮一字排开), 而上部的framelayout里又套了一个columnLayout, 所以里面的绿色的controls们是竖着排列的.

综上,layout可以嵌套.

layout使用方法举例

global proc fuckme(){
    if (`window -ex fuckMeWnd`)
        deleteUI fuckMeWnd;
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
    columnLayout;
        rowLayout -nc 2;
        textScrollList;
            columnLayout;
                button -l "Make Cube" -c "polyCube";
                button -l "Make Sphere" -c "polySphere";
                button -l "Load Selected";
                button -l "Clear";

                setParent ..;
            setParent ..;
        button "Delete Selected Items" ;

    showWindow;
}

fuckme_1

如上图所示,我使用了嵌套的layout,但是这里有几个问题,窗口放大缩小的时候左侧的textScrollList不会跟着缩放,按钮长短不一,很不好看.
这里有几种解决办法:

  1. 继续用rowLayout,加上-adj 参数让指定的column自动适应宽度
  2. 干脆直接全部用formLayout算了(这种layout比较自由)

方法1:

global proc fuckme(){
    if (`window -ex fuckMeWnd`)
        deleteUI fuckMeWnd;
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
    columnLayout -cat "both" 2 -adj 1;
        rowLayout -nc 2 -adj 1;
        textScrollList;
            columnLayout -cat "both" 2 -rs 10;
                button -l "Make Cube" -c "polyCube";
                button -l "Make Sphere" -c "polySphere";
                button -l "Load Selected";
                button -l "Clear";

                setParent ..;
            setParent ..;
        button -l "Delete Selected Items" ;

    showWindow;
}

fuckme_2

现在横向宽度会随窗口大小变化了,但是高度还是不会随窗口尺寸变化,我暂时没想到有什么方法一步就可以做到高度变化时,textScrollList的高度也跟着变,你只能希望用户不要把窗口拉太大了。

方法2: 使用formLayout,这个你可以随便想把controls怎么放都行,而且会随窗口大小变化自动变化,但是会长一点

global proc fuckme(){
    if (`window -ex fuckMeWnd`)
        deleteUI fuckMeWnd;
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
        formLayout;
            textScrollList;
            button -l "Make Cube" -c "polyCube";
            button -l "Make Sphere" -c "polySphere";
            button -l "Load Selected";
            button -l "Clear";
            button -l "Delete Selected Items";
    showWindow;
}

如果你直接来一个formLayout ,结果会是这样
fuckme_3
ui都是摞在一起的,因为你还没有告诉他们要怎么放,只是把他们加到了formLayout里而已。

此时会遇到了ui如何起名的问题,参见#15 应该如何命名界面控件( UI controls)? 用自己起的名字还是 Maya 自动赋予的名字,哪种方法好? 也就是说,你可以像下面这样,每个control都给起一个绝对的名字,但是这样没必要而且如果下次你再写个别的ui,难保会重名,除非你名字起得特别长,比如起成fuckme_makeCubeBtn,何况有些controls之后不会被别的proc访问到,所以不需要起这么多.

global proc fuckme(){
    if (`window -ex fuckMeWnd`)
        deleteUI fuckMeWnd;
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
        formLayout mainForm;
            textScrollList itemScrollList;
            button -l "Make Cube" -c "polyCube" makeCubeBtn;
            button -l "Make Sphere" -c "polySphere" makeSphereBtn;
            button -l "Load Selected" loadSelectedBtn;
            button -l "Clear" clearBtn;
            button -l "Delete Selected Items" delSelectedBtn;
    showWindow;
}

所以推荐的方法是下面这样

global proc fuckme(){
    if (`window -ex fuckMeWnd`)
        deleteUI fuckMeWnd;
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
        string $form=`formLayout`;
            string $list=`textScrollList`;
            string $makeCubeBtn = `button -l "Make Cube" -c "polyCube"`;
            string $makeSphereBtn=`button -l "Make Sphere" -c "polySphere"`;
            string $loadSelectedBtn=`button -l "Load Selected"`;
            string $clearBtn=`button -l "Clear"`;
            string $delSelectedBtn=`button -l "Delete Selected Items"`;
            
        formLayout -e
            // 让 list 吸附到form的顶部/左边/右边
            -af $list "left" 0
            -af $list "top" 0
            -ap $list "right" 0 75
        
            // 让 makeCubeBtn的左边 吸附到 list
            -ac $makeCubeBtn "left" 2 $list
            -af $makeCubeBtn "right" 2
            -ap $makeCubeBtn "top" 0 20
            
            // 让 makeSphereBtn的左边 吸附到 list,顶部吸附到makeCubeBtn
            -ac $makeSphereBtn "left" 2 $list
            -ac $makeSphereBtn "top" 10 $makeCubeBtn
            -af $makeSphereBtn "right" 2
            
            // 让 loadSelectedBtn的左边 吸附到 list,顶部吸附到makeSphereBtn
            -ac $loadSelectedBtn "left" 2 $list
            -ac $loadSelectedBtn "top" 10 $makeSphereBtn
            -af $loadSelectedBtn "right" 2
           
            // 让 clearBtn的左边 吸附到 list,顶部吸附到loadSelectedBtn
            -ac $clearBtn "left" 2 $list
            -ac $clearBtn "top" 10 $loadSelectedBtn
            -af $clearBtn "right" 2
 
            // delSelectedBtn 的左右侧和底部都吸附到form
            -af $delSelectedBtn "left" 2
            -af $delSelectedBtn "right" 2
            -af $delSelectedBtn "bottom" 2
            
            // list的底边吸附到 delSelectedBtn
            -ac $list "bottom" 2 $delSelectedBtn
                                                           
            $form;
            
    showWindow;
}

这样虽然长了不少,但是很多地方是复制粘贴的,而且textScrollList可以随着窗口大小自动变化大小了
fuckme_4

如何给按钮们连上命令

Make Cube 和 Make Sphere 按钮的命令很简单,就一句,所以没有出现在单独的proc里了,而另外几个按钮我想把他们放在单独的proc里,这些单独的proc必须是global proc. (这是mel做ui的要求,如果你想按下按钮调用某个proc,那这个proc必须是global proc)

global proc fm_delSelected(string $list){
    string $sel[]=`textScrollList -q -si $list`;
    for($s in $sel){
	    textScrollList -e -ri $s $list;
	    delete $s;
	}
}

global proc fm_loadSelected(string $list){
    string $sel[]=`ls -sl`;
    for($s in $sel){
	    textScrollList -e -a $s $list;    
	}
}

global proc fuckme(){
    if (`window -ex fuckMeWnd`)
        deleteUI fuckMeWnd;
    window -t "This is a fuckme tool ver 0.1 " fuckMeWnd;
        string $form=`formLayout`;
            string $list=`textScrollList`;
            string $makeCubeBtn = `button -l "Make Cube" -c "polyCube"`;
            string $makeSphereBtn=`button -l "Make Sphere" -c "polySphere"`;
            string $loadSelectedBtn=`button -l "Load Selected" -c ("fm_loadSelected(\""+$list+"\")")`;
            string $clearBtn=`button -l "Clear" -c ("textScrollList -e -ra "+$list)`;
            string $delSelectedBtn=`button -l "Delete Selected Items" -c ("fm_delSelected(\""+$list+"\")")`;
            
        formLayout -e
            -af $list "left" 0
            -af $list "top" 0
            -ap $list "right" 0 75
        
            -ac $makeCubeBtn "left" 2 $list
            -af $makeCubeBtn "right" 2
            -ap $makeCubeBtn "top" 0 20
            
            -ac $makeSphereBtn "left" 2 $list
            -ac $makeSphereBtn "top" 10 $makeCubeBtn
            -af $makeSphereBtn "right" 2
            
            -ac $loadSelectedBtn "left" 2 $list
            -ac $loadSelectedBtn "top" 10 $makeSphereBtn
            -af $loadSelectedBtn "right" 2
           
            -ac $clearBtn "left" 2 $list
            -ac $clearBtn "top" 10 $loadSelectedBtn
            -af $clearBtn "right" 2
 
            -af $delSelectedBtn "left" 2
            -af $delSelectedBtn "right" 2
            -af $delSelectedBtn "bottom" 2
            
            -ac $list "bottom" 2 $delSelectedBtn
                                                           
            $form;
            
    showWindow;
}

上面的例子里,所有的controls都没有自己起名,但是你需要知道的是,在这种情况下,你需要在另一个proc里比如fm_loadSelected访问ui上的某个control,在这里是左侧的textScrollList, 就算你给他起个绝对的名字也是不过分的,这里我把他的名字传给了fm_loadSelected proc,所以我用不着自己给textScrollList起名字,总之这时起不起名字可以自行随喜好决定

最终效果:
fuckme_5

以上就是个简单的完整例子了,其他滑动条等controls使用方法类似。先创建window,然后里面放一个或多个layout, layout里面放各种controls,逐渐调整直至达到各种controls都位于想要的位置.

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 博主赞过: