Learning iClone Python: nuts & bolts

Print Topic | Close Window

By RobertoColombo - Last Year
TUTORIAL 1: HelloWorld for the absolute beginner

Get your hands wet for the first time...

2. Select all the code under Method 2
3. Copy-Paste into a text file and name as HelloWorld.py
4. Open iClone
5. Select Script->Console Log
6. Select Script->Load Python and choose the file that you have created
7. A window should pop up, with the "Hello world" text message and an OK button. Moreover the message "Hello world" should appear also in the console window
8. Congratulations: you just created and run your first Python script!!!

What happened in there ?

import RLPydef run_script():
    print ("Hello World")
    RLPy.RUi.ShowMessageBox("Your First Python Plugin", "Hello World", RLPy.EMsgButton_Ok)

1. import RLPy
This statement tells iClone Python engine to load the whole RPLy class.
This class contains all the stuff related to iClone assets and it is here where we will have to look how to do when we want to touch some iClone object.

2. def run_script()
In Python, the functions are identified by the keword "def", followed by the procedure name.
The code within the function shall be indented by 4 spaces.
Note that the name is not just "a name" chosen within one thousands...
the name MUST be "run_script" because this is the method called by iClone when a Python script is loaded and executed.
If you do not trust it, try to rename it to something different, load the script, and see what does it happen...

3. print("Hello World")
The print() function is used to print text message on Python console window, which is available by default (no need to create it!!).
Try to comment this line of code by adding a '#' (dash) character at thr beginning of the line, save the file, and load it again.
Now the text "Hello world" will not be written into the console window and you will see only the window created with the code line 4 (see below)!

3. RLPy.RUi.ShowMessageBox("Your First Python Plugin", "Hello World", RLPy.EMsgButton_Ok)
The functions (in object-oriented programming terminology called "methods") re called by referencing them with the class base name, followed by a '.' (dot), and then the function name.
The ShowMessageBox() creates a new window.
This function receives some parameters (listed between the function brackets).
In this example the parameters are:
- the name of the window, shown in the window top area
- the text "Hello world", shown within the window
- a button with the text "OK", which closes the window when pressed
The mechanism that makes it possible to create this window and close when you press OK is hidden under-the-hood... do not care about it right now!
Try to comment this line of code, like you did for line 3 above, and leave now line 3 uncommented (i.e. no dash in line 3)
When you run the file, you should see the text message appearing in the Console Window but no other window should be created.
Got the difference between print() and ShowMessageBox() ?

As you can imagine, now it's up to you: try to make some small experiments in order to get familiar with this code.
For example, change the text....

