3

Maya でユーザー インターフェースを作成しようとしていますが、複数レベルの親とインデントがないため、非常に混乱しています。基本的なコード (機能を含まない) は現在約 400 行あり、必要なビットを見つけるのに時間がかかります。

たとえば、次のコードをコメントなしで見てください。

#Earlier user interface

py.rowColumnLayout( numberOfColumns = 5 )
py.text( label="", width = 1 )
py.text( label="Column 1", enable = False, width = 250 )
py.text( label="", width = 1 )
py.text( label="Column 2" enable = False, width = 250 )
py.text( label="", width = 1 )

py.text( label="" )
py.rowColumnLayout( numberOfColumns = 4 )
py.text( label="   Input data:", align="left" )
py.text( label="" )
py.text( label="" )
py.text( label="" )
py.textField( text = "Text here" )
py.text( label="" )
py.text( label="" )
py.text( label="" )
py.setParent( ".." )

py.text( label="" )
py.rowColumnLayout( numberOfColumns = 4 )
py.rowColumnLayout( numberOfColumns = 5 )
py.radioButton( label = "Read file from path", width = 100 )
py.text( label="" )
py.button( label = "Browse" )
py.text( label="" )
py.button( label = "Validate" )
py.setParent( ".." )
py.text( label="" )
py.text( label="" )
py.text( label="" )
py.setParent( ".." )
py.setParent( ".." )

ただし、これはインデントでどのように見えるかです

py.rowColumnLayout( numberOfColumns = 5 )
    py.text( label="", width = 1 )
    py.text( label="Column 1", enable = False, width = 250 )
    py.text( label="", width = 1 )
    py.text( label="Column 2" enable = False, width = 250 )
    py.text( label="", width = 1 )

    py.text( label="" )
    py.rowColumnLayout( numberOfColumns = 4 )
        py.text( label="   Input data:", align="left" )
        py.text( label="" )
        py.text( label="" )
        py.text( label="" )
        py.textField( text = "Text here" )
        py.text( label="" )
        py.text( label="" )
        py.text( label="" )
        py.setParent( ".." )

    py.text( label="" )
    py.rowColumnLayout( numberOfColumns = 4 )
        py.rowColumnLayout( numberOfColumns = 5 )
            py.radioButton( label = "Read file from path", width = 100 )
            py.text( label="" )
            py.button( label = "Browse" )
            py.text( label="" )
            py.button( label = "Validate" )
            py.setParent( ".." )
        py.text( label="" )
        py.text( label="" )
        py.text( label="" )
        py.setParent( ".." )
    py.setParent( ".." )

インデントを使用して記述できる方法はありますが、実行時にそれらをすべて無視することはできますか? インデントなしでpythonを書くことができるかどうかを尋ねる質問を見ましたが、私はその逆を必要としています。

注: 一部のpy.*関数の出力値も変数に割り当てる必要がありますが、最初にレイアウトを並べ替える必要があるため、まだ行っていません。

4

7 に答える 7

7

これは、私たちのようなテクニカル アーティストが Maya で UI を構築する際に毎日直面する優れたユース ケースです。

PyMEL ベースの UI の場合:

これは PyMEL に組み込まれています。コンテキスト マネージャーを作成する必要はありません。レイアウト コマンド自体はコンテキスト マネージャーです。with次のように、すべてのレイアウト コマンド呼び出しの前にキーワードを追加するだけです。

# Do this when using PyMEL for your UI code
import pymel.core as pm

# ...

