Source code for qwt.qtdesigner

# -*- coding: utf-8 -*-
#
# Licensed under the terms of the Qwt License
# Copyright (c) 2015 Pierre Raybaut, for the Qt Designer plugin helpers
# (see LICENSE file for more details)

"""
Qt Designer
-----------

The :mod:`qwt.qtdesigner` module provides helpers to integrate :mod:`qwt`
widgets into Qt Designer:

    * :py:class:`QwtPlotWidget`
    * :py:func:`loadui`
    * :py:func:`compileui`
    * :py:func:`create_qtdesigner_plugin`

:class:`QwtPlotWidget` is a thin :class:`qwt.QwtPlot` subclass exposing the
standard Qt widget constructor (``__init__(self, parent=None)``). It is the
widget promoted by the Qt Designer plugin, so that the code generated by
``uic`` (e.g. ``QwtPlotWidget(parent=...)`` with PyQt6) instantiates it
correctly. :class:`qwt.QwtPlot` itself keeps its historical constructor.

.. note::

    Qt Designer custom widget plugins rely on
    :class:`QtDesigner.QPyDesignerCustomWidgetPlugin`, which is only available
    with PyQt5/PyQt6. PySide6 does not expose this class.

.. autoclass:: QwtPlotWidget

.. autofunction:: loadui

.. autofunction:: compileui

.. autofunction:: create_qtdesigner_plugin
"""

from __future__ import annotations

import io

from qtpy import QtGui as QG
from qtpy import uic

from qwt.plot import QwtPlot


[docs] class QwtPlotWidget(QwtPlot): """:class:`qwt.QwtPlot` widget with the standard Qt constructor. This subclass is meant to be promoted in Qt Designer: unlike :class:`qwt.QwtPlot` (whose constructor accepts the historical ``QwtPlot([title], [parent])`` overloads), it exposes the conventional ``__init__(self, parent=None)`` signature expected by the code generated by ``uic`` (notably PyQt6, which uses ``QwtPlotWidget(parent=...)``). Args: parent: Parent widget """ def __init__(self, parent=None): super().__init__(parent)
[docs] def loadui(fname: str, replace_class: str | None = None): """Return Widget or Window class from a Qt Designer ``.ui`` file. When a promoted widget inherits from a class that is not known to the ``uic`` parser (i.e. not a standard Qt widget), ``loadUiType`` fails to resolve the widget hierarchy. Passing the offending base class name as ``replace_class`` neutralizes it by substituting ``QFrame`` (the base class of :class:`qwt.QwtPlot`) before the file is parsed. For a plain :class:`qwt.QwtPlot` widget (which already inherits from ``QFrame``), no replacement is required and ``replace_class`` can be left to ``None``. Args: fname: Path to the ``.ui`` file replace_class: Base class name to replace by ``QFrame``, or ``None`` to load the file unchanged Returns: The generated form class """ with open(fname) as f: uifile_text = f.read() if replace_class is not None: uifile_text = uifile_text.replace(replace_class, "QFrame") ui, base_class = uic.loadUiType(io.StringIO(uifile_text)) class Form(base_class, ui): """Form class generated from the ``.ui`` file""" def __init__(self, parent=None): super().__init__(parent) self.setupUi(self) return Form
[docs] def compileui(fname: str, replace_class: str | None = None) -> None: """Compile a Qt Designer ``.ui`` file into a Python module. Args: fname: Path to the ``.ui`` file replace_class: Base class name to replace by ``QFrame``, or ``None`` to compile the file unchanged """ with open(fname) as f: uifile_text = f.read() if replace_class is not None: uifile_text = uifile_text.replace(replace_class, "QFrame") with open(fname.replace(".ui", "_ui.py"), "w") as pyfile: uic.compileUi(io.StringIO(uifile_text), pyfile, pyqt3_wrapper=True)
[docs] def create_qtdesigner_plugin( group: str, module_name: str, class_name: str, icon: str | QG.QIcon | None = None, tooltip: str = "", whatsthis: str = "", ): """Return a custom Qt Designer plugin class. Args: group: Name of the group the widget belongs to in Qt Designer module_name: Name of the module where the widget class is defined class_name: Name of the widget class icon: Icon shown in Qt Designer (path to an image file or :class:`QtGui.QIcon` instance) tooltip: Tool tip shown in Qt Designer whatsthis: "What's this" help text shown in Qt Designer Returns: A :class:`QtDesigner.QPyDesignerCustomWidgetPlugin` subclass Example:: Plugin = create_qtdesigner_plugin( group="PythonQwt", module_name="qwt.qtdesigner", class_name="QwtPlotWidget", ) """ from qtpy.QtDesigner import QPyDesignerCustomWidgetPlugin Widget = getattr(__import__(module_name, fromlist=[class_name]), class_name) class CustomWidgetPlugin(QPyDesignerCustomWidgetPlugin): """Qt Designer plugin for the ``%s`` widget""" % class_name def __init__(self, parent=None): QPyDesignerCustomWidgetPlugin.__init__(self) self.initialized = False def initialize(self, core): """Initialize the plugin""" if self.initialized: return self.initialized = True def isInitialized(self): """Return whether the plugin has been initialized""" return self.initialized def createWidget(self, parent): """Return a new instance of the custom widget""" return Widget(parent) def name(self): """Return the name of the custom widget class""" return class_name def group(self): """Return the name of the group the widget belongs to""" return group def icon(self): """Return the icon shown in Qt Designer""" if isinstance(icon, QG.QIcon): return icon elif isinstance(icon, str): return QG.QIcon(icon) return QG.QIcon() def toolTip(self): """Return the tool tip shown in Qt Designer""" return tooltip def whatsThis(self): """Return the "What's this" help text shown in Qt Designer""" return whatsthis def isContainer(self): """Return whether the widget is a container""" return False def domXml(self): """Return the XML used to define the widget in Qt Designer""" return f'<widget class="{class_name}" name="{class_name.lower()}" />\n' def includeFile(self): """Return the module name where the widget class is defined""" return module_name return CustomWidgetPlugin