Table of Contents
- Task Menu Extension Example
- The Project File: taskmenuextension.pro
- TicTacToePlugin Class Definition
- TicTacToePlugin Class Implementation
- TicTacToeTaskMenuFactory Class Definition
- TicTacToeTaskMenuFactory Class Implementation
- TicTacToeTaskMenu Class Definition
- TicTacToeTaskMenu Class Implementation
- TicTacToeDialog Class Definition
- TicTacToeDialog Class Implementation
- TicTacToe Class Definition
Previous topic
Next topic
Quick search
Task Menu Extension Example¶
Creating a custom widget plugin for Qt Designer and providing custom task menu entries that are associated with the plugin.
The Task Menu Extension example shows how to create a custom widget plugin for Qt Designer :ref:` <Qt-Designer-Manual>` , and how to to use the QDesignerTaskMenuExtension
class to provide custom task menu entries associated with the plugin.
To provide a custom widget that can be used with Qt Designer, we need to supply a self-contained implementation. In this example we use a custom widget designed to show the task menu extension feature: The TicTacToe widget.
An extension is an object which modifies the behavior of Qt Designer. The QDesignerTaskMenuExtension
can provide custom task menu entries when a widget with this extension is selected.
There are four available types of extensions in Qt Designer:
QDesignerContainerExtension
provides an extension that allows you to add (and delete) pages to a multi-page container plugin in Qt Designer.
QDesignerMemberSheetExtension
provides an extension that allows you to manipulate a widget’s member functions which is displayed when configuring connections using Qt Designer’s mode for editing signals and slots.
QDesignerPropertySheetExtension
provides an extension that allows you to manipulate a widget’s properties which is displayed in Qt Designer’s property editor.
QDesignerTaskMenuExtension
provides an extension that allows you to add custom menu entries to Qt Designer's task menu.
You can use all the extensions following the same pattern as in this example, only replacing the respective extension base class. For more information, see the Qt Designer C++ Classes .
The Task Menu Extension example consists of five classes:
TicTacToe
is a custom widget that lets the user play the Tic-Tac-Toe game.
TicTacToePlugin
exposes theTicTacToe
class to Qt Designer.
TicTacToeTaskMenuFactory
creates aTicTacToeTaskMenu
object.
TicTacToeTaskMenu
provides the task menu extension, i.e the plugin’s associated task menu entries.
TicTacToeDialog
lets the user modify the state of a Tic-Tac-Toe plugin loaded into Qt Designer.
The project file for custom widget plugins needs some additional information to ensure that they will work within Qt Designer. For example, custom widget plugins rely on components supplied with Qt Designer, and this must be specified in the project file that we use. We will first take a look at the plugin’s project file.
Then we will continue by reviewing the TicTacToePlugin
class, and take a look at the TicTacToeTaskMenuFactory
and TicTacToeTaskMenu
classes. Finally, we will review the TicTacToeDialog
class before we take a quick look at the TicTacToe
widget’s class definition.
The Project File: taskmenuextension.pro¶
The project file must contain some additional information to ensure that the plugin will work as expected:
<Code snippet "taskmenuextension/taskmenuextension.pro:0" not found> <Code snippet "taskmenuextension/taskmenuextension.pro:1" not found>
The TEMPLATE
variable’s value makes qmake
create the custom widget as a library. Later, we will ensure that the widget will be recognized as a plugin by Qt by using the Q_PLUGIN_METADATA()
macro to export the relevant widget information.
The CONFIG
variable is set to plugin
, which ensures that qmake
considers the custom widget a plugin library.
The QT
variable contains the value designer
. Since the plugin uses components supplied with Qt Designer that require linkage, this value ensures that our plugin links against Qt Designer's library (libQtDesigner.so
).
The header and source files for the widget are declared in the usual way:
<Code snippet "taskmenuextension/taskmenuextension.pro:2" not found>
We provide an implementation of the plugin interface so that Qt Designer can use the custom widget. In this particular example we also provide implementations of the task menu extension and the extension factory as well as a dialog implementation.
It is important to ensure that the plugin is installed in a location that is searched by Qt Designer. We do this by specifying a target path for the project and adding it to the list of items to install:
<Code snippet "doc/snippets/doc_src_examples_taskmenuextension.pro:0" not found>
The task menu extension is created as a library, and will be installed alongside the other Qt Designer plugins when the project is installed (using make install
or an equivalent installation procedure).
Note that if you want the plugins to appear in a Visual Studio integration, the plugins must be built in release mode and their libraries must be copied into the plugin directory in the install path of the integration (for an example, see C:/program files/trolltech as/visual studio integration/plugins
).
For more information about plugins, see the How to Create Qt Plugins documentation.
TicTacToePlugin Class Definition¶
The TicTacToePlugin
class exposes the
TicTacToe class to Qt Designer. Its definition is equivalent to the Custom Widget Plugin example’s plugin class which is explained in detail. The only part of the class definition that is specific to this particular custom widget is the class name:
#ifndef TICTACTOEPLUGIN_H #define TICTACTOEPLUGIN_H QT_BEGIN_NAMESPACE class QIcon(): class QWidget(): QT_END_NAMESPACE class TicTacToePlugin(QObject, QDesignerCustomWidgetInterface): Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface") Q_INTERFACES(QDesignerCustomWidgetInterface) # public TicTacToePlugin = explicit(QObject parent = None) name = QString() group = QString() toolTip = QString() whatsThis = QString() includeFile = QString() icon = QIcon() isContainer = bool() createWidget = QWidget(QWidget parent) isInitialized = bool() def initialize(formEditor): domXml = QString() # private initialized = False() #endif
The plugin class provides Qt Designer with basic information about our plugin, such as its class name and its include file. Furthermore it knows how to create instances of the TicTacToe
widget. TicTacToePlugin also defines the initialize()
function which is called after the plugin is loaded into Qt Designer. The function’s QDesignerFormEditorInterface
parameter provides the plugin with a gateway to all of Qt Designer's API’s.
The TicTacToePlugin
class inherits from both QObject
and QDesignerCustomWidgetInterface
. It is important to remember, when using multiple inheritance, to ensure that all the interfaces (i.e. the classes that doesn’t inherit Q_OBJECT
) are made known to the meta object system using the Q_INTERFACES()
macro. This enables Qt Designer to use qobject_cast()
to query for supported interfaces using nothing but a QObject
pointer.
TicTacToePlugin Class Implementation¶
The TicTacToePlugin class implementation is in most parts equivalent to the Custom Widget Plugin example’s plugin class:
def __init__(self, parent): QObject.__init__(self, parent) def name(self): def QStringLiteral("TicTacToe"): def group(self): def QStringLiteral([Examples]"): def toolTip(self): def QStringLiteral(Example,(C++)"): def whatsThis(self): def QString(): def includeFile(self): def QStringLiteral("tictactoe.h"): def icon(self): def QIcon(): def isContainer(self): return False TicTacToePlugin::createWidget = QWidget(QWidget parent) ticTacToe = TicTacToe(parent) ticTacToe.setState(QStringLiteral("-X-XO----")) return ticTacToe def isInitialized(self): return initialized
The only function that differs significantly is the initialize() function:
def initialize(self, formEditor):
The initialize()
function takes a QDesignerFormEditorInterface
object as argument. The QDesignerFormEditorInterface
class provides access to Qt Designer’s components.
In Qt Designer you can create two kinds of plugins: custom widget plugins and tool plugins. QDesignerFormEditorInterface
provides access to all the Qt Designer components that you normally need to create a tool plugin: the extension manager, the object inspector, the property editor and the widget box. Custom widget plugins have access to the same components.
if (initialized) return manager = formEditor.extensionManager() Q_ASSERT(manager != 0)
When creating extensions associated with custom widget plugins, we need to access Qt Designer's current extension manager which we retrieve from the QDesignerFormEditorInterface
parameter.
Qt Designer's QDesignerFormEditorInterface
holds information about all Qt Designer’s components: The action editor, the object inspector, the property editor, the widget box, and the extension and form window managers.
The QExtensionManager
class provides extension management facilities for Qt Designer. Using Qt Designer's current extension manager you can retrieve the extension for a given object. You can also register and unregister an extension for a given object. Remember that an extension is an object which modifies the behavior of Qt Designer.
When registrering an extension, it is actually the associated extension factory that is registered. In Qt Designer, extension factories are used to look up and create named extensions as they are required. So, in this example, the task menu extension itself is not created until a task menu is requested by the user.
manager.registerExtensions(TicTacToeTaskMenuFactory(manager), Q_TYPEID(QDesignerTaskMenuExtension)) initialized = True def domXml(self): return QLatin1String(R"( <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> )")
We create a TicTacToeTaskMenuFactory
object that we register using Qt Designer's current extension manager
retrieved from the QDesignerFormEditorInterface
parameter. The first argument is the newly created factory and the second argument is an extension identifier which is a string. The Q_TYPEID()
macro simply converts the string into a QLatin1String
.
The TicTacToeTaskMenuFactory
class is a subclass of QExtensionFactory
. When the user request a task menu by clicking the right mouse button over a widget with the specified task menu extension, Qt Designer's extension manager will run through all its registered factories invoking the first one that is able to create a task menu extension for the selected widget. This factory will in turn create a TicTacToeTaskMenu
object (the extension).
We omit to reimplement the domXml()
function (which include default settings for the widget in the standard XML format used by Qt Designer), since no default values are necessary.
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface")
Finally, we use the Q_PLUGIN_METADATA()
macro to export the TicTacToePlugin class for use with Qt’s plugin handling classes: This macro ensures that Qt Designer can access and construct the custom widget. Without this macro, there is no way for Qt Designer to use the widget.
TicTacToeTaskMenuFactory Class Definition¶
The TicTacToeTaskMenuFactory
class inherits QExtensionFactory
which provides a standard extension factory for Qt Designer.
class TicTacToeTaskMenuFactory(QExtensionFactory): Q_OBJECT # public TicTacToeTaskMenuFactory = explicit(QExtensionManager parent = None) protected: createExtension = QObject(QObject object, QString iid, QObject parent)
The subclass’s purpose is to reimplement the createExtension()
function, making it able to create a TicTacToe
task menu extension.
TicTacToeTaskMenuFactory Class Implementation¶
The class constructor simply calls the QExtensionFactory
base class constructor:
def __init__(self, parent): QExtensionFactory.__init__(self, parent)
As described above, the factory is invoked when the user request a task menu by clicking the right mouse button over a widget with the specified task menu extension in Qt Designer.
Qt Designer's behavior is the same whether the requested extension is associated with a container, a member sheet, a property sheet or a task menu: Its extension manager runs through all its registered extension factories calling createExtension()
for each until one responds by creating the requested extension.
TicTacToeTaskMenuFactory::createExtension(QObject = QObject() iid, = QString() parent) = QObject() if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) return None if (TicTacToe tic = TicTacToe(object)) def TicTacToeTaskMenu(tic,parent): return None
So the first thing we do in TicTacToeTaskMenuFactory::createExtension()
is to check if the requested extension is a task menu extension. If it is, and the widget requesting it is a TicTacToe
widget, we create and return a TicTacToeTaskMenu
object. Otherwise, we simply return a null pointer, allowing Qt Designer's extension manager to continue its search through the registered factories.
TicTacToeTaskMenu Class Definition¶
The TicTacToeTaskMenu
class inherits QDesignerTaskMenuExtension
which allows you to add custom entries (in the form of QActions) to the task menu in Qt Designer.
class TicTacToeTaskMenu(QObject, QDesignerTaskMenuExtension): Q_OBJECT Q_INTERFACES(QDesignerTaskMenuExtension) # public TicTacToeTaskMenu = explicit(TicTacToe tic, QObject parent) preferredEditAction = QAction() *> = QList<QAction() slots: = private() def editState(): # private editStateAction = QAction() ticTacToe = TicTacToe()
We reimplement the preferredEditAction()
and taskActions()
functions. Note that we implement a constructor that takes two arguments: the parent widget, and the TicTacToe
widget for which the task menu is requested.
In addition we declare the private editState()
slot, our custom editStateAction
and a private pointer to the TicTacToe
widget which state we want to modify.
TicTacToeTaskMenu Class Implementation¶
def __init__(self, tic, parent): QObject.__init__(self, parent) , editStateAction(QAction(tr("Edit State..."), self)) , ticTacToe(tic) connect(editStateAction, QAction.triggered, self, TicTacToeTaskMenu.editState)
In the constructor we first save the reference to the TicTacToe
widget sent as parameter, i.e the widget which state we want to modify. We will need this later when our custom action is invoked. We also create our custom editStateAction
and connect it to the editState()
slot.
def editState(self): dialog = TicTacToeDialog(ticTacToe) dialog.exec()
The editState()
slot is called whenever the user chooses the Edit State… option in a TicTacToe
widget’s task menu. The slot creates a TicTacToeDialog
presenting the current state of the widget, and allowing the user to edit its state by playing the game.
TicTacToeTaskMenu::preferredEditAction = QAction() return editStateAction
We reimplement the preferredEditAction()
function to return our custom editStateAction
as the action that should be invoked when selecting a TicTacToe
widget and pressing F2 .
QList<QAction *> TicTacToeTaskMenu::taskActions() return QList<QAction *>{editStateAction}
We reimplement the taskActions()
function to return a list of our custom actions making these appear on top of the default menu entries in a TicTacToe
widget’s task menu.
TicTacToeDialog Class Definition¶
The TicTacToeDialog
class inherits QDialog
. The dialog lets the user modify the state of the currently selected Tic-Tac-Toe plugin.
class TicTacToeDialog(QDialog): Q_OBJECT # public TicTacToeDialog = explicit(TicTacToe plugin = None, QWidget parent = None) sizeHint = QSize() slots: = private() def resetState(): def saveState(): # private editor = TicTacToe() ticTacToe = TicTacToe() buttonBox = QDialogButtonBox()
We reimplement the sizeHint()
function. We also declare two private slots: resetState()
and saveState()
. In addition to the dialog’s buttons and layouts we declare two TicTacToe
pointers, one to the widget the user can interact with and the other to the original custom widget plugin which state the user wants to edit.
TicTacToeDialog Class Implementation¶
def __init__(self, tic, parent): QDialog.__init__(self, parent) , editor(TicTacToe) , ticTacToe(tic) , buttonBox(QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel | QDialogButtonBox.Reset)) editor.setState(ticTacToe.state()) connect(buttonBox.button(QDialogButtonBox.Reset), QAbstractButton.clicked, self, TicTacToeDialog::resetState) connect(buttonBox, QDialogButtonBox.accepted, self, TicTacToeDialog.saveState) connect(buttonBox, QDialogButtonBox.rejected, self, QDialog.reject) mainLayout = QVBoxLayout(self) mainLayout.addWidget(editor) mainLayout.addWidget(buttonBox) setWindowTitle(tr("Edit State"))
In the constructor we first save the reference to the TicTacToe widget sent as parameter, i.e the widget which state the user want to modify. Then we create a new TicTacToe
widget, and set its state to be equivalent to the parameter widget’s state.
Finally, we create the dialog’s buttons and layout.
def sizeHint(self): def QSize(250,250):
We reimplement the sizeHint()
function to ensure that the dialog is given a reasonable size.
def resetState(self): editor.clearBoard()
The resetState()
slot is called whenever the user press the Reset button. The only thing we do is to call the clearBoard()
function for the editor widget, i.e. the TicTacToe
widget we created in the dialog’s constructor.
def saveState(self):
The saveState()
slot is called whenever the user press the OK button, and transfers the state of the editor widget to the widget which state we want to modify. In order to make the change of state visible to Qt Designer we need to set the latter widget’s state property using the QDesignerFormWindowInterface
class.
QDesignerFormWindowInterface
provides you with information about the associated form window as well as allowing you to alter its properties. The interface is not intended to be instantiated directly, but to provide access to Qt Designer’s current form windows controlled by Qt Designer’s form window manager.
If you are looking for the form window containing a specific widget, you can use the static findFormWindow()
function:
if (QDesignerFormWindowInterface formWindow = QDesignerFormWindowInterface.findFormWindow(ticTacToe)) { formWindow.cursor().setProperty("state", editor.state())
After retrieving the form window of the widget (which state we want to modify), we use the cursor()
function to retrieve the form window’s cursor.
The QDesignerFormWindowCursorInterface
class provides an interface to the form window’s text cursor. Once we have cursor, we can finally set the state property using the setProperty()
function.
accept()
In the end we call the accept()
function which sets the accept flag of the event object. Setting the accept
parameter indicates that the event receiver wants the event. Unwanted events might be propagated to the parent widget.
TicTacToe Class Definition¶
The TicTacToe
class is a custom widget that lets the user play the Tic-Tac-Toe game.
class TicTacToe(QWidget): Q_OBJECT Q_PROPERTY(QString state READ state WRITE setState) # public TicTacToe = explicit(QWidget parent = None) minimumSizeHint = QSize() sizeHint = QSize() def setState(newState): state = QString() def clearBoard(): protected: def mousePressEvent(event): def paintEvent(event): # private staticexpr char16_t Empty = '-' staticexpr char16_t Cross = 'X' staticexpr char16_t Nought = 'O' cellRect = QRect(int position) int cellWidth() { return width() / 3; } int cellHeight() { return height() / 3; } myState = QString() turnNumber = 0
The main details to observe in the TicTacToe
class defintion is the declaration of the state
property and its state()
and setState()
functions.
We need to declare the TicTacToe
widget’s state as a property to make it visible to Qt Designer; allowing Qt Designer to manage it in the same way it manages the properties the TicTacToe
widget inherits from QWidget
and QObject
, for example featuring the property editor.
© 2022 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.