En esta página

Extensión del menú de tareas

Creación de un complemento de widget personalizado para Qt Widgets Designer y creación de entradas de menú de tareas personalizadas asociadas al complemento.

El ejemplo de la extensión del menú de tareas muestra cómo crear un complemento de widget personalizado para Qt Widgets Designer y cómo utilizar la clase QDesignerTaskMenuExtension para proporcionar entradas de menú de tareas personalizadas asociadas al complemento.

Captura de pantalla de una acción personalizada "Editar estado..." en un menú contextual de <span translate="no">Qt Widgets</span> Designer.

Para proporcionar un widget personalizado que se pueda utilizar con Qt Widgets Designer, necesitamos proporcionar una implementación autónoma. En este ejemplo utilizamos un widget personalizado diseñado para mostrar la función de ampliación del menú de tareas: El widget TicTacToe.

Una extensión es un objeto que modifica el comportamiento de Qt Widgets Designer. QDesignerTaskMenuExtension puede proporcionar entradas de menú de tareas personalizadas cuando se selecciona un widget con esta extensión.

Hay cuatro tipos de extensiones disponibles en Qt Widgets Designer:

  • QDesignerContainerExtension proporciona una extensión que permite añadir (y eliminar) páginas a un plugin contenedor multipágina en Qt Widgets Designer.
  • QDesignerMemberSheetExtension proporciona una extensión que permite manipular las funciones miembro de un widget que se muestra al configurar conexiones utilizando el modo de edición de señales y ranuras de Qt Widgets Designer.
  • QDesignerPropertySheetExtension proporciona una extensión que permite manipular las propiedades de un widget y que se muestra en el editor de propiedades de Qt Widgets Designer.
  • QDesignerTaskMenuExtension proporciona una extensión que permite añadir entradas de menú personalizadas al menú de tareas de Qt Widgets Designer.

Puedes utilizar todas las extensiones siguiendo el mismo patrón que en este ejemplo, sólo que sustituyendo la clase base de la extensión correspondiente. Para más información, consulte la página Qt Widgets Designer C++ Classes.

El ejemplo de extensión del menú de tareas consta de cinco clases:

  • TicTacToe es un widget personalizado que permite al usuario jugar al juego Tic-Tac-Toe.
  • TicTacToePlugin expone la clase TicTacToe a Qt Widgets Designer.
  • TicTacToeTaskMenuFactory crea un objeto TicTacToeTaskMenu.
  • TicTacToeTaskMenu proporciona la extensión del menú de tareas, es decir, las entradas del menú de tareas asociadas al complemento.
  • TicTacToeDialog permite al usuario modificar el estado de un complemento Tic-Tac-Toe cargado en Qt Widgets Designer.

El archivo de proyecto para los plugins de widgets personalizados necesita alguna información adicional para asegurar que funcionarán dentro de Qt Widgets Designer. Por ejemplo, los plugins de widgets personalizados dependen de componentes suministrados con Qt Widgets Designer, y esto debe especificarse en el archivo de proyecto que utilicemos. Primero echaremos un vistazo al archivo de proyecto del plugin.

Luego continuaremos revisando la clase TicTacToePlugin, y echaremos un vistazo a las clases TicTacToeTaskMenuFactory y TicTacToeTaskMenu. Por último, revisaremos la clase TicTacToeDialog antes de echar un vistazo rápido a la definición de clase del widget TicTacToe.

Archivos del proyecto

CMake

Los archivos del proyecto necesitan indicar que se va a construir un plugin que enlace con las librerías Qt Widgets Designer:

find_package(Qt6 REQUIRED COMPONENTS Core Designer Gui Widgets)

qt_add_plugin(taskmenuextension)

target_link_libraries(taskmenuextension PUBLIC
    Qt::Core
    Qt::Designer
    Qt::Gui
    Qt::Widgets
)

El siguiente ejemplo muestra cómo añadir los archivos de cabecera y fuente del widget:

