首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Nuke中的Pyside Widget不保留值

Nuke中的Pyside Widget不保留值
EN

Stack Overflow用户
提问于 2018-01-06 22:56:22
回答 2查看 1.2K关注 0票数 2

我正在尝试向Nuke中的Node添加一个自定义Pyside小部件。Nuke允许通过PyCustom_Knob包装器实现这一点。

我能够创建这个小部件并显示它,但是它不会保留它的值。每次我关闭面板并重新打开,它都会重置。我如何让它保持它的设定值?我忘了什么?

我正在遵循教程。(问题相同)

以下是我的当前代码:

代码语言:javascript
复制
from PySide import QtGui, QtCore

class myPyKnob(QtGui.QSpinBox):

    def __init__(self, node):
        super(self.__class__, self).__init__()

        #Set a default value to the spinbox
        self.setValue(1)

        self.myValue = 0
        self.valueChanged.connect(self.valueChangedKnob)

    #Needed by Nuke to add the widget
    def makeUI(self):
        return self

    def updateValue(self):
        pass

    def valueChangedKnob(self):
        self.myValue = self.value()
        print(self.myValue)
        print(self.value())

# This takes the selected node and adds the widget using PyCustom_Knob
if __name__ == '__main__':
    node = nuke.selectedNode()
    knob = nuke.PyCustom_Knob( "MyWidget", "", "myPyKnob(nuke.thisNode())" ) 
    node.addKnob(knob)

这里是一个演示这个问题的视频链接:

核武器博士:最底层的PySide Widget

谢谢你

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-02-10 21:05:54

虽然Nuke旋钮是持久化的,但是当附加到的面板或选项卡在Nuke中没有打开时,PyCustom_Knob创建的PyCustom_Knob小部件就不存在了。这意味着在连接到节点/面板之前,或者在该节点/面板关闭之后,不能与PySide小部件进行交互。我修改了您的原始示例,以演示:

代码语言:javascript
复制
from PySide import QtGui, QtCore

class myPyKnob(QtGui.QSpinBox):

    def __init__(self, node):
        super(self.__class__, self).__init__()
        ##########################
        print("myPyKnob.__init__")
        ##########################
        #Set a default value to the spinbox
        self.setValue(1)

        self.myValue = 0
        self.valueChanged.connect(self.valueChangedKnob)

    #Needed by Nuke to add the widget
    def makeUI(self):
        return self

    def updateValue(self):
        pass

    def valueChangedKnob(self):
        self.myValue = self.value()
        print(self.myValue)
        print(self.value())

# This takes the selected node and adds the widget using PyCustom_Knob
if __name__ == '__main__':
    # This node is open in the properties panel
    opened_node = nuke.toNode('opened_node')

    pyside_knob1 = nuke.PyCustom_Knob( "MyWidget", "", "myPyKnob(nuke.toNode('opened_node'))" )

    print("Before addKnob(): {}".format(pyside_knob1.getObject()))
    opened_node.addKnob(pyside_knob1)
    print("After addKnob(): {}".format(pyside_knob1.getObject()))

    # This node is not open in the properties panel
    unopened_node = nuke.toNode('unopened_node')
    pyside_knob2 = nuke.PyCustom_Knob( "MyWidget", "", "myPyKnob(nuke.toNode('unopened_node'))" ) 
    unopened_node.addKnob(pyside_knob2)
    print("After addKnob(): {}".format(pyside_knob2.getObject()))

如果您在属性编辑器中打开节点'opened_node‘而属性编辑器中没有打开'unopened_node’来运行此操作,您将得到以下输出:

代码语言:javascript
复制
Before addKnob(): None
myPyKnob.__init__
After addKnob(): <__main__.myPyKnob object at 0x000000002DCC7588>
After addKnob(): None

对于打开的节点,直到将旋钮连接到节点时,才会构造PySide对象。对于未打开的节点,根本不创建它。但是,一旦您在属性面板中打开'unopened_node‘,您就会看到构造函数消失了。

在关闭属性面板中的节点后,这就更加令人困惑了。关闭属性面板中的“opened_node”并运行以下命令:

代码语言:javascript
复制
pyside_obj = nuke.toNode("opened_node").knob("MyWidget").getObject()
print(pyside_obj)
print(pyside_obj.value())

您应该获得与以下类似的输出:

