Workspace 7.0.2
|
In this section, we're going to understand the code that was automatically generated by Workspace so that we know how to customise our widget, and implement its custom visualisation capability.
Rebuilding (continue on with tutorial Writing a Custom Widget )
The first thing we need to understand is that the wizard has generated three classes:
Now that we understand that, we can have a look at the code that comprises each of our classes. Let's start with the RectangleWidget.
Here we can see that we extend QWidget. QWidget is the base class for all widget types in the Qt toolkit. Anything you see in a user interface is some type of QWidget. By default, a QWidget is essentially an empty container into which we can place other widgets.
We can also see that we add the Q_OBJECT macro at the top of the class. This makes sure that Qt adds the appropriate meta-object functionality when we compile the class. In other words, it allows us to use fancy things called Signals and Slots which are not available in standard C++.
As in the previous tutorials, we can also see our implementation class, RectangleWidgetImpl
being forward-declared and a pointer to an instance of it being declared as a private member of the class.
The next thing to do is to define our constructor, destructor and our two key public member functions updateWidget and updateData. As one would expect, updateWidget is used to update the widget by taking a reference to a Rectangle, and updateData is used to update a reference to a data object with information gathered from the widget's UI.
Lastly, we can see a fancy section called signals, and within it the declaration of a signal called widgetUpdated. As one might expect, this signal is emitted whenever the widget has been updated by the user, indicating that it is ready to reflect these updates in the data, if any is available.
We'll see how our widgetUpdated signal is used when we look at our widget connector later. For now, if you'd like any more information about how Signals and Slots work in Qt, you can take a look at this Qt documention page.
Rebuilding (continue on with tutorial Writing a Custom Widget )
We will show this implementation file in stages and talk about each part as we go. As usual, we start by including the required headers, the most notable of which is the ui_rectanglewidget.h file. This file contains the Qt generated UI class, which we are essentially wrapping with our class. We also include the usual namespace scopes:
The next thing we need to do is define our private implementation class:
This class is very straightforward. It contains the implementations of our updateWidget and updateData methods, as well as a pointer to the UI implementation class generated by Qt's UI file generator.
Next up, we find the definitions of our updateWidget and updateData methods:
This is where we update the controls in the UI using our data, and update a reference to some data with the information presented in the widget.
The next important piece of implementation is the Widget's constructor:
Note that it contains a comment indicating that this is the location to connect up any signals from our UI controls to our widgetUpdated signal. Triggering the widgetUpdated signal will cause the updateData function to be called when Workspace deems it safe to do so.
The remainder of the file is simple forwarding functions:
Rebuilding (continue on with tutorial Writing a Custom Widget )
As discussed above, our RectangleWidgetConnector class extends QWidgetConnector and is used by Workspace to control the safe updating of the widget, as well as the safe updating of the connected data in the underlying Workflow. The header file for the connector is not overly complex. First up, we can see the inclusion of the relevant headers:
We can then see the class declaration with features such as the public inheritance from CSIRO::Widgets::QWidgetConnector, the inclusion of the Q_OBJECT macro for Qt meta-object compilation, and two key virtual methods, updateWidget and updateData. These methods override pure-virtual methods in the base class QWidgetConnector, and accept as parameters DataObjects. When we look at the implementation, we will see that it is the responsibliity of these functions to extract the raw data from these data objects, and either supply it to the widget for display, or to supply it to the widget for updating.
Rebuilding (continue on with tutorial Writing a Custom Widget )
Let's have a look at the implementation of the connector. Although we will not need to modify this class, it is useful to understand how it works. As usual, we include a bunch of standard Workspace headers:
Our constructor accepts a QWidget as the type, and it is our responsibility to make sure it is of the correct type when it is used. Although the base class will actually store a pointer to the widget, we make sure to assert that it is of the correct type here. We also make sure to connect our widget's widgetUpdated signal to our requestUpdateData slot (defined on the QWidgetConnector base class). This means that whenever the widget emits its widgetUpdated signal, the connector will tell Workspace that it needs to update the underlying data. Workspace will then invoke the updateData method on the connector as soon as it is safe to do so.
Next up is the implementation of our updateWidget method:
Here we can see that the method takes a DataObject, which from our previous tutorials we will remember as being a generic pointer to some data of a particular Workspace type. It then does the following:
Our updateData method is very similar:
It does the same thing as the updateWidget method above, but invokes the updateData method of the RectangleWidget, passing in a non-const reference to the Rectangle data it extracts from the DataObject.
The setWidgetReadOnly method is called by the Workspace editor to toggle read only behaviour for your widget when it is attached to a data object that has read only access. The base class implementation of setWidgetReadOnly will simply disable your widget. If instead your widget requires partial interactivity while in read only mode, you can specify your widget's read only customisations here.
For this tutorial we'll use the default base class implementation.
Rebuilding (continue on with tutorial Writing a Custom Widget )
Similar to the WidgetConnector, the WidgetFactory files will not need to be modified. We are only looking at these to understand how the code works. As described above, the RectangleWidgetFactory is used by Workspace to create our RectangleWidget and our RectangleWidgetConnector. It's header file begins with the usual header guards, header includes and forward declarations:
As we can see below, the class itself extends CSIRO::Widgets::WidgetFactory; the base class for creating widgets in Workspace:
It contains a number of important method declarations:
Rebuilding (continue on with tutorial Writing a Custom Widget )
Let's have a look at the implementation of the methods in the WidgetFactory, defined in the .cpp file, starting with the getInstance function:
As we can see, all it does is declare a static instance of the RectangleWidgetFactory and returns an instance of it.
The getQWidgetMetaObject function doesn't do much. It just returns a reference to the static meta object declared in our widget.
As expected, our getDataFactory method returns a reference of the Rectangle data factory. Lastly, our createWidget and createWidgetConnector methods are also straightforward.
Rebuilding (continue on with tutorial Writing a Custom Widget )
As expected, the wizard has made a number of changes to our setup() function in the SimplePlugin implementation. First of all, we can see that it's added rectanglewidgetfactory.h to the include headers:
If we look at the setup function, we'll also see a new line adding the widget factory to our plugin.
Rebuilding (continue on with tutorial Writing a Custom Widget )
The CMakeLists.txt file has also been modified to contain references to the new files. As we can see below, the HEADERS, INSTALL_HEADERS, MOC_HEADERS, SOURCES and UI_SOURCES have all been updated to refer to our newly generated files:
Rebuilding (continue on with tutorial Writing a Custom Widget )