Workspace  6.13.0
Writing a Custom Widget

Introduction

In the previous tutorial, we created a custom datatype to represent our Rectangle information. Since we used the ObjectGroup base-class, Workspace was able to give us:

For some data types, this may not be sufficient to display or edit the data type. For example, more complex data types can be visualised differently, such as images, scenes or tree structures. In this tutorial, we will create a widget for editing the properties of our Rectangle data type.

By the end of the tutorial we will:

Contents


Sample files used and modified in this tutorial


Using the "Create Workspace Widget" code wizard

In the previous tutorial, we used the Workspace code wizard to generate the code for our Rectangle data type. In this tutorial, we're going to use the Create Workspace Widget wizard to add a skeleton widget to our simple plugin. To start the wizard:

  1. Navigate to the Development menu and select Create workspace widget... Create datatype widget
    tutcustomwidget_createcustomwidgetmenu.png
    Finding the code wizard
  2. A window will be displayed that looks something like this:
    tutcustomwidget_createcustomwidgetwizard.png
    The create workspace widget wizard
    We can use this code wizard to generate the skeleton code required for a custom widget. Let's start by filling out the fields on the form:
Note
At any time you can check the purpose of these fields by hovering over them with the mouse and reading the tooltips (as shown above).

Our form will now look something like this:

tutcustomwidget_createcustomwidgetwizardpopulated.png
Our values entered into the wizard

If we now look at the bottom of the plugin wizard, we will see some derived values. Workspace is showing us the name of the scoped class name of the new widget, as well as the scoped class name of the plugin that it is going to add it to. Next:

As we did with the data type wizard, we now get to select a copyright notice.

tutcustomwidget_copyright.png
Select none for this tutorial

Workspace will now generate the code for our new widget and place it in the directory that we selected earlier (the same directory into which we generated our plugin). If you navigate to this directory, you'll see that it has the following contents:

tutcustomwidget_directorycontents.png
The contents of the plugin directory after generating the operation

For more details about the code generated, see Writing a custom widget - looking at the code or click on one of the links to individual files below.

Rebuilding

Now that we've added our new files to the plugin, we will need to take the steps we did in the previous tutorial to compile our tutorial:

  1. Launch CMakeGui from the Workspace's Development menu
  2. Click Configure
  3. Click Generate
  4. Following the steps from the Writing a Simple Workspace Plugin tutorial, recompile your plugin for your target platform

Modifying the user interface

Next up, we will need to use Qt Designer to modify the user interface description file, rectanglewidget.ui. To do this:

  1. From the Workspace's Developer menu, launch Qt Designer
  2. When the application launches, select File > Open and in the provided dialog, browse to the location of your rectanglewidget.ui and click the Open button.
  3. You should see an empty form something like this.
    tutcustomwidget_openrectanglewidgetui.png
    The default Custom Widget in Qt Designer
    Now we're going to add some child widgets to our form which we will use to display the properties of our rectangle.
  4. From the WidgetBox on the left of the screen, drag-and-drop a Label on to the form.
  5. Double-click the Label and change its text to Width
  6. Drag another Label onto the form and change its text to Height
  7. Drag a Double Spin Box onto the form.
  8. Click on the Double Spin Box and in the Property Editor on the right of the screen, change its objectName property to width
  9. Drag another Double Spin Box onto the form and modify its objectName property to height
  10. Right-click on some empty space and select Lay Out in a Grid
  11. Click the Save button.

    tutcustomwidget_updatedrectanglewidgetui.png
    The updated Custom Widget in Qt Designer
    Note
    The QDoubleSpinBox control has a default maximum of 99.00. If you want to change the number of decimal places or the maximum value, you can do so via the Property Editor panel.

Now that you've done that, recompile the plugin. This will update the Qt generated UI code so that we can reference it from within our rectanglewidget.cpp file.

The next step is to modify our updateWidget and updateData functions to control the user interface. Below is the code we will add into the rectanglewidget.cpp file:

bool RectangleWidgetImpl::updateWidget(const CSIRO::Rectangle& data)
{
// ================================== //
// Update your widget's controls here //
// ================================== //
ui_->width->setValue(data.getWidth());
ui_->height->setValue(data.getHeight());
return true;
}

What we're doing here is extracting the values from our Rectangle and updating the text displayed in the widgets. Similarly, our updateData method moves data from the widget's controls into the Rectangle data.

bool RectangleWidgetImpl::updateData(CSIRO::Rectangle& data)
{
// =================================== //
// Update the data argument with data //
// from your widgets controls here //
// =================================== //
data.setWidth(ui_->width->value());
data.setHeight(ui_->height->value());
return true;
}

The last thing we need to do is connect our spin boxes' valueChanged signal to our widgets widgetUpdated signal. This will ensure that whenever our spin boxes change, our data is updated as soon as possible. We do this by adding a few lines to the constructor:

RectangleWidget::RectangleWidget(QWidget* parent) :
QWidget(parent),
pImpl_(std::make_unique<RectangleWidgetImpl>(*this))
{
bool connected = true;
// ====================================== //
// Connect up your signals and slots here //
// (see examples below) //
// ====================================== //
connected = connect(pImpl_->ui_->width, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &RectangleWidget::widgetUpdated);
WS_VERIFY_RUNTIME(connected);
connected = connect(pImpl_->ui_->height, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &RectangleWidget::widgetUpdated);
WS_VERIFY_RUNTIME(connected);
}

Note that the static cast is necessary in this case to distinguish between the two types of valueChanged signals that a QDoubleSpinBox can emit (double or QString).

Now that we've made those changes, we can now recompile and load up Workspace.


Using our new widget

To use the widget, we can do the following:

  1. From the Operation Catalogue, drag-and-drop a CalculateRectangleArea operation on to the canvas.
  2. Click on the operation to see its properties in the Operation Editor or right click on the Rectangle input and select "Display with RectangleWidget" from the context menu.

    tutcustomwidget_addingthecustomwidget.png
    Adding the Custom Widget to an input
  3. Right click on the Area output and select "Display with QLineEdit from the context menu.
  4. Right click on the Dependencies output and add a Workspace output
  5. Execute the workflow
  6. You can now change the values in the display widget and it will instantly update the operation.

    tutcustomwidget_executingaworkflowwithacustomwidget.png
    Executing a workflow with a Custom Widget

Summary

This tutorial has introduced you to the essential elements of adding a new custom widget to your Workspace plugin. The main points to remember are the following:


Next steps

The following tutorials are suggested as next steps: