Python 错误(QThread 未定义) [英] Python error (QThread is undefined)

查看:119
本文介绍了Python 错误(QThread 未定义)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这段代码是关于渲染后的.我已经安装了 pyqt5 和 python 3.4我不是 Python 编码专家

This code is about after effects render. I have installed pyqt5 and python 3.4 I am no expert at python coding

"""
By:
---
Jared Glass
www.linkedin.com/in/JaredMushuGlass

Description:
------------
Render Queue/Batch Render tool for After Effects. 
Automatically searches for latest versions of After Effects Projects 
in a specified folder and adds to the queue. You can then choose to 
remove or add other After Effects Projects. The tool will render 
everything in each After Effects Project’s Render Queue using multiple 
processors if available.

Requirements:
------------
This tool has been created and tested on windows but should work on Mac and Linux too.
It requires Python and PyQt be installed.
I’m using Python 2.6 and PyQt 4.9.6. 

Demo Video: http://www.youtube.com/watch?v=3ktHj_PDI0M
After Effects Blog: www.codingForAfterEffects.wordpress.com

Logic:
------
1. Prompt user for root folder in which to search for all ".aep" files.
2. Get the latest versions (by highest version number) of all ".aep" files found in
    the user specified root and all child directories.
3. Allow user to add or remove files from the queue.
4. Render the files in the queue in order when the render button is clicked.
    4.1 Find the "aerender" executable.
    4.2 Start a thread to render the aep files.
"""


from PyQt5 import QtCore, QtGui
import sip
import sys, os, subprocess



################### 
#### Functions ####
###################
def aerender_path():
    '''Find the aerender executable''' 
    aerenderPath = None
    for programFolder in program_folders():
        for root, dirs, files in os.walk(programFolder):
            # check if "after" and "effects" are in folder path
            if not "after" in root.lower() or not "effects" in root.lower():
                continue
            for file in files:
                fileName, fileExt   = os.path.splitext(file)
                if fileName == "aerender":
                    aerenderPath = os.path.join(root, file)
                    break
        if aerenderPath != None:
            break
    return aerenderPath


def program_folders():
    '''Program folder(s) for this platform'''
    folders = []
    if sys.platform == "darwin":
        folders = ["/Applications"]
    elif sys.platform == "win32":
        folders = [r"C:\Program Files", r"C:\Program Files (x86)"]
    elif sys.platform == "linux2":
        folders = ["/Applications", "/usr"]
    return folders


def open_folder(path):
    '''open folder for each platform'''
    if sys.platform == 'darwin':
        subprocess.Popen(['open', '--', path])
    elif sys.platform == 'linux2':
        subprocess.Popen(['gnome-open', '--', path])
    elif sys.platform == 'win32':
        subprocess.Popen(['explorer', path])


def get_aep_files(searchFolder):
    '''Find all latest .aep files in the "searchFolder"'''
    aepDict = {}
    for root, dirs, files in os.walk(searchFolder):
        for file in files:
            fileName, fileExt   = os.path.splitext(file)
            if fileExt != ".aep":
                continue

            # Reverse string to get rid of version numbers
            fileName    = os.path.splitext(file)[0]
            reversed    = fileName[::-1]
            splitIndex  = False
            for index in range(len(reversed)):
                char    = reversed[index]
                try:
                    int(char)
                except ValueError:
                    splitIndex = index
                    break

            version = 0
            name    = fileName
            if splitIndex:
                name        = reversed[splitIndex:][::-1]
                version     = int(reversed[:splitIndex][::-1])
                # remove whitespace from end of name
                name        = name.rstrip()

            # If an aep file with the same name is already stored, check for the latest version
            if name in aepDict.keys():
                aepData     = aepDict[name]
                aepPath     = aepData[0]
                aepVersion  = aepData[1]
                if aepVersion > version:
                    continue

            path            = os.path.join(root, file)
            aepDict[name]   = [path, version]   
    aepFiles = [ aepDict[key][0] for key in aepDict.keys() ]
    aepFiles.sort()
    return aepFiles 