target_sources(taskmenuextension PRIVATE
    tictactoe.cpp tictactoe.h
    tictactoedialog.cpp tictactoedialog.h
    tictactoeplugin.cpp tictactoeplugin.h
    tictactoetaskmenu.cpp tictactoetaskmenu.h
)

Proporcionamos una implementación de la interfaz del plugin para que Qt Widgets Designer pueda utilizar el widget personalizado. En este ejemplo en particular también proporcionamos implementaciones de la extensión del menú de tareas y de la fábrica de extensiones, así como una implementación del diálogo.

Es importante asegurarse de que el plugin se instala en una ubicación que sea buscada por Qt Widgets Designer. Esto se consigue especificando una ruta de destino para el proyecto y añadiéndolo a la lista de elementos a instalar:

   set(INSTALL_EXAMPLEDIR "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_PLUGINS}/designer")
install(TARGETS taskmenuextension
    RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
    BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
    LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

La extensión del menú de tareas se crea como una biblioteca. Se instalará junto con los demás plugins de Qt Widgets Designer cuando se instale el proyecto (mediante ninja install o un procedimiento de instalación equivalente).

Para más información sobre plugins, consulte la documentación Cómo crear plugins de Qt.

qmake

El siguiente ejemplo muestra cómo vincular un plugin a las librerías Qt Widgets Designer:

TEMPLATE = lib
CONFIG  += plugin

QT      += widgets designer

El siguiente ejemplo muestra cómo añadir los archivos de cabecera y fuente del widget:

HEADERS += tictactoe.h \
           tictactoedialog.h \
           tictactoeplugin.h \
           tictactoetaskmenu.h
SOURCES += tictactoe.cpp \
           tictactoedialog.cpp \
           tictactoeplugin.cpp \
           tictactoetaskmenu.cpp
OTHER_FILES += tictactoe.json

El siguiente ejemplo muestra cómo instalar un plugin en la ruta de plugins de Qt Widgets Designer:

target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target

Definición de la clase TicTacToePlugin

La clase TicTacToePlugin expone la clase the TicTacToe a Qt Widgets Designer. Su definición es equivalente a la clase plugin del ejemplo Custom Widget Plugin que se explica en detalle. La única parte de la definición de la clase que es específica para este widget personalizado en particular es el nombre de la clase.

Para asegurar que Qt reconoce el widget como un plugin, exporta la información relevante sobre el widget añadiendo la macro Q_PLUGIN_METADATA():

#ifndef TICTACTOEPLUGIN_H
#define TICTACTOEPLUGIN_H

#include <QtUiPlugin/QDesignerCustomWidgetInterface>

class QIcon;
class QWidget;

class TicTacToePlugin : public QObject, public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")
    Q_INTERFACES(QDesignerCustomWidgetInterface)

public:
    explicit TicTacToePlugin(QObject *parent = nullptr);

    QString name() const override;
    QString group() const override;
    QString toolTip() const override;
    QString whatsThis() const override;
    QString includeFile() const override;
    QIcon icon() const override;
    bool isContainer() const override;
    QWidget *createWidget(QWidget *parent) override;
    bool isInitialized() const override;
    void initialize(QDesignerFormEditorInterface *formEditor) override;
    QString domXml() const override;

private:
    bool initialized = false;
};

#endif

La clase plugin proporciona a Qt Widgets Designer información básica sobre nuestro plugin, como su nombre de clase y su archivo de inclusión. Además, sabe cómo crear instancias del widget TicTacToe. TicTacToePlugin también define la función initialize() que se llama después de cargar el plugin en Qt Widgets Designer. El parámetro QDesignerFormEditorInterface de la función proporciona al plugin una puerta de acceso a todas las API de Qt Widgets Designer.

La clase TicTacToePlugin hereda tanto de QObject como de QDesignerCustomWidgetInterface. Es importante recordar, cuando se utiliza herencia múltiple, asegurarse de que todas las interfaces (es decir, las clases que no heredan de Q_OBJECT) se dan a conocer al meta sistema de objetos utilizando la macro Q_INTERFACES(). Esto permite a Qt Widgets Designer utilizar qobject_cast() para buscar interfaces compatibles utilizando únicamente un puntero QObject.

