Community Tutorial: Unreal / PyQt sample UI Template

This is a simple UI template for loading Qt / PyQt tool windows within Unreal using Python. This template will parent the window to Unreal, remove old instances of the window, and automatically resize the widget. It also includes sample methods, how to identify child widgets, and how to connect a signal to a method. I recommend Qt Designer to generate tool .ui files.

Please feel free to post questions, comments, or suggestions for improvements.

https://dev.epicgames.com/community/learning/tutorials/mJaO/unreal-engine-unreal-pyqt-sample-ui-template

Hi,

This template worked great in 5.3 and below. However, in 5.4 as the Python version is now 3.11 Pyside2 is no longer supported.

I tried PySide6 however the engine just hangs and crashes when running the script.

Any ideas of what changes that need to be made? This currently blocks some tools we’ve made from working in 5.4.

EDIT:

Further investigation suggests its the QUiLoader, still testing things out to see if there is a fix.

EDIT:

import unreal
import sys
from functools import partial  # if you want to include args with UI method calls
from PySide6.QtWidgets import QApplication, QWidget, QPushButton
from PySide6.QtUiTools import QUiLoader
from PySide6.QtCore import QFile

"""
Be sure to add your default python modules directory path to Unreal:
Project Settings -> Python -> Additional Paths

Default location of installed modules:
C:\\Users\\[USER]]\\AppData\Local\\Programs\\Python\\[PYTHON VERSION]\\Lib\site-packages

This code required PySide6 module which may need to be installed.
To install required modules open windows command prompt and enter:
pip install [MODULENAME]
"""

class UnrealUITemplate(QWidget):
    """
    Create a default tool window.
    """
    # store ref to window to prevent garbage collection
    window = None
    def __init__(self, parent = None, loader = None):
        """
        Import UI and connect components
        """
        super(UnrealUITemplate, self).__init__(parent)
        
        #load the created UI widget
        self.widgetPath = 'C:\\'
        self.widget = loader.load(self.widgetPath + 'mainWidget.ui')  #path to PyQt .ui file

        #attach the widget to the instance of this class (aka self)
        self.widget.setParent(self)

        #find interactive elements of UI
        self.btn_close = self.widget.findChild(QPushButton, 'btn_close')

        #assign clicked handler to buttons
        self.btn_close.clicked.connect(self.closewindow)

    """
    Your code goes here.
    """
    def resizeEvent(self, event):
        """
        Called on automatically generated resize event
        """
        self.widget.resize(self.width(), self.height())

    def closewindow(self):
        """
        Close the window.
        """
        self.destroy()

def openWindow():
    """
    Create tool window.
    """
    ui_loader = QUiLoader()

    if QApplication.instance():
        # Id any current instances of tool and destroy
        for win in (QApplication.allWindows()):
            if 'toolWindow' in win.objectName(): # update this name to match name below
                win.destroy()
    else:
        QApplication(sys.argv)
    
    # load UI into QApp instance
    UnrealUITemplate.window = UnrealUITemplate(loader = ui_loader)
    UnrealUITemplate.window.show()
    UnrealUITemplate.window.setObjectName('toolWindow') # update this with something unique to your tool
    UnrealUITemplate.window.setWindowTitle('Sample Tool')
    unreal.parent_external_window_to_slate(UnrealUITemplate.window.winId(),unreal.SlateParentWindowSearchMethod.MAIN_WINDOW)
    
openWindow()

Fix is to parse in the loader outside of the class. No idea why but this comment on this question lead me on to solving the issue: python - PySide6 QUiLoader doesn’t show window - Stack Overflow

PySIde 6 works with Python 3.11, so hopefully this should work better.

EDIT:

It’s not working again. Investigating.

EDIT:

Fixed the example again, the QUiLoader() has to be before any QApplications calls

1 Like