#################   
#### Classes ####   
#################
class RenderThread(QThread):
    '''Thread to handle the aerender executable so the main GUI
    stays responsive while render processing takes place'''
    def __init__(self, parent, aerenderPath, aepList):
        QThread.__init__(self, parent)

        self.aerenderPath   = aerenderPath
        self.aepList        = aepList

    def run(self):  
        while len(self.aepList) > 0:
            aepPath = self.aepList.pop(0)
            self.emit(SIGNAL("STARTED"), aepPath)
            procStr = '"' + self.aerenderPath + '"'
            procStr += ' -project "' + aepPath + '"'
            procStr += ' -mp '
            procStr += ' -close DO_NOT_SAVE_CHANGES'
            proc = subprocess.Popen(procStr)
            proc.wait()
            self.emit(SIGNAL("FINISHED"), aepPath)


class RenderDialog(QDialog):
    '''Main GUI'''
    def __init__(self):
        QDialog.__init__(self)

        # Widgets
        queueGroup      = QGroupBox("Queue")
        self.queueList  = QListWidget()
        removeBtn       = QPushButton("Remove")
        addBtn          = QPushButton("Add")
        self.renderBtn  = QPushButton("Render")
        self.proBar     = QProgressBar()
        doneGroup       = QGroupBox("Done")
        self.doneList   = QListWidget()

        # Layout
        layout = QGridLayout(queueGroup)
        layout.addWidget(self.queueList,    0, 0, 1, 2)
        layout.addWidget(removeBtn,         1, 0)
        layout.addWidget(addBtn,            1, 1)
        layout = QVBoxLayout(doneGroup)
        layout.addWidget(self.doneList)
        layout = QVBoxLayout(self)
        layout.addWidget(queueGroup)
        layout.addWidget(self.renderBtn)
        layout.addWidget(self.proBar)
        layout.addWidget(doneGroup)

        # Connections
        removeBtn.clicked.connect(self.remove_queue)
        addBtn.clicked.connect(self.add_queue)
        self.queueList.itemDoubleClicked[QListWidgetItem].connect(self.open_item_folder) 
        self.doneList.itemDoubleClicked[QListWidgetItem].connect(self.open_item_folder) 
        self.renderBtn.clicked.connect(self.render)

        # Settings
        self.setWindowTitle("AE Render Queue")
        self.queueList.setSelectionMode(QAbstractItemView.MultiSelection)
        self.doneList.setSelectionMode(QAbstractItemView.NoSelection)

        # Run
        searchFolder = str(QFileDialog.getExistingDirectory(self, "Select folder to search for all After Effects Projects in"))

        aepFiles = get_aep_files(searchFolder)
        self.queueList.addItems(aepFiles)
        self.proBar.hide()


    ## Defs ##
    def render(self):
        self.renderBtn.hide()
        self.proBar.show()
        self.proBar.setMaximum(self.queueList.count() + 1)
        self.proBar.setFormat("Locating aerender")
        self.proBar.setValue(0)

        aerenderPath = aerender_path()
        if aerenderPath == None:
            QMessageBox.critical(self, "ERROR", "Cannot locate the \"aerender\" file in the default install directory for your platform. \nPlease re-install After Effects to the default location or \nmodify this scripts \"program_folders\" function." )
            self.close()

        aepList = [ str(self.queueList.item(index).text()) for index in range(self.queueList.count()) ] 

        renderThread = RenderThread(self, aerenderPath, aepList)
        renderThread.start()

        self.connect(renderThread, SIGNAL("STARTED"), self.single_render_started)
        self.connect(renderThread, SIGNAL("FINISHED"), self.single_render_finished)

    def single_render_started(self, aepPath):
        '''Increment progress when a new render is started.'''
        self.proBar.setFormat(os.path.basename(aepPath))
        self.proBar.setValue(self.proBar.value() + 1)

    def single_render_finished(self, aepPath):
        '''Move the aep file path from the render queue to the done
        queue once completed.
        Also if there are no more items to render, reset the GUI'''
        item = self.queueList.takeItem(0)
        self.doneList.insertItem(0, item)
        if not self.queueList.count() > 0:
            self.renderBtn.show()
            self.proBar.hide()

    def remove_queue(self):
        '''Remove selected items from the queue''' 
        rows = []
        for item in self.queueList.selectedItems():
            rows.append(self.queueList.row(item))
        rows.sort(reverse=True)
        for row in rows:
            item = self.queueList.takeItem(row) 
            sip.delete(item)

    def add_queue(self):
        '''Add specified items to the queue'''
        files = QFileDialog.getOpenFileNames(self, "Select .aep files to add to the render queue", filter = "After Effects Projects (*.aep)")
        files.sort()
        self.queueList.addItems(files)

    def open_item_folder(self, item):
        '''Open the folder of the specified aep file'''
        folder = os.path.dirname(str(item.text()))
        open_folder(folder)



