The possibility to program custom widgets for the nodes is one of the core concepts. For that, you use PySide2 (aka Qt For Python) directly. A widget must derive from QWidget either directly or indirectly. Deriving from QPushButton for example would make a valid widget too. There are no restrictions - your custom widget can be any QWidget (which itself can contain about anything). If you are not familiar with Qt but have already worked with other big GUI libraries, getting into PySide2 is not very difficult, I guess. Use the existent nodes with widgets as reference. A node can have a main widget which sits either between or under the ports, and every data input of a node can have a custom widget too. All widget classes must be declared in the NodeManager (whether a node has a main widget and every custom input widget in the Input Widgets area). The NodeManager will then create template files for all these widgets which you then can edit either directly in the NodeManager or outside by editing the metacode files directly. All widget metacode files are located in the widgets folder inside the node's folder.
Access Parent Node
In both types of widgets, you can access the parent node via
Using Custom Content - Package Path
As you can see in the code generated for a widget, there is a package path which is the path to the package the node is a part of. This is very useful if you want to use resources like images laying on your file system. You can put them anywhere you want into the package directory, they will not be removed by the NodeManager when overriding the package. You can also use the package path to import further Python classes you defined and want to use in different widgets (like a widget parent for a certain type of node).
The following code is an example for a button node. Once you press the button, the first and only execution output should get executed:
from PySide2.QtWidgets import QPushButton class %NODE_TITLE%_NodeInstance_MainWidget(QPushButton): def __init__(self, parent_node_instance): super(%NODE_TITLE%_NodeInstance_MainWidget, self).__init__() # leave these lines ------------------------------ self.parent_node_instance = parent_node_instance # ------------------------------------------------ self.setStyleSheet(''' background-color: #36383B; padding-top: 5px; padding-bottom: 5px; padding-left: 22px; padding-right: 22px; border: 1px solid #666666; border-radius: 5px; ''') # get_data, set_data and remove event stay empty as there are no states or timers
In the node's class, we need to connect this button like that:
# ... class %NODE_TITLE%_NodeInstance(NodeInstance): def __init__(self, parent_node: Node, flow, configuration=None): super(%NODE_TITLE%_NodeInstance, self).__init__(parent_node, flow, configuration) self.main_widget.clicked.connect(M(self.button_clicked)) # QPushButton.clicked.connect() is Qt syntax self.initialized() def button_clicked(self): self.update() # will result in an update event def update_event(self, input_called=-1): self.exec_output(0) # ...
Data Input Widgets
Input widgets are custom widgets you can program for data input ports of a node. There are standard widgets for data inputs which you can select in the NodeManager for the initial ports, or you can also use them when programatically adding new inputs (see section API -> Ports). But you can also program custom widgets for data inputs.
When using custom input widgets, you must define them in the Input Widgets area in the NodeManager and give the exact name in the input widget name line edit of any initial input using it or in the equivalent API method call. Different inputs can use the same custom widget.
Programming a custom input widget almost does not differ from programming a main widget. The only difference is that you need to fill the get_val() method which should return the value the widget currently holds. A spin box, for example, would return the number it currently shows. This value will only be used (by calling self.input(index) in the node) if the port is not connected to some other node.