Implementación de la clase TicTacToePlugin

La implementación de la clase TicTacToePlugin es en su mayor parte equivalente a la clase plugin del ejemplo Custom Widget Plugin:

TicTacToePlugin::TicTacToePlugin(QObject *parent)
    : QObject(parent)
{
}

QString TicTacToePlugin::name() const
{
    return u"TicTacToe"_s;
}

QString TicTacToePlugin::group() const
{
    return u"Display Widgets [Examples]"_s;
}

QString TicTacToePlugin::toolTip() const
{
    return u"Tic Tac Toe Example, demonstrating class QDesignerTaskMenuExtension (C++)"_s;
}

QString TicTacToePlugin::whatsThis() const
{
    return {};
}

QString TicTacToePlugin::includeFile() const
{
    return u"tictactoe.h"_s;
}

QIcon TicTacToePlugin::icon() const
{
    return {};
}

bool TicTacToePlugin::isContainer() const
{
    return false;
}

QWidget *TicTacToePlugin::createWidget(QWidget *parent)
{
    auto *ticTacToe = new TicTacToe(parent);
    ticTacToe->setState(u"-X-XO----"_s);
    return ticTacToe;
}

bool TicTacToePlugin::isInitialized() const
{
    return initialized;
}

La única función que difiere significativamente es la función initialize():

void TicTacToePlugin::initialize(QDesignerFormEditorInterface *formEditor)
{

La función initialize() toma un objeto QDesignerFormEditorInterface como argumento. La clase QDesignerFormEditorInterface proporciona acceso a los componentes de Qt Widgets Designer.

En Qt Widgets Designer se pueden crear dos tipos de plugins: plugins de widgets personalizados y plugins de herramientas. QDesignerFormEditorInterface proporciona acceso a todos los componentes de Qt Widgets Designer que normalmente se necesitan para crear un plugin de herramientas: el gestor de extensiones, el inspector de objetos, el editor de propiedades y el cuadro de widgets. Los plugins de widgets personalizados tienen acceso a los mismos componentes.

    if (initialized)
        return;

    auto *manager = formEditor->extensionManager();
    Q_ASSERT(manager != nullptr);

Cuando creamos extensiones asociadas con plugins de widgets personalizados, necesitamos acceder al gestor de extensiones actual de Qt Widgets Designer que recuperamos del parámetro QDesignerFormEditorInterface.

Qt Widgets QDesignerFormEditorInterface de Designer contiene información sobre todos los componentes de Qt Designer: El editor de acciones, el inspector de objetos, el editor de propiedades, la caja de widgets y los gestores de extensiones y ventanas de formulario.

La clase QExtensionManager proporciona facilidades de gestión de extensiones para Qt Widgets Designer. Utilizando el gestor de extensiones actual de Qt Widgets Designer puede recuperar la extensión de un objeto determinado. También puede registrar y anular el registro de una extensión para un objeto determinado. Recuerde que una extensión es un objeto que modifica el comportamiento de Qt Widgets Designer.

Al registrar una extensión, en realidad lo que se registra es la fábrica de extensiones asociada. En Qt Widgets Designer, las fábricas de extensiones se utilizan para buscar y crear extensiones con nombre a medida que se necesitan. Así, en este ejemplo, la extensión del menú de tareas no se crea hasta que el usuario solicita un menú de tareas.

    manager->registerExtensions(new TicTacToeTaskMenuFactory(manager),
                                Q_TYPEID(QDesignerTaskMenuExtension));

    initialized = true;
}

QString TicTacToePlugin::domXml() const
{
    return uR"(
<ui language="c++">
    <widget class="TicTacToe" name="ticTacToe"/>
    <customwidgets>
        <customwidget>
            <class>TicTacToe</class>
            <propertyspecifications>
            <tooltip name="state">Tic Tac Toe state</tooltip>
            <stringpropertyspecification name="state" notr="true" type="singleline"/>
            </propertyspecifications>
        </customwidget>
    </customwidgets>
</ui>
)"_s;
}