with pm.rowColumnLayout( numberOfColumns = 5 ):
    pm.text( label="", width = 1 )
    pm.text( label="Column 1", enable = False, width = 250 )
    pm.text( label="", width = 1 )
    pm.text( label="Column 2", enable = False, width = 250 )
    pm.text( label="", width = 1 )

    pm.text( label="" )

    with pm.rowColumnLayout( numberOfColumns = 4 ):
        pm.text( label="   Input data:", align="left" )
        pm.text( label="" )
        pm.text( label="" )
        pm.text( label="" )
        pm.textField( text = "Text here" )
        pm.text( label="" )
        pm.text( label="" )
        pm.text( label="" )        

    pm.text( label="" )
    with pm.rowColumnLayout( numberOfColumns = 4 ):
        with pm.rowColumnLayout( numberOfColumns = 5 ):
            pm.radioButton( label = "Read file from path", width = 100 )
            pm.text( label="" )
            pm.button( label = "Browse" )
            pm.text( label="" )
            pm.button( label = "Validate" )

        pm.text( label="" )
        pm.text( label="" )
        pm.text( label="" )

maya.cmds ベースの UI の場合:

簡単な解決策の 1 つは、ダミーのコンテキスト マネージャーを作成することです。あなたはこのようなことをすることができます

# Do this when using Maya's cmds for your UI code
import maya.cmds as cmds

# ...

from contextlib import contextmanager
@contextmanager
def neat_indent():
    # OPTIONAL: This is also an opportunity to do something before the block of code runs!
    try:
        # During this is where your indented block will execute
        # Leave it empty
        yield
    finally:
        # OPTIONAL: This is where you can write code that executes AFTER your indented block executes.
        pass

これにより、コードをあまり変更する必要がなくなります。with意図するすべてのインデントの先頭に、キーワードを使用してコンテキスト マネージャー関数を追加するだけです。

cmds.rowColumnLayout( numberOfColumns = 5 )
with neat_indent():
    cmds.text( label="", width = 1 )
    cmds.text( label="Column 1", enable = False, width = 250 )
    cmds.text( label="", width = 1 )
    cmds.text( label="Column 2", enable = False, width = 250 )
    cmds.text( label="", width = 1 )

    cmds.text( label="" )

    cmds.rowColumnLayout( numberOfColumns = 4 )
    with neat_indent():
        cmds.text( label="   Input data:", align="left" )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.textField( text = "Text here" )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.setParent( ".." )

    cmds.text( label="" )
    cmds.rowColumnLayout( numberOfColumns = 4 )
    with neat_indent():
        cmds.rowColumnLayout( numberOfColumns = 5 )
        with neat_indent():
            cmds.radioButton( label = "Read file from path", width = 100 )
            cmds.text( label="" )
            cmds.button( label = "Browse" )
            cmds.text( label="" )
            cmds.button( label = "Validate" )
            cmds.setParent( ".." )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.setParent( ".." )
    cmds.setParent( ".." )

私たちが作成したコンテキスト マネージャーはneat_indent()、インデント ブロックをラップするコードを記述する機会も提供します。ここでの実用的な例は、すべてのインデントの最後に自分が書いていることに気付くことpy.setParent("..")です。finallyこれをコンテキストマネージャのセクションに投げ込むだけです:

from contextlib import contextmanager
@contextmanager
def neat_indent(parent=None):
    # OPTIONAL: This is also an opportunity to do something before the block of code runs!
    try:
        # During this is where your indented block will execute
        # Leave it empty
        yield
    finally:
        # OPTIONAL: This is where you can write code that executes AFTER your indented block executes.
        if parent:
            cmds.setParent(parent)

あなたのコードはより理にかなっています:

cmds.rowColumnLayout( numberOfColumns = 5 )
with neat_indent(".."):
    cmds.text( label="", width = 1 )
    cmds.text( label="Column 1", enable = False, width = 250 )
    cmds.text( label="", width = 1 )
    cmds.text( label="Column 2", enable = False, width = 250 )
    cmds.text( label="", width = 1 )

    cmds.text( label="" )

    cmds.rowColumnLayout( numberOfColumns = 4 )
    with neat_indent(".."):
        cmds.text( label="   Input data:", align="left" )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.textField( text = "Text here" )
        cmds.text( label="" )
        cmds.text( label="" )
        cmds.text( label="" )        

    cmds.text( label="" )
    cmds.rowColumnLayout( numberOfColumns = 4 )
    with neat_indent(".."):
        cmds.rowColumnLayout( numberOfColumns = 5 )
        with neat_indent(".."):
            cmds.radioButton( label = "Read file from path", width = 100 )
            cmds.text( label="" )
            cmds.button( label = "Browse" )
            cmds.text( label="" )
            cmds.button( label = "Validate" )

        cmds.text( label="" )
        cmds.text( label="" )
        cmds.text( label="" )