##############
#### Main ####
##############
if __name__ == "__main__":
    app = QApplication(sys.argv)
    renDlg= RenderDialog()
    renDlg.show()
    sys.exit(app.exec_())

运行时出现以下错误.这很令人沮丧.

I get the following error when i run it. It is very frustrating.

 Qt: Untested Windows version 10.0 detected!
Traceback (most recent call last):
  File "C:\Users\PrashSal\Downloads\AERenderQueue.py", line 149, in run
    self.emit(SIGNAL("STARTED"), aepPath)
AttributeError: 'RenderThread' object has no attribute 'emit'
TypeError: single_render_started() missing 1 required positional argument: 'aepPath'
TypeError: single_render_finished() missing 1 required positional argument: 'aepPath'

请用外行的语言回答,因为我不知道很多 python 术语.如果可能,请直接提供修改后的代码.

Please answer in layman's language as I don't know a lot of python terminology. If possible please provide the modified code directly.

谢谢和问候.我获得此代码的网站链接是 https://www.highend3d.com/downloads/applications/render-managers/c/after-effects-render-queue

Thanks and regards. The link to the website where I got this code is https://www.highend3d.com/downloads/applications/render-managers/c/after-effects-render-queue

推荐答案

导入类的问题,一个简单的解决方法就是在import的部分放置如下:

The problem of importing classes, a simple way to solve is to place the following in the part of imports:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

plus:另一个可能的错误是代码使用了旧的连接样式,如果有错误,请更改以下内容:

self.connect(renderThread, SIGNAL("STARTED"), self.single_render_started)
self.connect(renderThread, SIGNAL("FINISHED"), self.single_render_finished)

到:

renderThread.started.connect(self.single_render_started)
renderThread.finished.connect(self.single_render_finished)

完整代码:

"""
By:
---
Jared Glass
www.linkedin.com/in/JaredMushuGlass

Description:
------------
Render Queue/Batch Render tool for After Effects. 
Automatically searches for latest versions of After Effects Projects 
in a specified folder and adds to the queue. You can then choose to 
remove or add other After Effects Projects. The tool will render 
everything in each After Effects Project’s Render Queue using multiple 
processors if available.

Requirements:
------------
This tool has been created and tested on windows but should work on Mac and Linux too.
It requires Python and PyQt be installed.
I’m using Python 2.6 and PyQt 4.9.6. 

Demo Video: http://www.youtube.com/watch?v=3ktHj_PDI0M
After Effects Blog: www.codingForAfterEffects.wordpress.com

Logic:
------
1. Prompt user for root folder in which to search for all ".aep" files.
2. Get the latest versions (by highest version number) of all ".aep" files found in
    the user specified root and all child directories.
3. Allow user to add or remove files from the queue.
4. Render the files in the queue in order when the render button is clicked.
    4.1 Find the "aerender" executable.
    4.2 Start a thread to render the aep files.
"""


