Как создать окно прогресса через Python в Maya?

Мне было интересно, есть ли способ создать окно прогресса, которое показывает, сколько времени до момента завершения вашей программы. Это то, что у меня есть до сих пор, но это не то, что я ожидал.

Я хочу, чтобы он работал, пока не будут созданы все кривые, а затем остановился.

import maya.cmds as cmds

cmds.setAttr( "nParticle1Shape.lifespanMode", 2 ) 
cmds.setAttr( "nParticle1Shape.maxCount", 5 ) 
cmds.setAttr( "nParticle1Shape.lifespanRandom", 3 )

allParticleDictionary = {}
minFrames = cmds.playbackOptions( q=True, min=True )
maxFrames = cmds.playbackOptions( q=True, max=True )

running = 0
amount = 0
cmds.progressWindow( title='Doing Nothing',progress=amount,status='Sleeping: 0%',isInterruptable=True )

for currentFrame in range(0, int(maxFrames)):
    cmds.currentTime( currentFrame, update=True, edit=True )
    cmds.select( 'nParticle1' )

    Particles = cmds.ls( sl=True, type='transform' )
    for part in Particles:
        for particleCount in range( 0,cmds.particle(part, q=True,ct=True) ):
            particleName = cmds.particle( part, q=True, order=particleCount, at='id' )
            particlesPosition = cmds.particle( part, q=True, order=particleCount, at='position' )
            particleDictionary = {}

            if str( particleName[0] ) in allParticleDictionary.keys():
                particleDictionary = allParticleDictionary[str(particleName[0])]

                particleDictionary[currentFrame] = particlesPosition
                allParticleDictionary[str(particleName[0])] = particleDictionary


    emptyFolder = cmds.group( em=True, n="Curves" )
    for curveParticleId in allParticleDictionary.keys():
        pointList = []
        sortedKeyFrameList = sorted( allParticleDictionary[curveParticleId].keys() )

        if len( sortedKeyFrameList ) > 1:
            for keyFrame in sortedKeyFrameList:
                pointList.append( allParticleDictionary[curveParticleId][keyFrame] )

                curveObj = cmds.curve( name = "pCurve" + str(curveParticleId ), p = pointList)
                Locators = cmds.spaceLocator( name = "locator" + str(curveParticleId) )
                cmds.pathAnimation( Locators, stu=sortedKeyFrameList[0], etu=sortedKeyFrameList[-1], c=curveObj )       

                running = 1
                # place all objects in Group called Curves 
                cmds.parent( curveObj, emptyFolder )
                cmds.select( Locators )
                cmds.delete()

            while running == 0:

                # Checks if the dialog has been cancelled
                if cmds.progressWindow( query=True, isCancelled=True ) :
                    break

                # Checks if end condition has been reached
                if cmds.progressWindow( query=True, progress=True ) >= 100 :
                    break

                amount += 20
                cmds.progressWindow( edit=True, progress=amount, status=('Sleeping: ' + `amount` + '%' ) )
                cmds.pause( seconds=1 )
                cmds.progressWindow( endProgress=1 )

person Kari Noriy    schedule 28.04.2017    source источник
comment
Что вы имеете в виду, пока не будут созданы все кривые? Какая часть вашего кода это?   -  person UKDP    schedule 28.04.2017
comment
Я хочу, чтобы он посмотрел, сколько времени осталось до завершения выполнения функции, и получил представление об использовании окна выполнения   -  person Kari Noriy    schedule 28.04.2017
comment
Я имею в виду, какая часть вашего кода должна обрабатываться в окне прогресса. Это только в петле for currentFrame in range(0, int(maxFrames))?   -  person UKDP    schedule 28.04.2017
comment
Извините, это для: для curveParticleId в allParticleDictionary.keys ():   -  person Kari Noriy    schedule 28.04.2017
comment
FWIW код, показанный здесь, не будет работать при вырезании и вставке, он выглядит как несогласованные отступы   -  person theodox    schedule 28.04.2017
comment
спасибо theodox, теперь он должен работать.   -  person Kari Noriy    schedule 28.04.2017


Ответы (1)


Предисловие состоит в том, что я не совсем уверен, что правильно понял вашу логику: как сказал @theodox, ваши отступы кажутся неправильными даже после вашего последнего исправления.

В любом случае, вот версия, которая должна делать то, к чему вы стремитесь, если я правильно ее истолковал:

from maya import cmds

def checkProgressEscape():
    # check if dialog has been cancelled
    cancelled = cmds.progressWindow(query=True, isCancelled=True)
    if cancelled:
        cmds.progressWindow(endProgress=1)
    return cancelled

