Revisiting this issue, I was able to come up with a much neater solution. It uses the amazing [UnrealEnginePython][1] plugin. Besides unlocking the full power and comfort of Python, it has the added benefit of eliminating the need for C++ in this case. After setting up the plugin, simply pip install any Python GUI framework and call its file dialog functions. Since the GUI frameworks are crossplatform, I believe this method should work on Linux and other supported platforms as well. But I’ve only tried with Windows. Please let me know how it goes with other platforms.
Mini Example
Download a suitable embedded version of UnrealEnginePython and add to the Plugins folder of your project, and enable it in your Plugins settings. To install PySide2, a Python binding of the popular QT framework, run the following command from the Python folder in the plugin (…MyProject/Plugins/UnrealEnginePython/Binaries/Win64/).
./python.exe -m pip install --target . pyside2
With that done, create a PyActor blueprint class and set up its variables like so
Then set up the actor like so
We then create a file_dialog.py in the Project/Scripts folder and paste the following in it.
from PySide2 import QtCore, QtWidgets, QtGui
import unreal_engine as ue
from PySide2.QtWidgets import QFileDialog
from unreal_engine import FSlateApplication
#this import initializes our qt app
from ueqt import inst as ueqt
class DummyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
class FileDialogManager:
# this is called on game start
def begin_play(self):
ue.log("File Dialog:::Start")
def open(self):
widget = DummyWidget()
# widget.resize(800, 600)
# widget.show()
# get the active top level window
top_window = FSlateApplication.get_active_top_level_window()
top_window.set_as_owner(widget.winId())
f = QFileDialog.getOpenFileName(
widget, #parent
self.uobject.Title, #title
self.uobject.InitialDir, #initial dir
";;".join(self.uobject.FileTypeFilters), #filters
self.uobject.FileTypeFilters[self.uobject.SelectedFileTypeFilter] #selected filter
)
if len(f[0]) < 1:
ue.log("Open File Dialog:::Canceled")
self.uobject.call_function('OnCancel')
return
ue.log("Open File Dialog:::Confirmed")
ue.log(f)
widget.close()
self.uobject.Filepath = f[0]
self.uobject.call_function('OnOpen')
# this is called at every 'tick'
def tick(self, delta_time):
pass
# this is called at the end
def end_play(self, reason=None):
ue.log("File Dialog:::Quit")
ue.log(reason)
Then we create a ueqt.py script
import sys
import unreal_engine as ue
import PySide2
from PySide2 import QtWidgets
class UEQT:
app = None
def __init__(self):
self.app = QtWidgets.QApplication(sys.argv)
inst = UEQT()
ue.set_brutal_finalize(True)
That’s all the coding we need. Head back to our PyActor and create a function called Open and another called OnOpen. Then create an event dispatcher called OnFileOpen with a single string input.
Then to open a dialog when you need to, simply spawn the actor, bind the OnFileOpen event and call Open.
If you get stuck, check out this repo on Bitbucket Bitbucket. It was created following this example. You can study its blueprint classes and python files for a better understanding.
Note: At the time of writing, only the latest code from the UnrealEnginePython repo supports attaching the file dialog to the unreal window. You should build the plugin from source (following the instructions on their page) if this is needed. Or comment out the lines of code with “top_window”. It will still open the file dialog, but it will not be attached to the unreal window. Or just wait for them to update the releases