Creamos un objeto TicTacToeTaskMenuFactory que registramos utilizando el extension manager actual de Qt Widgets Designer recuperado del parámetro QDesignerFormEditorInterface. El primer argumento es la fábrica recién creada y el segundo argumento es un identificador de extensión que es una cadena. La macro Q_TYPEID() simplemente convierte la cadena en un QLatin1String.

La clase TicTacToeTaskMenuFactory es una subclase de QExtensionFactory. Cuando el usuario solicita un menú de tareas pulsando el botón derecho del ratón sobre un widget con la extensión de menú de tareas especificada, el gestor de extensiones de Qt Widgets Designer recorrerá todas sus fábricas registradas invocando a la primera que sea capaz de crear una extensión de menú de tareas para el widget seleccionado. Esta fábrica creará a su vez un objeto TicTacToeTaskMenu (la extensión).

Omitimos reimplementar la función QDesignerCustomWidgetInterface::domXml() (que incluye valores por defecto para el widget en el formato XML estándar utilizado por Qt Widgets Designer), ya que no son necesarios valores por defecto.

    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")

Por último, utilizamos la macro Q_PLUGIN_METADATA() para exportar la clase TicTacToePlugin para su uso con las clases de gestión de plugins de Qt: Esta macro asegura que Qt Widgets Designer pueda acceder y construir el widget personalizado. Sin esta macro, no hay forma de que Qt Widgets Designer utilice el widget.

Definición de la Clase TicTacToeTaskMenuFactory

La clase TicTacToeTaskMenuFactory hereda de QExtensionFactory que proporciona una fábrica de extensión estándar para Qt Widgets Designer.

class TicTacToeTaskMenuFactory : public QExtensionFactory
{
    Q_OBJECT

public:
    explicit TicTacToeTaskMenuFactory(QExtensionManager *parent = nullptr);

protected:
    QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const override;
};

El propósito de la subclase es reimplementar la función QExtensionFactory::createExtension(), haciéndola capaz de crear una extensión del menú de tareas TicTacToe.

Implementación de la clase TicTacToeTaskMenuFactory

El constructor de la clase simplemente llama al constructor de la clase base QExtensionFactory:

TicTacToeTaskMenuFactory::TicTacToeTaskMenuFactory(QExtensionManager *parent)
    : QExtensionFactory(parent)
{
}

Como se ha descrito anteriormente, la fábrica se invoca cuando el usuario solicita un menú de tareas haciendo clic con el botón derecho del ratón sobre un widget con la extensión de menú de tareas especificada en Qt Widgets Designer.

Qt Widgets El comportamiento de Designer es el mismo tanto si la extensión solicitada está asociada a un contenedor, una hoja de miembros, una hoja de propiedades o un menú de tareas: Su gestor de extensiones recorre todas sus fábricas de extensiones registradas llamando a createExtension() para cada una de ellas hasta que una responde creando la extensión solicitada.

QObject *TicTacToeTaskMenuFactory::createExtension(QObject *object,
                                                   const QString &iid,
                                                   QObject *parent) const
{
    if (iid != Q_TYPEID(QDesignerTaskMenuExtension))
        return nullptr;

    if (auto *tic = qobject_cast<TicTacToe*>(object))
        return new TicTacToeTaskMenu(tic, parent);

    return nullptr;
}

Así que lo primero que hacemos en TicTacToeTaskMenuFactory::createExtension() es comprobar si la extensión solicitada es una extensión del menú de tareas. Si lo es, y el widget que la solicita es un widget TicTacToe, creamos y devolvemos un objeto TicTacToeTaskMenu. En caso contrario, simplemente devolvemos un puntero nulo, permitiendo al gestor de extensiones de Qt Widgets Designer continuar su búsqueda a través de las fábricas registradas.

Definición de la clase TicTacToeTaskMenu

Captura de pantalla que muestra todas las opciones para cambiar un widget en el editor de IU

La clase TicTacToeTaskMenu hereda de QDesignerTaskMenuExtension que permite añadir entradas personalizadas (en forma de QActions) al menú de tareas en Qt Widgets Designer.