def getAllParticlesDictionary(shape):
    cmds.progressWindow(title='Fetch Particle Data', progress=0, status='Fetched: 0%', isInterruptable=True)

    ptcsDict = {}
    minFrames = int(cmds.playbackOptions( q=True, min=True))
    maxFrames = int(cmds.playbackOptions( q=True, max=True))
    nFrames = float(maxFrames - minFrames)
    # better use the actual range, since you queried the playback options
    for currentFrame in range(minFrames, maxFrames):
        if checkProgressEscape():
            return
        amount = 100.0 / nFrames * (currentFrame - minFrames + 1)
        cmds.progressWindow(edit=True, progress=amount, status='Fetched: %d%%' % amount)
        # cmds.pause(seconds=.001)

        cmds.currentTime(currentFrame, update=True, edit=True)
        for particleCount in xrange(cmds.particle(shape, q=True, ct=True)):
            particleId = int(cmds.particle(shape, q=True, order=particleCount, at='id')[0])
            # better check the key exists first, then add your logic
            if particleId not in ptcsDict.keys():
                ptcsDict[particleId] = {}                    
            ptcsDict[particleId][currentFrame] = cmds.particle(shape, q=True, order=particleCount, at='position')

    cmds.progressWindow(endProgress=1)
    return ptcsDict

def curvesFromParticle(ptcsDict):
    cmds.progressWindow(title='Build Curves', progress=0, status='Building Curves: 0%', isInterruptable=True)
    # this section had to be de-indented
    emptyFolder = cmds.group(em=True, n="Curves")
    ptcCount = len(ptcsDict)
    for i, (curveParticleId, data) in enumerate(ptcsDict.iteritems()):
        if checkProgressEscape():
            return

        sortedKeyFrameList = sorted(data.keys())
        pointList = []
        for keyFrame in sortedKeyFrameList:
            pointList.append(ptcsDict[curveParticleId][keyFrame])

        curveObj = cmds.curve(name="pCurve%d" % curveParticleId, p=pointList)
        locators = cmds.spaceLocator( name = "locator%d" % curveParticleId)
        cmds.pathAnimation( locators, stu=sortedKeyFrameList[0], etu=sortedKeyFrameList[-1], c=curveObj)       
        # place all objects in Group called Curves 
        cmds.parent(curveObj, emptyFolder)
        cmds.delete(locators)

        amount = 100 / ptcCount * float(i)
        cmds.progressWindow(edit=True, progress=amount, status='Building Curves: %d%%' % amount)
    cmds.progressWindow(endProgress=1)


ptcs = cmds.ls(typ='nParticle')
for shape in ptcs:
    cmds.setAttr("%s.lifespanMode" % (shape, ), 2)
    cmds.setAttr("%s.maxCount" % (shape, ), 100)
    cmds.setAttr("%s.lifespanRandom" % (shape, ), 3)
    ptcDict = getAllParticlesDictionary(shape)
    if not ptcDict:
        print 'data was not be fetched for %s; skipped' % (shape, )
        continue
    curvesFromParticle(ptcDict)

Выше представлена ​​(слегка) измененная версия вашего скрипта; как вы видете:

  • Я перенес основные блоки логики в функции (просто для удобства чтения)
  • Я удалил ваши while операторы, так как они не требуются индикатором выполнения: вы уже зацикливаете for оператор
  • Я также удалил вашу проверку прогресса, если она равна или больше 100, потому что, как только вы выйдете из цикла, вы можете предположить, что вам больше не нужно показывать прогресс, и просто вызовите команду боковой панели с аргументом endProgress; вам все еще нужно проверить, избежал ли пользователь процесса, хотя
  • Я добавил два "сеанса" индикатора выполнения, один для цикла получения данных о частицах и заполнения вашего словаря, второй для построения кривых.

Кстати, вы можете узнать (если вы еще этого не сделали), что Maya в основном однопоточная. При использовании API вы можете обойти некоторые ограничения, но, как правило, при использовании cmds maya вы можете быть уверены, что работаете с одним потоком.

Это означает, что индикатор выполнения будет работать в том же потоке, в котором работает ваша логика, что ограничивает производительность вашего скрипта на несколько порядков: я проделал большую работу с частицами + индикаторами выполнения и обнаружил, что рисование пользовательского интерфейса может быть намного медленнее, чем просто выполнение вашей логики. По мере увеличения количества частиц ваш скрипт может стать ужасно медленным только из-за обновления индикатора выполнения, не из-за самой логики.

Хорошая практика - обновлять прогресс только через известные промежутки времени (читай: каждые n частиц). Допустим, у вас есть 1000000 частиц и вы хотите обновить боковую панель только с шагом 5%, вы бы написали что-то вроде этого:

import random

cmds.progressWindow(title='Stepped Progress Bar', progress=0, status='Progress (stepped by 1): 0%%', isInterruptable=True)
limit = 1000000
step = 5
for i in xrange(limit):
    progress = 100.0 / limit * i
    if progress % step:
        continue
    cmds.progressWindow(e=1, progress=progress, status='Progress (stepped by 1): %d%%' % progress)
    # the following is to simulate some processing time
    cmds.pause(seconds=random.random() * 2)
cmds.progressWindow(endProgress=1)
person mapofemergence    schedule 23.06.2017
comment
@Nathan, спасибо за ваши исправления: они очень ценятся и действительно полезны в качестве руководства для будущих ответов. - person mapofemergence; 23.06.2017