Better_Software_Header_MobileBetter_Software_Header_Web

Find what you need - explore our website and developer resources

Creating Python bindings for Qt libraries

~$ python3 -m pip install --index-url=http://download.qt.io/snapshots/ci/pyside/[Qt-Version]/latest/ shiboken2-generator pyside2 --trusted-host download.qt.io
~$ python3 -m pip install --index-url=http://download.qt.io/snapshots/ci/pyside/5.15/latest/ shiboken2-generator pyside2 --trusted-host download.qt.io
<?xml version="1.0"?>
<!-- The package name -->
<typesystem package="KDDockWidgets">
    <!-- Pre-defined typesystem that contains types used by our class.
        PySide has one typesystem for each module, so here we use only the
        Widgets typesystem because it already includes gui and core
        typesystems -->
    <load-typesystem name="typesystem_widgets.xml" generate="no"/>

    <!-- Our classes are declared in a namespace, so we need to define one -->
    <namespace-type name="KDDockWidgets">
        <!-- This is used in a public virtual pure function.
             We need to declare it otherwise shiboken will ignore the
             function and will fail to create a wrapper -->
        <primitive-type name="DropAreaWithCentralFrame"/>

        <!-- Export our public enums and flags -->
        <enum-type name="Location"/>
        <enum-type name="MainWindowOption" flags="MainWindowOptions"/>
        <enum-type name="AddingOption"/>
        <enum-type name="RestoreOption" flags="RestoreOptions"/>
        <enum-type name="DefaultSizeMode"/>
        <enum-type name="FrameOption" flags="FrameOptions"/>

        <!-- Export our classes
             For classes we can use two types:
                object-type: class that does not have a copy-constructor
                             and cannot be passed as value to functions;
                value-type: class that can be passed as value for functions

             Here we only use 'object-type' since all our classes are
             derived from QWidget.
         -->
        <object-type name="MainWindowBase" />
        <object-type name="MainWindow" />

        <!-- DockWidgetBase contains an internal enum, so we declare it
             inside of the object-type -->

        <object-type name="DockWidgetBase" >
            <enum-type name="Option" flags="Options" />
        </object-type>

        <object-type name="DockWidget" />
    </namespace-type>
</typesystem>
#pragma once

// Make "signals:", "slots:" visible as access specifiers
#define QT_ANNOTATE_ACCESS_SPECIFIER(a) __attribute__((annotate(#a)))

#include <MainWindowBase.h>
#include <MainWindow.h>
#include <DockWidgetBase.h>
#include <DockWidget.h>
# Auto-Generate files - every class will have a cpp and h file
set(PyKDDockWidgets_SRC
    # individual classes
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_dockwidgetbase_wrapper.cpp
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_dockwidgetbase_wrapper.h
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_dockwidget_wrapper.cpp
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_dockwidget_wrapper.h
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_mainwindowbase_wrapper.cpp
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_mainwindowbase_wrapper.h
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_mainwindow_wrapper.cpp
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_mainwindow_wrapper.h
    # namespace wrapper
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_wrapper.cpp
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_wrapper.h
    # global module wrapper
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_module_wrapper.cpp
    ${CMAKE_CURRENT_BINARY_DIR}/KDDockWidgets/kddockwidgets_python.h
)

# The includes are needed to parse and build classes specified in our typesystem
set(PyKDDockWidgets_include_paths
    $<JOIN:$<TARGET_PROPERTY:KDAB::kddockwidgets,INTERFACE_INCLUDE_DIRECTORIES>,${PATH_SEP}>
)

# Set list of paths where shiboken should look for typesystem
set(PyKDDockWidgets_typesystem_paths
    # PySide path, this variable was exposed by FindPySide2.cmake
    ${PYSIDE_TYPESYSTEMS}
)

# Include flags/path that will be set in 'target_include_directories'
set(PyKDDockWidgets_target_include_directories
    ${CMAKE_SOURCE_DIR}
)

# Libraries necessary to link the target for the command 'target_link_libraries'
set(PyKDDockWidgets_target_link_libraries
    KDAB::kddockwidgets
    Qt5::Core
    Qt5::Gui
    Qt5::Widgets
)

# Dependencies - changes on these files should trigger new bindings
set(PyKDDockWidgets_DEPENDS
    ${CMAKE_CURRENT_SOURCE_DIR}/kddockwidgets_global.h
    ${CMAKE_SOURCE_DIR}/src/DockWidgetBase.h
    ${CMAKE_SOURCE_DIR}/src/DockWidget.h
    ${CMAKE_SOURCE_DIR}/src/MainWindowBase.h
    ${CMAKE_SOURCE_DIR}/src/MainWindow.h
)

CREATE_PYTHON_BINDINGS(
    "KDDockWidgets"
    "${PyKDDockWidgets_typesystem_paths}"
    "${PyKDDockWidgets_include_paths}"
    "${PyKDDockWidgets_SRC}"
    "${PyKDDockWidgets_target_include_directories}"
    "${PyKDDockWidgets_target_link_libraries}"
    ${CMAKE_CURRENT_SOURCE_DIR}/kddockwidgets_global.h
    ${CMAKE_CURRENT_SOURCE_DIR}/typesystem_kddockwidgets.xml
    "${PyKDDockWidgets_DEPENDS}"
    ${CMAKE_CURRENT_BINARY_DIR}
)

# Make moduled import from build dir works
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${CMAKE_CURRENT_BINARY_DIR}/__init__.py)

# install
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py DESTINATION ${Python3_SITELIB}/PyKDDockWidgets)
__all__ = ['KDDockWidgets']

# Preload PySide2 libraries to avoid missing libraries while loading our module
try:
    from PySide2 import QtCore
except Exception:
    print("Failed to load PySide")
    raise

# Avoid duplicate namespace - the package name would normally look like this:
# PyKDDockWidgets.KDDockWidgets.KDDockWidgets.MainWindow
# (There is a bug PYSIDE-1325 to get this namespace duplication fixed.)
# To avoid this, we use this workaround:
from .KDDockWidgets import KDDockWidgets as _priv
KDDockWidgets = _priv
from PyKDDockWidgets import KDDockWidgets

options = KDDockWidgets.MainWindowOption_None

dock = KDDockWidgets.DockWidget("new dock 1")
dock.resize(600, 600)
dock.show()

About KDAB


2 Comments

25 - Sept - 2024

Joel

26 - Sept - 2024

Renato Araujo

RenatoAraujo

Renato Araujo

Senior Software Engineer

Learn Modern C++

Learn more