class TicTacToeTaskMenu : public QObject, public QDesignerTaskMenuExtension
{
    Q_OBJECT
    Q_INTERFACES(QDesignerTaskMenuExtension)

public:
    explicit TicTacToeTaskMenu(TicTacToe *tic, QObject *parent);

    QAction *preferredEditAction() const override;
    QList<QAction *> taskActions() const override;

private slots:
    void editState();

private:
    QAction *editStateAction;
    TicTacToe *ticTacToe;
};

Reimplementamos las funciones preferredEditAction() y taskActions(). Observa que implementamos un constructor que toma dos argumentos: el widget padre, y el widget TicTacToe para el que se solicita el menú de tareas.

Además declaramos el slot privado editState(), nuestro editStateAction personalizado y un puntero privado al widget TicTacToe cuyo estado queremos modificar.

Implementación de la Clase TicTacToeTaskMenu

TicTacToeTaskMenu::TicTacToeTaskMenu(TicTacToe *tic, QObject *parent)
    : QObject(parent)
    , editStateAction(new QAction(tr("Edit State..."), this))
    , ticTacToe(tic)
{
    connect(editStateAction, &QAction::triggered, this, &TicTacToeTaskMenu::editState);
}

En el constructor guardamos primero la referencia al widget TicTacToe enviado como parámetro, es decir, el widget cuyo estado queremos modificar. Lo necesitaremos más tarde cuando se invoque nuestra acción personalizada. También creamos nuestro editStateAction personalizado y lo conectamos a la ranura editState().

void TicTacToeTaskMenu::editState()
{
    TicTacToeDialog dialog(ticTacToe);
    dialog.exec();
}

La ranura editState() se llama cada vez que el usuario elige la opción Editar estado... en el menú de tareas de un widget TicTacToe. La ranura crea un TicTacToeDialog que presenta el estado actual del widget, y permite al usuario editar su estado jugando al juego.

QAction *TicTacToeTaskMenu::preferredEditAction() const
{
    return editStateAction;
}

Reimplementamos la función preferredEditAction() para devolver nuestro editStateAction personalizado como la acción que debe invocarse al seleccionar un widget TicTacToe y pulsar F2.

QList<QAction *> TicTacToeTaskMenu::taskActions() const
{
    return QList<QAction *>{editStateAction};
}

Reimplementamos la función taskActions() para devolver una lista de nuestras acciones personalizadas haciendo que éstas aparezcan sobre las entradas del menú por defecto en el menú de tareas de un widget TicTacToe.

Definición de la clase TicTacToeDialog

Captura de pantalla que muestra el modo de estado de edición de un widget

La clase TicTacToeDialog hereda de QDialog. El diálogo permite al usuario modificar el estado del plugin Tic-Tac-Toe actualmente seleccionado.

class TicTacToeDialog : public QDialog
{
    Q_OBJECT

public:
    explicit TicTacToeDialog(TicTacToe *plugin = nullptr, QWidget *parent = nullptr);

    QSize sizeHint() const override;

private slots:
    void resetState();
    void saveState();

private:
    TicTacToe *editor;
    TicTacToe *ticTacToe;
    QDialogButtonBox *buttonBox;
};

Reimplementamos la función sizeHint(). También declaramos dos ranuras privadas: resetState() y saveState(). Además de los botones y diseños del diálogo declaramos dos punteros TicTacToe, uno al widget con el que el usuario puede interactuar y el otro al plugin widget personalizado original cuyo estado el usuario desea editar.

Implementación de la clase TicTacToeDialog

TicTacToeDialog::TicTacToeDialog(TicTacToe *tic, QWidget *parent)
    : QDialog(parent)
    , editor(new TicTacToe)
    , ticTacToe(tic)
    , buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok
                                     | QDialogButtonBox::Cancel
                                     | QDialogButtonBox::Reset))
{
    editor->setState(ticTacToe->state());

    connect(buttonBox->button(QDialogButtonBox::Reset), &QAbstractButton::clicked,
            this, &TicTacToeDialog::resetState);
    connect(buttonBox, &QDialogButtonBox::accepted, this, &TicTacToeDialog::saveState);
    connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);

    auto *mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(editor);
    mainLayout->addWidget(buttonBox);

    setWindowTitle(tr("Edit State"));
}

