Difference between revisions of "IC Python API:Item Lister"

From Reallusion Wiki!
Jump to: navigation, search
m (Inserting Items)
m (Creating the UI)
Line 75: Line 75:
 
We'll need to load the configured QT UI file.  You can download '''Item_Lister.ui''' [[Media:Item_Lister.ui | here]] -make sure this UI file is placed in the same script directory.  We'll also need to connect the custom user controls with relevant methods mentioned above and register our event callbacks.
 
We'll need to load the configured QT UI file.  You can download '''Item_Lister.ui''' [[Media:Item_Lister.ui | here]] -make sure this UI file is placed in the same script directory.  We'll also need to connect the custom user controls with relevant methods mentioned above and register our event callbacks.
  
<syntaxhighlight lang"python">
+
<syntaxhighlight lang="python">
 
dialog_window = RLPy.RUi.CreateRDialog()
 
dialog_window = RLPy.RUi.CreateRDialog()
 
dialog_window.SetWindowTitle("Item Lister")
 
dialog_window.SetWindowTitle("Item Lister")
Line 90: Line 90:
 
widget.pushButton.clicked.connect(insert_items)
 
widget.pushButton.clicked.connect(insert_items)
  
# Create Event Callback
 
 
event_callback = EventCallback()
 
event_callback = EventCallback()
 
event_callback_id = RLPy.REventHandler.RegisterCallback(event_callback)
 
event_callback_id = RLPy.REventHandler.RegisterCallback(event_callback)
Line 96: Line 95:
 
dialog_window.Show()
 
dialog_window.Show()
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
== Everything Put Together ==
 +
 +
You can copy and paste the following code into a PY file and load it into iClone via '''Script > Load Python'''.
 +
 +
<syntaxhighlight lang="python">
 +
import RLPy
 +
import os
 +
from PySide2 import *
 +
from PySide2.shiboken2 import wrapInstance
 +
 +
recorded_objects = {}
 +
 +
 +
class EventCallback(RLPy.REventCallback):
 +
    def __init__(self):
 +
        RLPy.REventCallback.__init__(self)
 +
 +
    def OnObjectDeleted(self):
 +
        prune_list()
 +
 +
 +
class DialogEventCallback(RLPy.RDialogCallback):
 +
    def __init__(self):
 +
        RLPy.RDialogCallback.__init__(self)
 +
 +
    def OnDialogHide(self):
 +
        global event_callback_id
 +
        RLPy.REventHandler.UnregisterCallback(event_callback_id)
 +
        return True
 +
 +
 +
def prune_list():
 +
    widget.listWidget.clear()
 +
 +
    for name, item in list(recorded_objects.items()):
 +
        if item.IsValid():
 +
            widget.listWidget.insertItem(widget.listWidget.count(), name)
 +
        else:
 +
            del recorded_objects[name]
 +
 +
 +
def insert_items():
 +
    for item in RLPy.RScene.GetSelectedObjects():
 +
        recorded_objects[item.GetName()] = item
 +
 +
    prune_list()
 +
 +
 +
dialog_window = RLPy.RUi.CreateRDialog()
 +
dialog_window.SetWindowTitle("Item Lister")
 +
 +
dialog = wrapInstance(int(dialog_window.GetWindow()), QtWidgets.QDialog)
 +
dialog.setFixedWidth(250)
 +
 +
qt_ui_file = QtCore.QFile(os.path.dirname(__file__) + "/Item_Lister.ui")
 +
qt_ui_file.open(QtCore.QFile.ReadOnly)
 +
widget = QtUiTools.QUiLoader().load(qt_ui_file)
 +
qt_ui_file.close()
 +
dialog.layout().addWidget(widget)
 +
 +
widget.pushButton.clicked.connect(insert_items)
 +
 +
event_callback = EventCallback()
 +
event_callback_id = RLPy.REventHandler.RegisterCallback(event_callback)
 +
 +
dialog_window.Show()
 +
</syntaxhighlight>
 +
 +
== APIs Used ==
 +
 +
You can research the following references for the APIs deployed in this code.
 +
 +
<div style="column-count:4; -moz-column-count:4; -webkit-column-count:4">
 +
* [[ IC_Python_API:RLPy_REventCallback#__init__ | RLPy.REventCallback.__init__() ]]
 +
* [[ IC_Python_API:RLPy_RDialogCallback#__init__ | RLPy.RDialogCallback.__init__() ]]
 +
* [[ IC_Python_API:RLPy_REventHandler#UnregisterCallback | RLPy.REventHandler.UnregisterCallback() ]]
 +
* [[ IC_Python_API:RLPy_RScene#GetSelectedObjects | RLPy.RScene.GetSelectedObjects() ]]
 +
* [[ IC_Python_API:RLPy_RUi#CreateRDialog | RLPy.RUi.CreateRDialog() ]]
 +
* [[ IC_Python_API:RLPy_REventHandler#RegisterCallback | RLPy.REventHandler.RegisterCallback() ]]
 +
</div>

Revision as of 00:15, 24 September 2019

Main article: RL Python Samples.

There are two main lessons for this article: Capturing a state of the scene by recording user specified objects and pruning the list when the said objects become obsolete. We demonstrate these two priorities with a script that can record user specified objects in a list window.

Required Modules and Global Variables

Besides the fundamental Reallusion Python module, we'll also need Pyside2 and os to read the QT UI file and build the user interface. We'll also need a global variable to store the various designated objects in the scene.

import RLPy
import os
from PySide2 import *
from PySide2.shiboken2 import wrapInstance

recorded_objects = {}

Event Callbacks

We'll need a way to prune the recorded list by verifying it again when an object in the scene is deleted, performed by an REventCallback. However, we'll also need to clean up the said callback event when the window is closed, so we'll also need a RDialogCallback to rescind the aforementioned event callback.

class EventCallback(RLPy.REventCallback):
    def __init__(self):
        RLPy.REventCallback.__init__(self)

    def OnObjectDeleted(self):
        prune_list()


class DialogEventCallback(RLPy.RDialogCallback):
    def __init__(self):
        RLPy.RDialogCallback.__init__(self)

    def OnDialogHide(self):
        global event_callback_id
        RLPy.REventHandler.UnregisterCallback(event_callback_id)
        return True

Notice that we call the prune_list method in the event that an object is deleted from the scene.

Pruning the List

Let's create a function to prune the list represented by the recorded_objects dictionary. We test for the existence of an object with the RLPy.RIBase.IsValid() member function.

def prune_list_list():
    widget.listWidget.clear()

    for name, item in list(recorded_objects.items()):
        if item.IsValid():
            widget.listWidget.insertItem(widget.listWidget.count(), name)
        else:
            del recorded_objects[name]

Notice that when we iterate over the list, we actually iterate over a copy of it by casting it to another list() type. This is so we can safely delete from the list while changing its size.

Inserting Items

We'll also need a function for inserting items to the list and call the prune_list() function to validate the listed objects.

def insert_items():
    for item in RLPy.RScene.GetSelectedObjects():
        recorded_objects[item.GetName()] = item

    prune_list()

Creating the UI

We'll need to load the configured QT UI file. You can download Item_Lister.ui here -make sure this UI file is placed in the same script directory. We'll also need to connect the custom user controls with relevant methods mentioned above and register our event callbacks.

dialog_window = RLPy.RUi.CreateRDialog()
dialog_window.SetWindowTitle("Item Lister")

dialog = wrapInstance(int(dialog_window.GetWindow()), QtWidgets.QDialog)
dialog.setFixedWidth(250)

qt_ui_file = QtCore.QFile(os.path.dirname(__file__) + "/item_lister.ui")
qt_ui_file.open(QtCore.QFile.ReadOnly)
widget = QtUiTools.QUiLoader().load(qt_ui_file)
qt_ui_file.close()
dialog.layout().addWidget(widget)

widget.pushButton.clicked.connect(insert_items)

event_callback = EventCallback()
event_callback_id = RLPy.REventHandler.RegisterCallback(event_callback)

dialog_window.Show()

Everything Put Together

You can copy and paste the following code into a PY file and load it into iClone via Script > Load Python.

import RLPy
import os
from PySide2 import *
from PySide2.shiboken2 import wrapInstance

recorded_objects = {}


class EventCallback(RLPy.REventCallback):
    def __init__(self):
        RLPy.REventCallback.__init__(self)

    def OnObjectDeleted(self):
        prune_list()


class DialogEventCallback(RLPy.RDialogCallback):
    def __init__(self):
        RLPy.RDialogCallback.__init__(self)

    def OnDialogHide(self):
        global event_callback_id
        RLPy.REventHandler.UnregisterCallback(event_callback_id)
        return True


def prune_list():
    widget.listWidget.clear()

    for name, item in list(recorded_objects.items()):
        if item.IsValid():
            widget.listWidget.insertItem(widget.listWidget.count(), name)
        else:
            del recorded_objects[name]


def insert_items():
    for item in RLPy.RScene.GetSelectedObjects():
        recorded_objects[item.GetName()] = item

    prune_list()


dialog_window = RLPy.RUi.CreateRDialog()
dialog_window.SetWindowTitle("Item Lister")

dialog = wrapInstance(int(dialog_window.GetWindow()), QtWidgets.QDialog)
dialog.setFixedWidth(250)

qt_ui_file = QtCore.QFile(os.path.dirname(__file__) + "/Item_Lister.ui")
qt_ui_file.open(QtCore.QFile.ReadOnly)
widget = QtUiTools.QUiLoader().load(qt_ui_file)
qt_ui_file.close()
dialog.layout().addWidget(widget)

widget.pushButton.clicked.connect(insert_items)

event_callback = EventCallback()
event_callback_id = RLPy.REventHandler.RegisterCallback(event_callback)

dialog_window.Show()

APIs Used

You can research the following references for the APIs deployed in this code.