Note: at the time of writing this post, it is not clear how to assign the proper values to the ShowMessageBox() parameters, apart from tht obvious 2 text strings.
The ShowMessageBox() doc does not link "RLPy.EMsgButton_Ok" as one of thr posible input parameter values.... therefore I do not recommend to try fancy things except modifying the mesage text... at least till RL has clarified this (see also the question nr. 4 here: https://forum.reallusion.com/399142/Python-FAQ-Tracker)

By RobertoColombo - Last Year
Hi Dalerna,

problem is now fixed.
See here: https://forum.reallusion.com/399188/Basic-Samples-Request-thread

By RobertoColombo - Last Year
TUTORIAL 2: Python funtion sleection via Menu interface for the absolute beginner

Get your hands wet for the second time...

2. Select all the code under Method 1
3. Copy-Paste into a text file and name as main.py
4. Save this file into the directory OpenPlugin/MyFolder, wher "MyFolder" is a placeholder for any name you want to use.
    The openPlugin directory shall be under Bin64 directory
5. Open iClone
6. A new menu group should appear, which contains one menu item
7. Congratulations: you just created and run a main Python script that will be run everytime iClone starts!!!

import RLPy
import PySide2
from PySide2.QtWidgets import QMainWindow, QMenu
from PySide2.shiboken2 import wrapInstance
def initialize_plugin():
    # Add menu    ic_dlg = PySide2.shiboken2.wrapInstance(int(RLPy.RUi.GetMainWindow()), PySide2.QtWidgets.QMainWindow)
    plugin_menu = ic_dlg.menuBar().findChild(PySide2.QtWidgets.QMenu, "pysample_menu")
    if (plugin_menu == None):
        plugin_menu = PySide2.shiboken2.wrapInstance(int(RLPy.RUi.AddMenu("Python Samples", RLPy.EMenu_Plugins)), PySide2.QtWidgets.QMenu)
    hello_world_action = plugin_menu.addAction("Hello World")
def show_dialog():
    RLPy.RUi.ShowMessageBox("Your First Python Plugin", "Hello World", RLPy.EMsgButton_Ok)

What happened in there ?

1. import xxx
Same explanation as the TUTORIAL 1 above.
Now, 2 libraries shall be imported: Reallusion class of objects and the "pyside2" library, which is used to convert the Qt library into Python objects.
Note that an explicit importing of teh PySide2 library is MANDATORY otherwise iClone not see them, that is, the following likes of code are are necessary

    from PySide2.QtWidgets import QMainWindow, QMenu
    from PySide2.shiboken2 import wrapInstance

2. def initialize_plugin()
The name of the function suggests that it is run when iClone initializes the Python engine and the corresponding event is caught only by a Python code executed within the main.py code.
Note that the entry point of a loaded Python code is "run_script()" and if omitted, nothing happens in a loaded plug-in.
The same is valid for the "main.py" code, loaded at the start-up, but this time the event triggers the "initialize_plugin()" function.

3. ic_dlg = PySide2.shiboken2.wrapInstance(int(RLPy.RUi.GetMainWindow()), PySide2.QtWidgets.QMainWindow)
Here things start to get complicated...
Let's start from the output of this line of code: "ic_dlg" is an "handle" (you can think of it as a way to reference an object for further actions) in Python language and environment to iClone main window.
This is the result of following "tools": 
3a. "shiboken2" is a tool to connects objects within C++ language into Python objects. The wrapFunction() method creates a Python wrapper for a C++ object instantiated at a given memory address.
In this case the object is iClone window, whos handle is  returned by RLPy.RUi.GetMainWindow() function and whose type is defined within Qt library.
3b. "PySide2" is a library that connects the a Qt object into a Python object: iClone main window has now been transformed into a Python object!

4. plugin_menu = ic_dlg.menuBar().findChild(PySide2.QtWidgets.QMenu, "pysample_menu")
This line of code takes the handle to the iClone main window object and using some of the methods available for this object, checks whether a menu group called "pysample_menu" already exists.
The output of this funtion is an "handle" to this menu group.
Note that every operation on the GUI (Graphic user interface) always passes through the pyside2 library, because this is the way to connect the Qt library to our Python world

5. if (plugin_menu == None):
        plugin_menu = PySide2.shiboken2.wrapInstance(int(RLPy.RUi.AddMenu("Python Samples", RLPy.EMenu_Plugins)), PySide2.QtWidgets.QMenu)
These lines should be enough clear.
If no menu group called "pysample_menu" exists, then the hanlde has a "null" value, which in Python is represented by the keyword "None",
In this case, a new menu group, which sahll display the text "Python samples" when shown.
This is the name of the menu gorup displayed in iClone window.
The menu group object (i.e. the element that "lives" within the Python world) has also a name and the 3rd line of code calls it "pysample_menu".
In summary, these 3 lines of code check whether any menu object called "pysample_code" alerady exits, and, if it does not exists, a new menu group object is created, renamed as "pysample_code" and set to display the text "Python samples" whne shown.
Note the indentation: the code indented under the "if" statement is executed if the confition is true.
The code line 6, decribed hereunder, is not part of the "if" block because it has a lesser indentation.
Python uses this mechanism to enforce the lazy programmers to use indentation... 
Note also that the "if" statement msut end with a ':' (colon)

6. hello_world_action = plugin_menu.addAction("Hello World")
This line of code fills the menu group that we just created with 1 item, called "Hello world" and returns an handle (called "hello_world_action") to this item.
This handle is used in the next line to set what does it happens when this item is selcted...

7. hello_world_action.triggered.connect(show_dialog)
This code sets which function shall be run when the menu item "hello_world_action"is triggered, i.e. selected
The function is show_dialog() and obviously shall be defined somewhere...

8. def show_dialog():
    RLPy.RUi.ShowMessageBox("Your First Python Plugin", "Hello World", RLPy.EMsgButton_Ok)

Here is our function!
It does the same (except writing in the Python console) as the function "run_script()" of teh example above: it creates a window and display the message "Hello world".
A button is also created to close the window.
Refer to the Tutorial 1 above for more details about this line of code.

By Delerna - Last Year
Well explained sir. Looking forward to reading more from you.

I have also tried what you showed as Tutorial 2.
I am not sure where to put the main.py file either as you questioned reallusion here in question 1
So I just saved it in my Python folder, changed function name initialize_plugin to run_Script and loaded it into iClone but got nothing from it.
Checked the error messages

The code on line 6 is this
ic_dlg = PySide2.shiboken2.wrapInstance(int(RLPy.RUi.GetMainWindow()), PySide2.QtWidgets.QMainWindow)

Which is using the PySide2 import
Thanks to you here I now understand that is used to convert QT objects into python objects.
QT is something I never knew about until now so I am looking into what I need to do to get this into my computer in a way that it will be used by iClones python API
Also saw your question for that here in your question 2

Anyway, thanks again for your posts. Appreciate them
By RobertoColombo - Last Year
Hi Dennis,

Perhaps I will contact RL for a job when i will retire and will have more time... Wink


By RobertoColombo - Last Year
Hi all,

I started this thread with the idea to add any useful information that can help both the developers, whatever level they are. 


By justaviking - Last Year
Thank you for this great thread, Roberto.

Perhaps Reallusion can hire you to write some of the documentation they ought to have provided.