代码语言:javascript
复制
<__main__.myPyKnob object at 0x000000002DCC7588>
Traceback (most recent call last):
  File "<string>", line 3, in <module>
RuntimeError: Internal C++ object (myPyKnob) already deleted.

一开始,一切看起来都很好--旋钮与以前一样保持着对同一个对象的引用。但是,如果尝试运行任何内部方法,则会发现内部对象已被删除!如果继续关闭并重新打开“属性”面板中的节点,则每次都会看到构造函数创建一个新实例。这显然是一个很大的问题,因为不仅值没有保存,而且如果节点不打开,Nuke中的任何其他值都无法检索这些值。

tk421storm已经指出的解决方案是将值存储在节点上的另一个隐藏旋钮中,因为旋钮将持久化。在您的示例中,这是非常简单的,因为int_knob与QSpinBox相当匹配,但是如果您的自定义小部件有更多特性,则会变得更加复杂。当我遇到这个问题时,我的PySide小部件是一个完整的面板,带有多个下拉菜单、复选框和一个动态大小的列表,用户可以根据他们的需要增长或缩小。这是用户每次重新打开节点时都需要宣传的大量值。

我确定的解决方案是将PySide小部件的所有值存储在字典中。每个小部件更新的每个回调都调用一个_updateCache()方法(属于我的pyside小部件类),该方法对值进行编码,并将它们存储在外部String_Knob中。构造函数然后接受此字典作为参数来恢复其以前的状态。

代码语言:javascript
复制
def _updateCache(self):
    """
    Updates a knob on the node to contain all of the values for this node.
    Nuke will not store these values so we need to restore them ourselves after every
    script load
    """
    data = self._getInfo() # Gets all widget values in a dictionary
    b64encode_data = base64.b64encode(json.dumps(data)) # Encode it to be safe
    self.node.knob("pyside_cache").setValue(b64encode_data) # Store on an external String_Knob

由于每个小部件都会立即更新缓存,外部脚本不需要直接与PySide对象通信,它们只需使用类似的方法访问缓存即可:

代码语言:javascript
复制
def get_pyside_cache(self, node):
"""
Retrieve PySide Widget values
:return: dictionary of widget values, or None if failure
"""
    if node.knob("pyside_cache").value() != "":
        try:
            return json.loads(base64.b64decode(node.knob("pyside_cache").value()))
        except ValueError:
            print("ValueError: Could not load a json object from pyside_cache")

    return None

我希望这能帮到你!

票数 0
EN

Stack Overflow用户

发布于 2018-03-22 15:53:45

我非常肯定,您将不得不想出自己的方法来将数据存储在Py_custom旋钮上--听起来,nuke在默认情况下不会这样做。

您可以做我经常做的事情,并将数据存储在脚本的Root()的隐藏旋钮上。您的代码可能如下所示:

代码语言:javascript
复制
from PySide import QtGui, QtCore

class myPyKnob(QtGui.QSpinBox):

    def __init__(self, node):
        super(self.__class__, self).__init__()

        #each knob will need a custom name
        self.name=node.name()+"_pyCustomKnob"

        #we'll check for a stored result at the root and set it here
        #this should work when a script is loaded as well
        try:
             value=nuke.Root().toKnob(self.name).value()
        except:
             value=1
        self.setValue(value)

        self.valueChanged.connect(self.valueChangedKnob)

    #Needed by Nuke to add the widget
    def makeUI(self):
        return self

    def updateValue(self):
        pass

    def valueChangedKnob(self):
        myValue = self.value()
        #store the current result on the root
        try:
            nuke.Root().toKnob(self.name).setValue(myValue)
        except KeyError:
            #knob doesnt exist so we need to make it
            storageKnob=nuke.Int_Knob(self.name)
            nuke.Root().addKnob(storageKnob)
            storageKnob.setVisible(False)
            storageKnob.setValue(myValue)

# This takes the selected node and adds the widget using PyCustom_Knob
if __name__ == '__main__':
    node = nuke.selectedNode()
    knob = nuke.PyCustom_Knob( "MyWidget", "", "myPyKnob(nuke.thisNode())" ) 
    node.addKnob(knob)

在选择唯一名称时,您可能必须非常聪明,因为如果用户在创建这个旋钮之后更改了节点的名称,它将继续使用它的旧名称调用自己。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48132718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档