Pyside小部件核弹没有跟上值

问题描述 投票:2回答:2

我想自定义Pyside小部件添加到核弹节点。核弹可以通过这个包装PyCustom_Knob。

我可以创建窗口小部件,并显示它,但它不会让自己的价值观。每次我关闭面板并重新打开,它重置。我如何得到它来保持其设定值?什么我忘了?

我下面this教程。 (有相同的问题)

这里是我当前的代码:

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)

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

Nuke Docs:PySide的Widget在最底层

谢谢

python pyside nuke
2个回答
0
投票

虽然核弹旋钮是持久的,当面板或标签它们连接到不内核弹打开不存在由PyCustom_Knob创建PySide部件。这意味着PySide部件不能与它们所连接到的节点/面板之前,或之后,该节点/面板已被关闭进行交互。我修改了原来的例子来说明:

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”不是在属性编辑器中打开,你将得到以下的输出:

Before addKnob(): None
myPyKnob.__init__
After addKnob(): <__main__.myPyKnob object at 0x000000002DCC7588>
After addKnob(): None

对于我们的打开节点时,不构成的PySide对象,直到旋钮被安装到节点。对于未开封的节点,它是不是在所有创建。只要你打开属性面板“unopened_node”,不过,你会看到构造熄灭。

从属性面板关闭节点后,这会变得更加混乱。从属性面板关闭“opened_node”并运行此:

pyside_obj = nuke.toNode("opened_node").knob("MyWidget").getObject()
print(pyside_obj)
print(pyside_obj.value())

你应该得到类似这样的输出:

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

起初,一切都似乎是精细的旋钮像以前一样保持同一个对象的引用。但是,如果您尝试运行任何内部方法,你会发现内部对象已被删除!如果你继续在属性面板关闭并重新打开的节点上,你会看到构造函数创建一个新的实例每次。这显然是一个巨大的问题,因为不仅不值没有得到保存,但如果节点是不开放没有别的核弹可以检索这些值。

该解决方案,这tk421storm已经指出的那样,是将值存储在节点上的另一个隐藏把手,因为把手会持续。这是在你的例子很简单,作为一个int_knob对应相当好了QSpinBox,但可以变得更加复杂,如果您的自定义窗口小部件具有更多的功能。当我遇到这个问题,我PySide部件是与多个下拉菜单,复选框和动态分级列表用户可能增长,或者根据自己的需求缩小整个面板。这是一个很大需要每个用户重新打开该节点时要将会传播价值。

我看中的解决方案是所有PySide控件的值存储在一个字典。每一个部件的更新逢回调调用一个_updateCache()方法(属于我的pyside部件类)编码值并将其存储在外部String_Knob。然后,构造函数接受本字典,以恢复以前的状态参数。

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对象进行沟通,他们只需要使用类似的方法对其进行解码,以访问缓存:

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

我希望这有帮助!


1
投票

我敢肯定,你必须拿出你自己的方法将数据存储在一个Py_custom旋钮 - 这听起来像核弹默认不这样做。

你可以做什么我经常这样做,并在脚本的根()上的隐藏旋钮您的数据存储。您的代码可能是这个样子:

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)

你可能得要高明洱在您选择唯一的名称,因为如果用户更改节点的名称创建此旋钮后,它将继续它的老名字来称呼自己。

© www.soinside.com 2019 - 2024. All rights reserved.