#from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sip
import sys, os, subprocess



################### 
#### Functions ####
###################
def aerender_path():
    '''Find the aerender executable''' 
    aerenderPath = None
    for programFolder in program_folders():
        for root, dirs, files in os.walk(programFolder):
            # check if "after" and "effects" are in folder path
            if not "after" in root.lower() or not "effects" in root.lower():
                continue
            for file in files:
                fileName, fileExt   = os.path.splitext(file)
                if fileName == "aerender":
                    aerenderPath = os.path.join(root, file)
                    break
        if aerenderPath != None:
            break
    return aerenderPath


def program_folders():
    '''Program folder(s) for this platform'''
    folders = []
    if sys.platform == "darwin":
        folders = ["/Applications"]
    elif sys.platform == "win32":
        folders = [r"C:\Program Files", r"C:\Program Files (x86)"]
    elif sys.platform == "linux2":
        folders = ["/Applications", "/usr"]
    return folders


def open_folder(path):
    '''open folder for each platform'''
    if sys.platform == 'darwin':
        subprocess.Popen(['open', '--', path])
    elif sys.platform == 'linux2':
        subprocess.Popen(['gnome-open', '--', path])
    elif sys.platform == 'win32':
        subprocess.Popen(['explorer', path])


def get_aep_files(searchFolder):
    '''Find all latest .aep files in the "searchFolder"'''
    aepDict = {}
    for root, dirs, files in os.walk(searchFolder):
        for file in files:
            fileName, fileExt   = os.path.splitext(file)
            if fileExt != ".aep":
                continue

            # Reverse string to get rid of version numbers
            fileName    = os.path.splitext(file)[0]
            reversed    = fileName[::-1]
            splitIndex  = False
            for index in range(len(reversed)):
                char    = reversed[index]
                try:
                    int(char)
                except ValueError:
                    splitIndex = index
                    break

            version = 0
            name    = fileName
            if splitIndex:
                name        = reversed[splitIndex:][::-1]
                version     = int(reversed[:splitIndex][::-1])
                # remove whitespace from end of name
                name        = name.rstrip()

            # If an aep file with the same name is already stored, check for the latest version
            if name in aepDict.keys():
                aepData     = aepDict[name]
                aepPath     = aepData[0]
                aepVersion  = aepData[1]
                if aepVersion > version:
                    continue

            path            = os.path.join(root, file)
            aepDict[name]   = [path, version]   
    aepFiles = [ aepDict[key][0] for key in aepDict.keys() ]
    aepFiles.sort()
    return aepFiles 



#################   
#### Classes ####   
#################
class RenderThread(QThread):
    '''Thread to handle the aerender executable so the main GUI
    stays responsive while render processing takes place'''
    def __init__(self, parent, aerenderPath, aepList):
        QThread.__init__(self, parent)

        self.aerenderPath   = aerenderPath
        self.aepList        = aepList

    def run(self):  
        while len(self.aepList) > 0:
            aepPath = self.aepList.pop(0)
            self.emit(SIGNAL("STARTED"), aepPath)
            procStr = '"' + self.aerenderPath + '"'
            procStr += ' -project "' + aepPath + '"'
            procStr += ' -mp '
            procStr += ' -close DO_NOT_SAVE_CHANGES'
            proc = subprocess.Popen(procStr)
            proc.wait()
            self.emit(SIGNAL("FINISHED"), aepPath)