En el constructor primero guardamos la referencia al widget TicTacToe enviado como parámetro, es decir, el widget cuyo estado quiere modificar el usuario. Después creamos un nuevo widget TicTacToe, y establecemos su estado para que sea equivalente al estado del widget parámetro.

Por último, creamos los botones y el diseño del diálogo.

QSize TicTacToeDialog::sizeHint() const
{
    return {250, 250};
}

Reimplementamos la función sizeHint() para garantizar que el diálogo tenga un tamaño razonable.

void TicTacToeDialog::resetState()
{
    editor->clearBoard();
}

La ranura resetState() es llamada cada vez que el usuario pulsa el botón Reset. Lo único que hacemos es llamar a la función clearBoard() para el widget del editor, es decir, el widget TicTacToe que creamos en el constructor del diálogo.

void TicTacToeDialog::saveState()
{

La función saveState() es llamada cada vez que el usuario pulsa el botón Aceptar, y transfiere el estado del widget editor al widget cuyo estado queremos modificar. Para que el cambio de estado sea visible para Qt Widgets Designer necesitamos establecer la propiedad state de este último widget utilizando la clase QDesignerFormWindowInterface.

QDesignerFormWindowInterface te proporciona información sobre la ventana de formulario asociada, además de permitirte modificar sus propiedades. La interfaz no está pensada para ser instanciada directamente, sino para proporcionar acceso a las ventanas de formulario actuales de Qt Widgets Designer controladas por el gestor de ventanas de formulario de Qt Widgets Designer.

Si estás buscando la ventana de formulario que contiene un widget específico, puedes usar la función estática QDesignerFormWindowInterface::findFormWindow():

    if (auto *formWindow = QDesignerFormWindowInterface::findFormWindow(ticTacToe))
        formWindow->cursor()->setProperty("state", editor->state());

Después de recuperar la ventana de formulario del widget (cuyo estado queremos modificar), utilizamos la función QDesignerFormWindowInterface::cursor() para recuperar el cursor de la ventana de formulario.

La clase QDesignerFormWindowCursorInterface proporciona una interfaz para el cursor de texto de la ventana de formulario. Una vez que tenemos el cursor, podemos finalmente establecer la propiedad state usando la función QDesignerFormWindowCursorInterface::setProperty().

    accept();
}

Al final llamamos a la función QEvent::accept() que establece la bandera de aceptación del objeto evento. Establecer el parámetro accept indica que el receptor del evento quiere el evento. Los eventos no deseados pueden ser propagados al widget padre.

Definición de la clase TicTacToe

La clase TicTacToe es un widget personalizado que permite al usuario jugar al juego Tic-Tac-Toe.

class TicTacToe : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QString state READ state WRITE setState)

public:
    explicit TicTacToe(QWidget *parent = nullptr);

    QSize minimumSizeHint() const override;
    QSize sizeHint() const override;
    void setState(const QString &newState);
    QString state() const;
    void clearBoard();

protected:
    void mousePressEvent(QMouseEvent *event) override;
    void paintEvent(QPaintEvent *event) override;

private:
    static constexpr char16_t Empty = '-';
    static constexpr char16_t Cross = 'X';
    static constexpr char16_t Nought = 'O';

    QRect cellRect(int position) const;
    int cellWidth() const { return width() / 3; }
    int cellHeight() const { return height() / 3; }

    QString myState;
    int turnNumber = 0;
};

Los principales detalles a observar en la definición de la clase TicTacToe es la declaración de la propiedad state y sus funciones state() y setState().

Necesitamos declarar el estado del widget TicTacToe como una propiedad para hacerlo visible a Qt Widgets Designer; permitiendo a Qt Widgets Designer gestionarlo de la misma forma que gestiona las propiedades que el widget TicTacToe hereda de QWidget y QObject, por ejemplo presentando el editor de propiedades.

Proyecto de ejemplo @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.