diff options
-rw-r--r-- | examples/widgetbinding/CMakeLists.txt | 275 | ||||
-rw-r--r-- | examples/widgetbinding/README.md | 74 | ||||
-rw-r--r-- | examples/widgetbinding/bindings.h | 54 | ||||
-rw-r--r-- | examples/widgetbinding/bindings.xml | 56 | ||||
-rw-r--r-- | examples/widgetbinding/dialog.py | 77 | ||||
-rw-r--r-- | examples/widgetbinding/macros.h | 63 | ||||
-rw-r--r-- | examples/widgetbinding/main.py | 61 | ||||
-rw-r--r-- | examples/widgetbinding/wigglywidget.cpp | 111 | ||||
-rw-r--r-- | examples/widgetbinding/wigglywidget.h | 81 | ||||
-rw-r--r-- | examples/widgetbinding/wigglywidget.py | 97 |
10 files changed, 949 insertions, 0 deletions
diff --git a/examples/widgetbinding/CMakeLists.txt b/examples/widgetbinding/CMakeLists.txt new file mode 100644 index 000000000..a557f90ec --- /dev/null +++ b/examples/widgetbinding/CMakeLists.txt @@ -0,0 +1,275 @@ +cmake_minimum_required(VERSION 3.1) +cmake_policy(VERSION 3.1) + +# Enable policy to not use RPATH settings for install_name on macOS. +if(POLICY CMP0068) + cmake_policy(SET CMP0068 NEW) +endif() + +# Enable policy to run automoc on generated files. +if(POLICY CMP0071) + cmake_policy(SET CMP0071 NEW) +endif() + +# Consider changing the project name to something relevant for you. +project(wiggly LANGUAGES CXX) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) +find_package(Qt5 5.12 REQUIRED COMPONENTS Core Gui Widgets) + +# ================================ General configuration ====================================== + +# Set CPP standard to C++11 minimum. +set(CMAKE_CXX_STANDARD 11) + +# The wiggly library for which we will create bindings. You can change the name to something +# relevant for your project. +set(wiggly_library "libwiggly") + +# The name of the generated bindings module (as imported in Python). You can change the name +# to something relevant for your project. +set(bindings_library "wiggly") + +# The header file with all the types and functions for which bindings will be generated. +# Usually it simply includes other headers of the library you are creating bindings for. +set(wrapped_header ${CMAKE_SOURCE_DIR}/bindings.h) + +# The typesystem xml file which defines the relationships between the C++ types / functions +# and the corresponding Python equivalents. +set(typesystem_file ${CMAKE_SOURCE_DIR}/bindings.xml) + +# Specify which C++ files will be generated by shiboken. This includes the module wrapper +# and a '.cpp' file per C++ type. These are needed for generating the module shared +# library. +set(generated_sources + ${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/wiggly_module_wrapper.cpp + ${CMAKE_CURRENT_BINARY_DIR}/${bindings_library}/wigglywidget_wrapper.cpp) + + +# ================================== Shiboken detection ====================================== +# Use provided python interpreter if given. +if(NOT python_interpreter) + find_program(python_interpreter "python") +endif() +message(STATUS "Using python interpreter: ${python_interpreter}") + +# Macro to get various pyside / python include / link flags and paths. +# Uses the not entirely supported utils/pyside2_config.py file. +macro(pyside2_config option output_var) + if(${ARGC} GREATER 2) + set(is_list ${ARGV2}) + else() + set(is_list "") + endif() + + execute_process( + COMMAND ${python_interpreter} "${CMAKE_SOURCE_DIR}/../utils/pyside2_config.py" + ${option} + OUTPUT_VARIABLE ${output_var} + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if ("${${output_var}}" STREQUAL "") + message(FATAL_ERROR "Error: Calling pyside2_config.py ${option} returned no output.") + endif() + if(is_list) + string (REPLACE " " ";" ${output_var} "${${output_var}}") + endif() +endmacro() + +# Query for the shiboken generator path, Python path, include paths and linker flags. +pyside2_config(--shiboken2-module-path shiboken2_module_path) +pyside2_config(--shiboken2-generator-path shiboken2_generator_path) +pyside2_config(--pyside2-path pyside2_path) +pyside2_config(--pyside2-include-path pyside2_include_dir 1) +pyside2_config(--python-include-path python_include_dir) +pyside2_config(--shiboken2-generator-include-path shiboken_include_dir 1) +pyside2_config(--shiboken2-module-shared-libraries-cmake shiboken_shared_libraries 0) +pyside2_config(--python-link-flags-cmake python_linking_data 0) +pyside2_config(--pyside2-shared-libraries-cmake pyside2_shared_libraries 0) + +set(shiboken_path "${shiboken2_generator_path}/shiboken2${CMAKE_EXECUTABLE_SUFFIX}") +if(NOT EXISTS ${shiboken_path}) + message(FATAL_ERROR "Shiboken executable not found at path: ${shiboken_path}") +endif() + + +# ==================================== RPATH configuration ==================================== + + +# ============================================================================================= +# !!! (The section below is deployment related, so in a real world application you will want to +# take care of this properly with some custom script or tool). +# ============================================================================================= +# Enable rpaths so that the built shared libraries find their dependencies. +set(CMAKE_SKIP_BUILD_RPATH FALSE) +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +set(CMAKE_INSTALL_RPATH ${shiboken2_module_path} ${CMAKE_CURRENT_SOURCE_DIR}) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +# ============================================================================================= +# !!! End of dubious section. +# ============================================================================================= + + +# =============================== CMake target - wiggly_library =============================== + + +# Get all relevant Qt include dirs, to pass them on to shiboken. +get_property(QT_CORE_INCLUDE_DIRS TARGET Qt5::Core PROPERTY INTERFACE_INCLUDE_DIRECTORIES) +get_property(QT_GUI_INCLUDE_DIRS TARGET Qt5::Gui PROPERTY INTERFACE_INCLUDE_DIRECTORIES) +get_property(QT_WIDGETS_INCLUDE_DIRS TARGET Qt5::Widgets PROPERTY INTERFACE_INCLUDE_DIRECTORIES) +set(QT_INCLUDE_DIRS ${QT_CORE_INCLUDE_DIRS} ${QT_GUI_INCLUDE_DIRS} ${QT_WIDGETS_INCLUDE_DIRS}) +set(INCLUDES "") +foreach(INCLUDE_DIR ${QT_INCLUDE_DIRS}) + list(APPEND INCLUDES "-I${INCLUDE_DIR}") +endforeach() + +# On macOS, check if Qt is a framework build. This affects how include paths should be handled. +get_target_property(QtCore_is_framework Qt5::Core FRAMEWORK) +if (QtCore_is_framework) + get_target_property(qt_core_library_location Qt5::Core LOCATION) + get_filename_component(qt_core_library_location_dir "${qt_core_library_location}" DIRECTORY) + get_filename_component(lib_dir "${qt_core_library_location_dir}/../" ABSOLUTE) + list(APPEND INCLUDES "--framework-include-paths=${lib_dir}") +endif() + +# We need to include the headers for the module bindings that we use. +set(pyside2_additional_includes "") +foreach(INCLUDE_DIR ${pyside2_include_dir}) + list(APPEND pyside2_additional_includes "${INCLUDE_DIR}/QtCore") + list(APPEND pyside2_additional_includes "${INCLUDE_DIR}/QtGui") + list(APPEND pyside2_additional_includes "${INCLUDE_DIR}/QtWidgets") +endforeach() + + +# Define the wiggly shared library for which we will create bindings. +set(${wiggly_library}_sources wigglywidget.cpp) +add_library(${wiggly_library} SHARED ${${wiggly_library}_sources}) +set_property(TARGET ${wiggly_library} PROPERTY PREFIX "") + +# Needed mostly on Windows to export symbols, and create a .lib file, otherwise the binding +# library can't link to the wiggly library. +target_compile_definitions(${wiggly_library} PRIVATE BINDINGS_BUILD) + + +# ====================== Shiboken target for generating binding C++ files ==================== + + +# Set up the options to pass to shiboken. +set(shiboken_options --generator-set=shiboken --enable-parent-ctor-heuristic + --enable-pyside-extensions --enable-return-value-heuristic --use-isnull-as-nb_nonzero + --avoid-protected-hack + ${INCLUDES} + -I${CMAKE_SOURCE_DIR} + -T${CMAKE_SOURCE_DIR} + -T${pyside2_path}/typesystems + --output-directory=${CMAKE_CURRENT_BINARY_DIR} + ) + +set(generated_sources_dependencies ${wrapped_header} ${typesystem_file}) + +# Add custom target to run shiboken to generate the binding cpp files. +add_custom_command(OUTPUT ${generated_sources} + COMMAND ${shiboken_path} + ${shiboken_options} ${wrapped_header} ${typesystem_file} + DEPENDS ${generated_sources_dependencies} + #IMPLICIT_DEPENDS CXX ${wrapped_header} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Running generator for ${typesystem_file}.") + + +# =============================== CMake target - bindings_library ============================= + + +# Set the cpp files which will be used for the bindings library. +set(${bindings_library}_sources ${generated_sources}) + +# Define and build the bindings library. +add_library(${bindings_library} SHARED ${${bindings_library}_sources}) + + +# Apply relevant include and link flags. +target_include_directories(${bindings_library} PRIVATE ${pyside2_additional_includes}) +target_include_directories(${bindings_library} PRIVATE ${pyside2_include_dir}) +target_include_directories(${bindings_library} PRIVATE ${python_include_dir}) +target_include_directories(${bindings_library} PRIVATE ${shiboken_include_dir}) + +target_link_libraries(${wiggly_library} PRIVATE Qt5::Widgets) +target_link_libraries(${bindings_library} PRIVATE Qt5::Widgets) +target_link_libraries(${bindings_library} PRIVATE ${wiggly_library}) +target_link_libraries(${bindings_library} PRIVATE ${pyside2_shared_libraries}) +target_link_libraries(${bindings_library} PRIVATE ${shiboken_shared_libraries}) + +# Adjust the name of generated module. +set_property(TARGET ${bindings_library} PROPERTY PREFIX "") +set_property(TARGET ${bindings_library} PROPERTY OUTPUT_NAME + "${bindings_library}${PYTHON_EXTENSION_SUFFIX}") +if(WIN32) + set_property(TARGET ${bindings_library} PROPERTY SUFFIX ".pyd") +endif() + +# Make sure the linker doesn't complain about not finding Python symbols on macOS. +if(APPLE) + set_target_properties(${bindings_library} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") +endif(APPLE) + +# Find and link to the python import library only on Windows. +# On Linux and macOS, the undefined symbols will get resolved by the dynamic linker +# (the symbols will be picked up in the Python executable). +if (WIN32) + list(GET python_linking_data 0 python_libdir) + list(GET python_linking_data 1 python_lib) + find_library(python_link_flags ${python_lib} PATHS ${python_libdir} HINTS ${python_libdir}) + target_link_libraries(${bindings_library} PRIVATE ${python_link_flags}) +endif() + +# ================================= Dubious deployment section ================================ + +set(windows_shiboken_shared_libraries) + +if(WIN32) + # ========================================================================================= + # !!! (The section below is deployment related, so in a real world application you will + # want to take care of this properly (this is simply to eliminate errors that users usually + # encounter. + # ========================================================================================= + # Circumvent some "#pragma comment(lib)"s in "include/pyconfig.h" which might force to link + # against a wrong python shared library. + + set(python_versions_list 3 32 33 34 35 36 37 38) + set(python_additional_link_flags "") + foreach(ver ${python_versions_list}) + set(python_additional_link_flags + "${python_additional_link_flags} /NODEFAULTLIB:\"python${ver}_d.lib\"") + set(python_additional_link_flags + "${python_additional_link_flags} /NODEFAULTLIB:\"python${ver}.lib\"") + endforeach() + + set_target_properties(${bindings_library} + PROPERTIES LINK_FLAGS "${python_additional_link_flags}") + + # Compile a list of shiboken shared libraries to be installed, so that + # the user doesn't have to set the PATH manually to point to the PySide2 package. + foreach(library_path ${shiboken_shared_libraries}) + string(REGEX REPLACE ".lib$" ".dll" library_path ${library_path}) + file(TO_CMAKE_PATH ${library_path} library_path) + list(APPEND windows_shiboken_shared_libraries "${library_path}") + endforeach() + # ========================================================================================= + # !!! End of dubious section. + # ========================================================================================= +endif() + +# ============================================================================================= +# !!! (The section below is deployment related, so in a real world application you will want to +# take care of this properly with some custom script or tool). +# ============================================================================================= +# Install the library and the bindings module into the source folder near the main.py file, so +# that the Python interpeter successfully imports the used module. +install(TARGETS ${bindings_library} ${wiggly_library} + LIBRARY DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} + RUNTIME DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} + ) +install(FILES ${windows_shiboken_shared_libraries} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}) +# ============================================================================================= +# !!! End of dubious section. +# ============================================================================================= diff --git a/examples/widgetbinding/README.md b/examples/widgetbinding/README.md new file mode 100644 index 000000000..f58a49627 --- /dev/null +++ b/examples/widgetbinding/README.md @@ -0,0 +1,74 @@ +# WigglyWidget + +The original Qt/C++ example can be found here: +https://doc.qt.io/qt-5/qtwidgets-widgets-wiggly-example.html + +This example shows how to interact with a custom widget from two +different ways: + + * A full Python translation from a C++ example, + * A Python binding generated from the C++ file. + + +The original example contained three different files: + * `main.cpp/h`, which was translated to `main.py`, + * `dialog.cpp/h`, which was translated to `dialog.py`, + * `wigglywidget.cpp/h`, which was translated to `wigglywidget.py`, + but also remains as is, to enable the binding generation through + Shiboken. + +In the `dialog.py` file you will find two imports that will be related +to each of the two approaches described before:: + + + # Python translated file + from wigglywidget import WigglyWidget + + # Binding module create with Shiboken + from wiggly import WigglyWidget + + +## Steps to build the bindings + +The most important files are: + * `bindings.xml`, to specify the class that we want to expose from C++ + to Python, + * `bindings.h` to include the header of the classes we want to expose + * `CMakeList.txt`, with all the instructions to build the shared libraries + (DLL, or dylib) + * `pyside2_config.py` which is located in the utils directory, one level + up, to get the path for Shiboken and PySide. + +Now create a `build/` directory, and from inside run `cmake ..` to use +the provided `CMakeLists.txt`. +To build, just run `make`, and `make install` to copy the generated files +to the main example directory to be able to run the final example: +`python main.py`. +You should be able to see two identical custom widgets, one being the +Python translation, and the other one being the C++ one. + +### Windows + +For windows it's recommended to use either `nmake`, `jom` or `ninja`, +when running cmake. + +```bash +cmake -H.. -B. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release # for nmake +cmake -H.. -B. -G "NMake Makefiles JOM" -DCMAKE_BUILD_TYPE=Release # for jom +cmake -H.. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release # for ninja +``` + +### Linux, macOS + +Generally using `make` will be enough, but as in the Windows case, you can use +ninja to build the project. + +```bash +cmake -H.. -B. -G Ninja -DCMAKE_BUILD_TYPE=Release +``` + +## Final words + +Since this example originated by mixing the concepts of the `scriptableapplication` +and `samplebinding` examples, you can complement this README with the ones in +those directories. diff --git a/examples/widgetbinding/bindings.h b/examples/widgetbinding/bindings.h new file mode 100644 index 000000000..d59222656 --- /dev/null +++ b/examples/widgetbinding/bindings.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt for Python examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BINDINGS_H +#define BINDINGS_H +#include "wigglywidget.h" +#endif // BINDINGS_H diff --git a/examples/widgetbinding/bindings.xml b/examples/widgetbinding/bindings.xml new file mode 100644 index 000000000..07f1c89c9 --- /dev/null +++ b/examples/widgetbinding/bindings.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt for Python examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +--> +<typesystem package="wiggly"> + <load-typesystem name="typesystem_widgets.xml" generate="no"/> + <object-type name="WigglyWidget"/> +</typesystem> diff --git a/examples/widgetbinding/dialog.py b/examples/widgetbinding/dialog.py new file mode 100644 index 000000000..e52155999 --- /dev/null +++ b/examples/widgetbinding/dialog.py @@ -0,0 +1,77 @@ +############################################################################ +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## BSD License Usage +## Alternatively, you may use this file under the terms of the BSD license +## as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################ + +from PySide2.QtWidgets import QDialog, QLineEdit, QVBoxLayout + +# Python binding from the C++ widget +from wiggly import WigglyWidget as WigglyWidgetCPP + +# Python-only widget +from wigglywidget import WigglyWidget as WigglyWidgetPY + + +class Dialog(QDialog): + def __init__(self, parent=None): + super(Dialog, self).__init__(parent) + wiggly_widget_py = WigglyWidgetPY(self) + wiggly_widget_cpp = WigglyWidgetCPP(self) + lineEdit = QLineEdit(self) + + layout = QVBoxLayout(self) + layout.addWidget(wiggly_widget_py) + layout.addWidget(wiggly_widget_cpp) + layout.addWidget(lineEdit) + + lineEdit.textChanged.connect(wiggly_widget_py.setText) + lineEdit.textChanged.connect(wiggly_widget_cpp.setText) + lineEdit.setText("Hello world!") + + self.setWindowTitle("Wiggly") + self.resize(360, 145) diff --git a/examples/widgetbinding/macros.h b/examples/widgetbinding/macros.h new file mode 100644 index 000000000..224fada68 --- /dev/null +++ b/examples/widgetbinding/macros.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt for Python examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MACROS_H +#define MACROS_H + +#include <QtCore/qglobal.h> + +// Export symbols when creating .dll and .lib, and import them when using .lib. +#if BINDINGS_BUILD +# define BINDINGS_API Q_DECL_EXPORT +#else +# define BINDINGS_API Q_DECL_IMPORT +#endif + +#endif // MACROS_H diff --git a/examples/widgetbinding/main.py b/examples/widgetbinding/main.py new file mode 100644 index 000000000..556eb2638 --- /dev/null +++ b/examples/widgetbinding/main.py @@ -0,0 +1,61 @@ +############################################################################ +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## BSD License Usage +## Alternatively, you may use this file under the terms of the BSD license +## as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################ + +import sys + +from PySide2.QtWidgets import QApplication + +from dialog import Dialog + +if __name__ == "__main__": + app = QApplication() + w = Dialog() + w.show() + sys.exit(app.exec_()) diff --git a/examples/widgetbinding/wigglywidget.cpp b/examples/widgetbinding/wigglywidget.cpp new file mode 100644 index 000000000..ab549ef07 --- /dev/null +++ b/examples/widgetbinding/wigglywidget.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "wigglywidget.h" + +#include <QFontMetrics> +#include <QPainter> +#include <QTimerEvent> + +//! [0] +WigglyWidget::WigglyWidget(QWidget *parent) + : QWidget(parent), step(0) +{ + setBackgroundRole(QPalette::Midlight); + setAutoFillBackground(true); + + QFont newFont = font(); + newFont.setPointSize(newFont.pointSize() + 20); + setFont(newFont); + + timer.start(60, this); +} +//! [0] + +//! [1] +void WigglyWidget::paintEvent(QPaintEvent * /* event */) +//! [1] //! [2] +{ + static constexpr int sineTable[16] = { + 0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38 + }; + + QFontMetrics metrics(font()); + int x = (width() - metrics.horizontalAdvance(text)) / 2; + int y = (height() + metrics.ascent() - metrics.descent()) / 2; + QColor color; +//! [2] + +//! [3] + QPainter painter(this); +//! [3] //! [4] + for (int i = 0; i < text.size(); ++i) { + int index = (step + i) % 16; + color.setHsv((15 - index) * 16, 255, 191); + painter.setPen(color); + painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400), + QString(text[i])); + x += metrics.horizontalAdvance(text[i]); + } +} +//! [4] + +//! [5] +void WigglyWidget::timerEvent(QTimerEvent *event) +//! [5] //! [6] +{ + if (event->timerId() == timer.timerId()) { + ++step; + update(); + } else { + QWidget::timerEvent(event); + } +//! [6] +} diff --git a/examples/widgetbinding/wigglywidget.h b/examples/widgetbinding/wigglywidget.h new file mode 100644 index 000000000..d08db05d5 --- /dev/null +++ b/examples/widgetbinding/wigglywidget.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIGGLYWIDGET_H +#define WIGGLYWIDGET_H + +#include "macros.h" + +#include <QWidget> +#include <QBasicTimer> + +//! [0] +class BINDINGS_API WigglyWidget : public QWidget +{ + Q_OBJECT + +public: + WigglyWidget(QWidget *parent = nullptr); + +public slots: + void setText(const QString &newText) { text = newText; } + +protected: + void paintEvent(QPaintEvent *event) override; + void timerEvent(QTimerEvent *event) override; + +private: + QBasicTimer timer; + QString text; + int step; +}; +//! [0] + +#endif diff --git a/examples/widgetbinding/wigglywidget.py b/examples/widgetbinding/wigglywidget.py new file mode 100644 index 000000000..50a061074 --- /dev/null +++ b/examples/widgetbinding/wigglywidget.py @@ -0,0 +1,97 @@ +############################################################################ +## +## Copyright (C) 2020 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## Commercial License Usage +## Licensees holding valid commercial Qt licenses may use this file in +## accordance with the commercial license agreement provided with the +## Software or, alternatively, in accordance with the terms contained in +## a written agreement between you and The Qt Company. For licensing terms +## and conditions see https://www.qt.io/terms-conditions. For further +## information use the contact form at https://www.qt.io/contact-us. +## +## BSD License Usage +## Alternatively, you may use this file under the terms of the BSD license +## as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################ + +from PySide2.QtCore import QBasicTimer +from PySide2.QtGui import QColor, QFontMetrics, QPainter, QPalette +from PySide2.QtWidgets import QWidget + + +class WigglyWidget(QWidget): + def __init__(self, parent=None): + super(WigglyWidget, self).__init__(parent) + self.step = 0 + self.text = "" + self.setBackgroundRole(QPalette.Midlight) + self.setAutoFillBackground(True) + + newFont = self.font() + newFont.setPointSize(newFont.pointSize() + 20) + self.setFont(newFont) + + self.timer = QBasicTimer() + self.timer.start(60, self) + + def paintEvent(self, event): + sineTable = [0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, + -92, -71, -38] + + metrics = QFontMetrics(self.font()) + x = (self.width() - metrics.horizontalAdvance(self.text)) / 2 + y = (self.height() + metrics.ascent() - metrics.descent()) / 2 + color = QColor() + + painter = QPainter(self) + for i in range(len(self.text)): + index = (self.step + i) % 16 + color.setHsv((15 - index) * 16, 255, 191) + painter.setPen(color) + painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400), + str(self.text[i])) + x += metrics.horizontalAdvance(self.text[i]) + + def timerEvent(self, event): + if event.timerId() == self.timer.timerId(): + self.step += 1 + self.update() + else: + QWidget.timerEvent(event) + + def setText(self, text): + self.text = text |