コンテキスト マネージャーは強力です。この投稿では、標準ライブラリ モジュールのcontextmanager デコレータを使用しました。contextlibこのテクニックについては、こちらで読むことができます。with大体についてはこちら

また、Maya での UI 開発をよりクリーンでより Pythonic にするというまさにこの目的 (目的の 1 つ) のために、 @theodox はmGuiモジュールを作成しました。見てみな。

于 2015-01-19T21:56:00.917 に答える
1

@Kartikの答えは、ベースをうまくカバーしています。コンテキスト マネージャーがレイアウト (rowLayout、columnLayout など) をインラインで宣言できるようにすることで、レイアウト コードをもう少しクリーンアップできることを指摘しておきます。これにより、さらに簡単になります。

class uiCtx(object):
   '''
   quickie layouthelper: automatically setParents after a layout is finished
   '''
   def __init__(self, uiClass, *args, **kwargs):
        self.Control = uiClass(*args, **kwargs)

    def __enter__(self):
        return self

    def __exit__(self, tb, val, traceback):
        cmds.setParent("..")

    def __repr__(self):
        return self.Control

は、検出されたときに maya.cmds レイアウト関数を呼び出し、インデントされたブロックの最後で親を閉じるので、このスニペットのようにレイアウト呼び出しを実行できます。

    with uiCtx(cmds.rowLayout, **layout_options) as widget:
        self.Toggle = cmds.checkBox('', v = self.Module.enabled, cc = self._state_changed)
        with uiCtx(cmds.columnLayout, w=self.COLUMNS[1], cal='left') as details:
            cmds.text(l = self.ModuleKey, fn = "boldLabelFont")
            cmds.text(l = self.Module.path, fn = "smallObliqueLabelFont")
        cmds.button("edit",  c=self._edit)
        cmds.button("show", c=self._show)
    return widget

に を追加する__repr__と、uiCtx通常の Maya レイアウト コマンドと同じように文字列を返すかのように扱うことができるため、この例では、通常の方法で「widget」を照会できます。

全体はGitHubにアップされており、コンテキストで確認できます。Kartik も指摘したように、mGuiの形式でより精巧な宣言型 UI オプションがあり、実際には次のようになります。

with gui.Window('window', title = 'fred') as example_window:
    with BindingContext() as bind_ctx:
        with VerticalForm('main') as main:
            Text(None, label = "The following items don't have vertex colors")
            lists.VerticalList('lister' ).Collection < bind() < bound  
            with HorizontalStretchForm('buttons'):
                Button('refresh', l='Refresh')
                Button('close', l='Close')

# show the window
example_window.show()

ここにいくつかのマヤレイアウト関連情報があります

于 2015-01-20T20:28:31.313 に答える
0

宣言型アプローチを使用します。

interface = [
  [py.rowColumnLayout, [], dict(numberOfColumns=5)],
     [py.text, [], dict(label="", width=1)],
     [py.text, [], dict(label="Column 1", enable=False, width=250)],
     ...
     [py.setParent, [".."], {}],
]    

for callable, args, kwargs in interface:
    callable(*args, **kwargs)

内側()[]へこみは関係ありませんので、自由に線を整理してください。

于 2015-01-19T20:33:33.290 に答える
0

を解析して実行する別のプログラムを作成しますscript.py

parse.py

text = open('script.py').readlines()
text = [i.strip() for i in text]

edit = open('new.py', 'w')
for line in text:
    edit.write(line + '\n')
edit.close()

execfile('new.py')

このファイルは、new.py実行される変更を作成します。

于 2015-01-19T18:41:01.897 に答える