class RenderDialog(QDialog):
    '''Main GUI'''
    def __init__(self):
        QDialog.__init__(self)

        # Widgets
        queueGroup      = QGroupBox("Queue")
        self.queueList  = QListWidget()
        removeBtn       = QPushButton("Remove")
        addBtn          = QPushButton("Add")
        self.renderBtn  = QPushButton("Render")
        self.proBar     = QProgressBar()
        doneGroup       = QGroupBox("Done")
        self.doneList   = QListWidget()

        # Layout
        layout = QGridLayout(queueGroup)
        layout.addWidget(self.queueList,    0, 0, 1, 2)
        layout.addWidget(removeBtn,         1, 0)
        layout.addWidget(addBtn,            1, 1)
        layout = QVBoxLayout(doneGroup)
        layout.addWidget(self.doneList)
        layout = QVBoxLayout(self)
        layout.addWidget(queueGroup)
        layout.addWidget(self.renderBtn)
        layout.addWidget(self.proBar)
        layout.addWidget(doneGroup)

        # Connections
        removeBtn.clicked.connect(self.remove_queue)
        addBtn.clicked.connect(self.add_queue)
        self.queueList.itemDoubleClicked[QListWidgetItem].connect(self.open_item_folder) 
        self.doneList.itemDoubleClicked[QListWidgetItem].connect(self.open_item_folder) 
        self.renderBtn.clicked.connect(self.render)

        # Settings
        self.setWindowTitle("AE Render Queue")
        self.queueList.setSelectionMode(QAbstractItemView.MultiSelection)
        self.doneList.setSelectionMode(QAbstractItemView.NoSelection)

        # Run
        searchFolder = str(QFileDialog.getExistingDirectory(self, "Select folder to search for all After Effects Projects in"))

        aepFiles = get_aep_files(searchFolder)
        self.queueList.addItems(aepFiles)
        self.proBar.hide()


    ## Defs ##
    def render(self):
        self.renderBtn.hide()
        self.proBar.show()
        self.proBar.setMaximum(self.queueList.count() + 1)
        self.proBar.setFormat("Locating aerender")
        self.proBar.setValue(0)

        aerenderPath = aerender_path()
        if aerenderPath == None:
            QMessageBox.critical(self, "ERROR", "Cannot locate the \"aerender\" file in the default install directory for your platform. \nPlease re-install After Effects to the default location or \nmodify this scripts \"program_folders\" function." )
            self.close()

        aepList = [ str(self.queueList.item(index).text()) for index in range(self.queueList.count()) ] 

        renderThread = RenderThread(self, aerenderPath, aepList)
        renderThread.start()

        renderThread.started.connect(self.single_render_started)
        renderThread.finished.connect(self.single_render_finished)

    def single_render_started(self, aepPath):
        '''Increment progress when a new render is started.'''
        self.proBar.setFormat(os.path.basename(aepPath))
        self.proBar.setValue(self.proBar.value() + 1)

    def single_render_finished(self, aepPath):
        '''Move the aep file path from the render queue to the done
        queue once completed.
        Also if there are no more items to render, reset the GUI'''
        item = self.queueList.takeItem(0)
        self.doneList.insertItem(0, item)
        if not self.queueList.count() > 0:
            self.renderBtn.show()
            self.proBar.hide()

    def remove_queue(self):
        '''Remove selected items from the queue''' 
        rows = []
        for item in self.queueList.selectedItems():
            rows.append(self.queueList.row(item))
        rows.sort(reverse=True)
        for row in rows:
            item = self.queueList.takeItem(row) 
            sip.delete(item)

    def add_queue(self):
        '''Add specified items to the queue'''
        files = QFileDialog.getOpenFileNames(self, "Select .aep files to add to the render queue", filter = "After Effects Projects (*.aep)")
        files.sort()
        self.queueList.addItems(files)

    def open_item_folder(self, item):
        '''Open the folder of the specified aep file'''
        folder = os.path.dirname(str(item.text()))
        open_folder(folder)



##############
#### Main ####
##############
if __name__ == "__main__":
    app = QApplication(sys.argv)
    renDlg= RenderDialog()
    renDlg.show()
    sys.exit(app.exec_())

这篇关于Python 错误(QThread 未定义)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