Running .ui -> Python during CMake
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Be nice to others! Respect the FreeCAD code of conduct!
Running .ui -> Python during CMake
I'd like to translate a *.ui file into a Python class during the compilation process (via CMake), the way we do for C++. That is, to run either pyside2-uic or uic -g python (depending on the Qt version) automatically, so that when the .ui changes the generated file gets recreated. I don't see any examples for how to do this, all the other Python I see is generating entire windows in a ui file so just using loadUi(). In my case it's a widget that's getting reused hundreds of times, I don't want to reload the ui file each time. Is there a Python equivalent to QT5_WRAP_UI() or AUTOUIC()?
Re: Running .ui -> Python during CMake
Maybe designing it directly using python?
Or maybe coding directly it in C++.
Sometimes is not so difficult as it seems at first glance.
Regards
Carlo D.
Or maybe coding directly it in C++.
Sometimes is not so difficult as it seems at first glance.
Regards
Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.
Blog: https://okkmkblog.wordpress.com/
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.
Blog: https://okkmkblog.wordpress.com/
Re: Running .ui -> Python during CMake
It seems you must write your own CMake macro for this.
On my system Ubuntu 18.04 there are no official PySide2 packages but they are available on Launchpad. But what's odd with is package is that from a terminal window I cannot run:
because it raises an ImportError that QtCore cannot be loaded. Having a look at the file shows why. The shebang is:
So, it uses python2 and because I don't have installed PySide2 packages for that version the QtCore module cannot be loaded. A workaround for me is to explicitly invoke python3 with:
and this is a use case the CMake macro should cover, too.
On my system Ubuntu 18.04 there are no official PySide2 packages but they are available on Launchpad. But what's odd with is package is that from a terminal window I cannot run:
Code: Select all
/usr/bin/pyside2-uic
Code: Select all
#! /usr/bin/python2
Code: Select all
python3 /usr/bin/pyside2-uic file.ui -o ui_file.py
Re: Running .ui -> Python during CMake
This CMake function works with pyide2-uic:
For newer Qt versions you probably can use QT5_WRAP_UI like this I guess:
Two things you still have to consider:
Code: Select all
# must be set
set (PYSIDEUICBINARY "/usr/bin/pyside2-uic")
include(CMakeParseArguments)
function(PY3_WRAP_UI outfiles )
set(options)
set(oneValueArgs)
set(multiValueArgs OPTIONS)
cmake_parse_arguments(_WRAP_UI "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(ui_files ${_WRAP_UI_UNPARSED_ARGUMENTS})
set(ui_options ${_WRAP_UI_OPTIONS})
foreach(it ${ui_files})
get_filename_component(outfile ${it} NAME_WE)
get_filename_component(infile ${it} ABSOLUTE)
set(outfile ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.py)
add_custom_command(OUTPUT ${outfile}
COMMAND ${PYTHON_EXECUTABLE} ${PYSIDEUICBINARY}
ARGS ${ui_options} -o ${outfile} ${infile}
MAIN_DEPENDENCY ${infile} VERBATIM)
set_source_files_properties(${infile} PROPERTIES SKIP_AUTOUIC ON)
set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC ON)
set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOUIC ON)
list(APPEND ${outfiles} ${outfile})
endforeach()
set(${outfiles} ${${outfiles}} PARENT_SCOPE)
endfunction()
Code: Select all
qt5_wrap_ui(MY_UIC_PY_SRCS ${MY_UIC_SRCS} OPTIONS "-g python")
- The ui files must not contain any custom widgets. Only Qt widgets are allowed
- Inside the ui files namespaces are not allowed as otherwise an invalid class name will be generated, e.g. Ui_PartGui::MyUIFile
Re: Running .ui -> Python during CMake
I was able to use a custom widget with uic -g python -- is this a limitation of pyside2-uic? With uic it's a little weird because you still have to provide a C++-style header file for the widget, but it strips the .h off the end of the filename and imports it instead.
Re: Running .ui -> Python during CMake
The strategy I ended up using was to manually run uic on the ui file and include the resulting Python file manually in the git repo. I may not even commit the ui at all, I ended up hand-editing the resulting Python to deal with an unrelated issue, so it might not be worth keeping the ui around at all at this point. Anyone who wants to edit the widget needs to edit the Python directly now anyway.
Re: Running .ui -> Python during CMake
Then I wonder how does the code generator know to create an instance of an unknown class. As a simple example take the ImageOrientationDialog.ui file of the image module. It has one custom widget, a Gui::QuantitySpinBox.I was able to use a custom widget with uic -g python -- is this a limitation of pyside2-uic?
The ui file contains this information about the class:
Code: Select all
<customwidget>
<class>Gui::QuantitySpinBox</class>
<extends>QWidget</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
Re: Running .ui -> Python during CMake
I once wrote this summary about the differences of QUiLoader and pyide-uic: https://forum.freecadweb.org/viewtopic.php?f=10&t=5374
Btw, when I use the built-in function Gui.PySideUic.loadUiType then I again get the error message with ImageOrientationDialog.ui:
Btw, when I use the built-in function Gui.PySideUic.loadUiType then I again get the error message with ImageOrientationDialog.ui:
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<string>", line 16, in <module>
File "/usr/lib/python3/dist-packages/pyside2uic/__init__.py", line 143, in compileUi
winfo = compiler.UICompiler().compileUi(uifile, pyfile, from_imports)
File "/usr/lib/python3/dist-packages/pyside2uic/Compiler/compiler.py", line 91, in compileUi
w = self.parse(input_stream)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 874, in parse
actor(elem)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 717, in createUserInterface
self.traverseWidgetTree(elem)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 695, in traverseWidgetTree
handler(self, child)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 430, in createLayout
self.traverseWidgetTree(elem)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 695, in traverseWidgetTree
handler(self, child)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 467, in handleItem
self.traverseWidgetTree(elem)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 695, in traverseWidgetTree
handler(self, child)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 430, in createLayout
self.traverseWidgetTree(elem)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 695, in traverseWidgetTree
handler(self, child)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 467, in handleItem
self.traverseWidgetTree(elem)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 695, in traverseWidgetTree
handler(self, child)
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 191, in createWidget
self.stack.push(self.setupObject(widget_class, parent, elem))
File "/usr/lib/python3/dist-packages/pyside2uic/uiparser.py", line 154, in setupObject
obj = self.factory.createQObject(clsname, name, args, is_attribute)
File "/usr/lib/python3/dist-packages/pyside2uic/objcreator.py", line 91, in createQObject
raise NoSuchWidgetError(classname)
pyside2uic.exceptions.NoSuchWidgetError: Unknown Qt widget: Gui.QuantitySpinBox
Re: Running .ui -> Python during CMake
Oh, I see, I wasn't trying to use one of FreeCAD's custom widgets -- I had written a new one in Python that I was using, and that worked fine.