How to create your own gui plugin

Every plugin consits of:

  • a subclass of ArmarXGuiPlugin
  • a subclass of ArmarXComponentWidgetController (with Ice functionality) or ArmarXWidgetController (without Ice functionality)
  • a Qt .ui file containing the Gui layout
  • an optional .ui file containing a configuration dialog

All required files should be generated using the armarx-package tool in the following way (execute this command in the toplevel directory of your package):

    armarx-package add gui-plugin MyGuiPlugin

This is an exemplary header file (MyGuiPlugin.h) for a custom ArmarXGuiPlugin subclass :

#ifndef ARMARX_MY_GUI_PLUGIN_H
#define ARMARX_MY_GUI_PLUGIN_H
#include "MyWidgetController.h"
namespace armarx
{
// The plugin definition
class MyGuiPlugin :
public ArmarXGuiPlugin
{
public:
// add all widget controllers contained in the plugin in the constructor
// each entry will appear as a separate widget in the 'Add Widget' menu of ArmarXGui
MyGuiPlugin()
{
addWidget<MyWidgetController>();
}
// return the name of the plugin
// this has to be a unique name amongst all plugins
QString getPluginName()
{
return "MyGuiPlugin";
}
};
}
// ****
// IMPORTANT: Use this QT macro to register your plugin
// ****
Q_EXPORT_PLUGIN2(armarx_gui_MyGuiPlugin, MyGuiPlugin)
#endif

This is an exemplary header file (MyGuiPluginWidgetController.h)for a custom ArmarXComponentWidgetController subclass :

#ifndef _ARMARX_MYPACKAGE_MyGuiPlugin_WidgetController_H
#define _ARMARX_MYPACKAGE_MyGuiPlugin_WidgetController_H
// This file is created from your custom Qt-widget UI file that you have built with Qt-Designer or Qt-Creator
// this file is generated from MyGuiPlugin.ui
// .ui files are created using QtDesigner or QtCreator and describe the layout of a widget
#include "ui_MyGuiPluginWidget.h"
// This is an optional config dialog, which can be omitted
#include "ui_MyConfigDialog.h"
#include <QtGui/QMainWindow>
#include <memory>
// Only needed if you intend to offer 3D visualization data
#include <Inventor/nodes/SoNode.h>
// use a different namespace here depending on the armarx package the plugin belongs to
// such as memoryx or visionx
namespace armarx
{
// The widget controller
class MyGuiPluginWidgetController :
{
Q_OBJECT
public:
explicit MyGuiPluginWidgetController();
virtual ~MyGuiPluginWidgetController() {}
// inherited from armarx::Component
// implement you custom startup, connect and exit code here
virtual void onInitComponent();
virtual void onConnectComponent();
virtual void onExitComponent();
// inherited of ArmarXWidget
virtual QString getWidgetName() const
{
return "MyWidgetController";
}
// You may want to offer GUI save/load functionality.
// If not, you can leave these methods empty.
virtual void loadSettings(QSettings * settings);
virtual void saveSettings(QSettings * settings);
// Each Gui widget can be configured when it is instantiated.
// A custom initialization dialog can be implemented here.
// Have a look at existing plugins on how to realize a config dialog.
// If no custom implementation is provided by your widget, a standard config dialog is offered by ArmarXGui.
virtual QPointer<QDialog> getConfigDialog(QWidget* parent = 0);
// This method is called by the framework when your custom config dialog is closed with OK.
// Now you can read the parameters from your custom dialog.
virtual void configured();
// If this widget offers a 3D model you have to implement this method and
// return the SoNode containing the 3D model.
virtual SoNode* getScene();
signals:
// you may want to specify custom Qt signal methods here
// void updateData();
public slots:
// you may want to specify custom Qt slots methods here
// don't forget to connect them in onConnectComponent()
// e.g. connect(ui.myButton, SIGNAL(clicked()), this, SLOT(myButtonPressed()));
// void myButtonPressed();
private:
// the ui object comes from your Qt-UI widget "ui_MyGuiPluginWidget.h"
// PLEASE NOTE: the toplevel widget in this file needs to be named MyGuiPluginWidget
// otherwise this line will fail to compile
Ui::MyGuiPluginWidget widget;
// optional config dialog
QPointer<MyConfigDialog> dialog;
const std::string DEFAULT_SETTINGS_PLUGIN_NAME;
const std::string DEFAULT_SETTINGS_CUSTOM_TEXT;
};
}
#endif

The corresponding cpp file (MyGuiPluginWidgetController.cpp) :

#include "MyGuiPluginWidgetController.h"
// Qt and other includes are skipped here
namespace armarx
{
MyGuiPluginWidgetController::MyWidgetController() :
DEFAULT_SETTINGS_CUSTOM_TEXT("custom text")
{
// init gui
// getWidget() returns a container into which this widget is embedded
widget.setupUi(getWidget());
ARMARX_INFO << " setup of ui finished" << flush;
}
void MyGuiPluginWidgetController::onInitComponent()
{
ARMARX_INFO << "Init MyWidgetController " << flush;
// if you want to use proxies you can specify them here
//usingProxy(myProxyName);
}
void MyGuiPluginWidgetController::onConnectComponent()
{
// if you have a button named myButton in your widget you have to connect it here
//connect(ui.myButton, SIGNAL(clicked()), this, SLOT(myButtonPressed()));
// if you want to listen on topics you can specify them here
//usingTopic(myTopicName);
}
void MyGuiPluginWidgetController::onExitComponent()
{
// implement cleanup
}
QPointer<QDialog> MyGuiPluginWidgetController::getConfigDialog(QWidget* parent)
{
if (!dialog)
{
dialog = new MyConfigDialog(parent);
// set standard values (we assume here that the two Qt QLineEdits editMyGuiName and editCustomText are defined in config widget)
dialog->ui->editMyGuiName->setText(QString::fromStdString(DEFAULT_SETTINGS_PLUGIN_NAME));
dialog->ui->editCustomText->setText(QString::fromStdString(DEFAULT_SETTINGS_CUSTOM_TEXT));
}
return qobject_cast<MyConfigDialog*>(dialog);
}
void MyGuiPluginWidgetController::configured()
{
ARMARX_VERBOSE << "MyWidgetController::configured()";
// read user data from config dialog
// assumes that the ui of the dialog contains two fields with the name
// editCustomText and editMyGuiName
std::string customText = dialog->ui->editCustomText->text().toStdString();
this->setInstanceName(dialog->ui->editMyGuiName->text());
}
void MyGuiPluginWidgetController::loadSettings(QSettings* settings)
{
// Qt-based settings loading
std::string customText = settings->value("CustomText", QString::fromStdString(myCustomTextVariable)).toString().toStdString();
}
void MyGuiPluginWidgetController::saveSettings(QSettings* settings)
{
// Qt-based settings saving
settings->setValue("CustomText", QString::fromStdString(myCustomTextVariable));
}
SoNode* MyGuiPluginWidgetController::getScene()
{
// if widgte offers a 3d model it has to be returned here, otherwise this method shouldn't be implemented
return myOpenInventorModel;
}
void MyGuiPluginWidgetController::myButtonPressed()
{
ARMARX_INFO << "Button pressed" << flush;
}
}

A CMakeLists.txt file to compile this gui plugin:

armarx_set_target("MyGuiPlugin")
# Qt
find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL QUIET)
# Eigen
find_package(Eigen3 QUIET)
# VirtualRobot (adds dependencies to Coin3D and SoQt)
find_package(Simox 2.1.5 QUIET)
armarx_build_if(ArmarXGui_FOUND "ArmarXGui not available")
armarx_build_if(QT_FOUND "Qt not available")
armarx_build_if(QT_QTOPENGL_FOUND "QtOpenGL not available")
armarx_build_if(Eigen3_FOUND "Eigen3 not available")
armarx_build_if(Simox_FOUND "VirtualRobot not available")
if (QT_FOUND AND Eigen3_FOUND AND Simox_FOUND)
include(${QT_USE_FILE})
${Eigen3_INCLUDE_DIRS}
${Simox_INCLUDE_DIRS})
# MyConfigDialog.cpp is optional
set(SOURCES
MyGuiPluginWidgetController.cpp
MyConfigDialog.cpp
)
# MyConfigDialog.h is optional
set(HEADERS
MyGuiPlugin.h
MyGuiPluginWidgetController.h
MyConfigDialog.h
)
# MyConfigDialog.h is optional
set(GUI_MOC_HDRS
MyGuiPlugin.h
MyGuiPluginWidgetController.h
MyConfigDialog.h
)
# generates ui_MyGuiPlugin.h
# MyConfigDialog.ui is optional
set(GUI_UIS
MyGuiPluginWidget.ui
MyConfigDialog.ui
)
# You may want to add more libraries here
set(COMPONENT_LIBS ArmarXInterfaces ArmarXGuiBase ArmarXCore ${QT_LIBRARIES} ${Simox_LIBRARIES})
set(LIB_VERSION 0.1.0)
set(LIB_SOVERSION 0)
# The armarx_gui_library function builds your plugin
# It is made available by adding 'depends_on_armarx_package(ArmarXGui)' in the toplevel CMakeLists.txt
if (ArmarXGui_FOUND)
armarx_gui_library(MyGuiPlugin "${SOURCES}" "${GUI_MOC_HDRS}" "${GUI_UIS}" "" "${COMPONENT_LIBS}" "${LIB_VERSION}" "${LIB_SOVERSION}")

To add proper documentation for your gui plugin, create a doxygen page in your MyGuiPluginWidgetController.h:

namespace armarx
{
/**
* \page ${PACKAGENAME}-GuiPlugins-MyGuiPlugin MyGuiPlugin
* \brief The MyGuiPlugin allows you to ...
*
* \image html MyGuiPlugin.png
*
* This is a detailled description of the MyGuiPlugin
* gui plugin. It is very awesome.
*
* \see MyGuiPluginGuiPlugin
*/
...
}

and add it as subpage to ${PACKAGENAME}/etc/doxygen/pages/GuiPlugins.dox:

\subpage ${PACKAGENAME}-GuiPlugins-MyGuiPlugin "MyGuiPlugin"

Images (e.g. a screenshot of the widget) go to ${PACKAGENAME}/etc/doxygen/images/.

Note
All network calls (e.g. with Ice) should be in a seperate thread like armarx::RunningTask, armarx::PeriodicTask or QThread since they can take a long time to complete and block the complete GUI if executed in the qt main-event-loop. QTimer or timerEvent(QTimerEvent) are running in the same thread as the main application loop, so they are not suitable for network calls. Especially periodic network calls like updating data should be in a seperate thread.
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:180
endif
endif() find_package(Simox QUIET) armarx_build_if(Simox_FOUND "Simox not available") if(Simox_FOUND) include_directories($
Definition: CMakeLists.txt:10
armarx_gui_library
armarx_gui_library(ObserverPropertiesGuiPlugin "${SOURCES}" "${HEADERS}" "${GUI_UIS}" "" "${COMPONENT_LIBS}") if(qwt_FOUND) target_include_directories(ObserverPropertiesGuiPlugin SYSTEM PUBLIC $
Definition: CMakeLists.txt:53
find_package
find_package(Ice REQUIRED) set(COMPONENT_LIBS ArmarXCoreInterfaces ArmarXCore "/usr/lib/$
Definition: CMakeLists.txt:1
QtOpenGL
QtOpenGL
Definition: CMakeLists.txt:12
set
set(LIBS ArmarXCoreInterfaces ${CMAKE_THREAD_LIBS_INIT} ${dl_LIBRARIES} ${rt_LIBRARIES} ${QT_LIBRARIES} ${Boost_LIBRARIES} BoostAssertionHandler ArmarXCPPUtility SimoxUtility) set(LIB_FILES ArmarXManager.cpp ArmarXMultipleObjectsScheduler.cpp ArmarXObjectScheduler.cpp ManagedIceObject.cpp ManagedIceObjectPlugin.cpp Component.cpp ComponentPlugin.cpp IceGridAdmin.cpp ArmarXObjectObserver.cpp IceManager.cpp PackagePath.cpp RemoteReferenceCount.cpp logging/LoggingUtil.cpp logging/Logging.cpp logging/LogSender.cpp logging/ArmarXLogBuf.cpp system/ArmarXDataPath.cpp system/DynamicLibrary.cpp system/ProcessWatcher.cpp system/FactoryCollectionBase.cpp system/cmake/CMakePackageFinder.cpp system/cmake/CMakePackageFinderCache.cpp system/cmake/ArmarXPackageToolInterface.cpp system/RemoteObjectNode.cpp services/sharedmemory/HardwareId.cpp services/tasks/RunningTask.cpp services/tasks/ThreadList.cpp services/tasks/ThreadPool.cpp services/profiler/Profiler.cpp services/profiler/FileLoggingStrategy.cpp services/profiler/IceLoggingStrategy.cpp application/Application.cpp application/ApplicationOptions.cpp application/ApplicationProcessFacet.cpp application/ApplicationNetworkStats.cpp application/properties/PropertyUser.cpp application/properties/Property.cpp application/properties/PropertyDefinition.cpp application/properties/PropertyDefinitionContainer.cpp application/properties/PropertyDefinitionHelpFormatter.cpp application/properties/PropertyDefinitionConfigFormatter.cpp application/properties/PropertyDefinitionBriefHelpFormatter.cpp application/properties/PropertyDefinitionXmlFormatter.cpp application/properties/PropertyDefinitionDoxygenFormatter.cpp application/properties/PropertyDefinitionDoxygenComponentPagesFormatter.cpp application/properties/PropertyDefinitionContainerBriefHelpFormatter.cpp application/properties/IceProperties.cpp exceptions/Exception.cpp exceptions/local/UnexpectedEnumValueException.cpp util/FileSystemPathBuilder.cpp util/StringHelpers.cpp util/IceReportSkipper.cpp util/Throttler.cpp util/distributed/AMDCallbackCollection.cpp util/distributed/RemoteHandle/ClientSideRemoteHandleControlBlock.cpp util/distributed/RemoteHandle/RemoteHandle.cpp util/distributed/RemoteHandle/RemoteHandleControlBlock.cpp time/ice_conversions.cpp time/json_conversions.cpp time/CallbackWaitLock.cpp time/Clock.cpp time/ClockType.cpp time/ClockTypeNames.cpp time/CycleUtil.cpp time/DateTime.cpp time/Duration.cpp time/Frequency.cpp time/LocalTimeServer.cpp time/Metronome.cpp time/ScopedStopWatch.cpp time/StopWatch.cpp time/Timer.cpp time/TimeKeeper.cpp time/TimeUtil.cpp csv/CsvWriter.cpp csv/CsvReader.cpp) set(LIB_HEADERS ArmarXManager.h ArmarXDummyManager.h ArmarXMultipleObjectsScheduler.h ArmarXObjectObserver.h ArmarXObjectScheduler.h ArmarXFwd.h Component.h ComponentPlugin.h ComponentFactories.h CoreObjectFactories.h IceGridAdmin.h IceManager.h IceManagerImpl.h json_conversions.h ManagedIceObject.h ManagedIceObjectPlugin.h ManagedIceObjectImpl.h ManagedIceObjectDependency.h ManagedIceObjectRegistryInterface.h PackagePath.h RemoteReferenceCount.h system/ImportExport.h system/ImportExportComponent.h system/AbstractFactoryMethod.h system/FactoryCollectionBase.h system/Synchronization.h system/ArmarXDataPath.h system/DynamicLibrary.h system/ProcessWatcher.h system/ConditionSynchronization.h system/cmake/CMakePackageFinder.h system/cmake/CMakePackageFinderCache.h system/cmake/FindPackageX.cmake system/cmake/ArmarXPackageToolInterface.h system/RemoteObjectNode.h logging/LoggingUtil.h logging/LogSender.h logging/Logging.h logging/ArmarXLogBuf.h logging/SpamFilterData.h services/tasks/RunningTask.h services/tasks/PeriodicTask.h services/tasks/ThreadList.h services/tasks/TaskUtil.h services/tasks/ThreadPool.h services/sharedmemory/SharedMemoryProvider.h services/sharedmemory/SharedMemoryConsumer.h services/sharedmemory/IceSharedMemoryProvider.h services/sharedmemory/IceSharedMemoryConsumer.h services/sharedmemory/HardwareIdentifierProvider.h services/sharedmemory/HardwareId.h services/sharedmemory/exceptions/SharedMemoryExceptions.h services/profiler/Profiler.h services/profiler/LoggingStrategy.h services/profiler/FileLoggingStrategy.h services/profiler/IceLoggingStrategy.h application/Application.h application/ApplicationOptions.h application/ApplicationProcessFacet.h application/ApplicationNetworkStats.h application/properties/forward_declarations.h application/properties/Properties.h application/properties/Property.h application/properties/PluginEigen.h application/properties/PluginEnumNames.h application/properties/PluginCfgStruct.h application/properties/PluginAll.h application/properties/PropertyUser.h application/properties/PropertyDefinition.h application/properties/PropertyDefinition.hpp application/properties/PropertyDefinitionInterface.h application/properties/PropertyDefinitionContainer.h application/properties/PropertyDefinitionFormatter.h application/properties/PropertyDefinitionContainerFormatter.h application/properties/PropertyDefinitionConfigFormatter.h application/properties/PropertyDefinitionHelpFormatter.h application/properties/PropertyDefinitionBriefHelpFormatter.h application/properties/PropertyDefinitionXmlFormatter.h application/properties/PropertyDefinitionDoxygenFormatter.h application/properties/PropertyDefinitionDoxygenComponentPagesFormatter.h application/properties/PropertyDefinitionContainerBriefHelpFormatter.h application/properties/ProxyPropertyDefinition.h application/properties/IceProperties.h exceptions/Exception.h exceptions/LocalException.h exceptions/local/DynamicLibraryException.h exceptions/local/ExpressionException.h exceptions/local/FileIOException.h exceptions/local/InvalidPropertyValueException.h exceptions/local/MissingRequiredPropertyException.h exceptions/local/PropertyInheritanceCycleException.h exceptions/local/ProxyNotInitializedException.h exceptions/local/UnexpectedEnumValueException.h exceptions/local/UnmappedValueException.h exceptions/local/ValueRangeExceededException.h exceptions/user/NotImplementedYetException.h rapidxml/rapidxml.hpp rapidxml/rapidxml_print.hpp rapidxml/rapidxml_iterators.hpp rapidxml/rapidxml_utils.hpp rapidxml/wrapper/RapidXmlReader.h rapidxml/wrapper/RapidXmlWriter.h rapidxml/wrapper/DefaultRapidXmlReader.h rapidxml/wrapper/MultiNodeRapidXMLReader.h util/IceBlobToObject.h util/ObjectToIceBlob.h util/FileSystemPathBuilder.h util/FiniteStateMachine.h util/StringHelpers.h util/StringHelperTemplates.h util/algorithm.h util/OnScopeExit.h util/Predicates.h util/Preprocessor.h util/PropagateConst.h util/Registrar.h util/TemplateMetaProgramming.h util/TripleBuffer.h util/IceReportSkipper.h util/Throttler.h util/distributed/AMDCallbackCollection.h util/distributed/RemoteHandle/ClientSideRemoteHandleControlBlock.h util/distributed/RemoteHandle/RemoteHandle.h util/distributed/RemoteHandle/RemoteHandleControlBlock.h util/SimpleStatemachine.h time.h time_minimal.h time/forward_declarations.h time/ice_conversions.h time/json_conversions.h time/CallbackWaitLock.h time/Clock.h time/ClockType.h time/ClockTypeNames.h time/CycleUtil.h time/DateTime.h time/Duration.h time/Frequency.h time/LocalTimeServer.h time/Metronome.h time/ScopedStopWatch.h time/StopWatch.h time/Timer.h time/TimeUtil.h time/TimeKeeper.h csv/CsvWriter.h csv/CsvReader.h ice_conversions.h ice_conversions/ice_conversions_boost_templates.h ice_conversions/ice_conversions_templates.h ice_conversions/ice_conversions_templates.tpp $
Definition: CMakeLists.txt:12
armarx_build_if
EXACT REQUIRED COMPONENTS iostreams armarx_build_if(Boost_FOUND "Boost not available") armarx_build_if(UNIX "Only available on Linux") message(STATUS "Boost-Include-Dir
Definition: CMakeLists.txt:5
ArmarXGuiPlugin.h
QtGui
QtGui
Definition: CMakeLists.txt:12
ArmarXComponentWidgetController.h
armarx::flush
const LogSender::manipulator flush
Definition: LogSender.h:251
armarx_set_target
armarx_set_target("Core Library: ArmarXCore") set(LIB_NAME ArmarXCore) find_package(dl REQUIRED) find_package(rt REQUIRED) include_directories(SYSTEM $
Definition: CMakeLists.txt:1
include_directories
include_directories(SYSTEM ${Eigen3_INCLUDE_DIR}) endif() set(LIB_NAME RobotAPICore) set(LIBS RobotAPIInterfaces ArmarXCoreObservers ArmarXCoreStatechart ArmarXCoreEigen3Variants VirtualRobot Saba SimDynamics) set(LIB_FILES PIDController.cpp Trajectory.cpp TrajectoryController.cpp Pose.cpp FramedPose.cpp LinkedPose.cpp OrientedPoint.cpp FramedOrientedPoint.cpp RobotStatechartContext.cpp RobotPool.cpp checks/ConditionCheckMagnitudeChecks.cpp observerfilters/OffsetFilter.cpp observerfilters/PoseAverageFilter.cpp observerfilters/PoseMedianFilter.cpp observerfilters/PoseMedianOffsetFilter.cpp observerfilters/MedianDerivativeFilterV3.cpp RobotAPIObjectFactories.cpp remoterobot/RobotStateObserver.cpp remoterobot/RemoteRobot.cpp remoterobot/RemoteRobotNode.cpp math/LinearizeAngularTrajectory.cpp math/TimeSeriesUtils.cpp CartesianVelocityController.cpp CartesianPositionController.cpp CartesianWaypointController.cpp CartesianFeedForwardPositionController.cpp CartesianVelocityRamp.cpp JointVelocityRamp.cpp CartesianVelocityControllerWithRamp.cpp CartesianNaturalPositionController.cpp visualization/DebugDrawerTopic.cpp visualization/GlasbeyLUT.cpp) set(LIB_HEADERS PIDController.h MultiDimPIDController.h Trajectory.h TrajectoryController.h VectorHelpers.h Pose.h FramedPose.h LinkedPose.h OrientedPoint.h FramedOrientedPoint.h RobotStatechartContext.h RobotPool.h observerfilters/PoseMedianFilter.h observerfilters/PoseAverageFilter.h observerfilters/PoseMedianOffsetFilter.h observerfilters/OffsetFilter.h observerfilters/MatrixFilters.h observerfilters/MedianDerivativeFilterV3.h checks/ConditionCheckEqualsPose.h checks/ConditionCheckEqualsPoseWithTolerance.h checks/ConditionCheckMagnitudeChecks.h RobotAPIObjectFactories.h remoterobot/RobotStateObserver.h remoterobot/RemoteRobot.h math/SlidingWindowVectorMedian.h math/MathUtils.h math/Trigonometry.h math/SVD.h math/StatUtils.h math/MatrixHelpers.h math/ColorUtils.h math/LinearizeAngularTrajectory.h math/TimeSeriesUtils.h CartesianVelocityController.h CartesianPositionController.h CartesianWaypointController.h CartesianFeedForwardPositionController.h CartesianVelocityRamp.h JointVelocityRamp.h CartesianVelocityControllerWithRamp.h CartesianNaturalPositionController.h EigenHelpers.h visualization/DebugDrawerTopic.h visualization/GlasbeyLUT.h json_conversions.h) add_subdirectory(test) armarx_add_library("$
Definition: CMakeLists.txt:11
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
DEFAULT_SETTINGS_PLUGIN_NAME
#define DEFAULT_SETTINGS_PLUGIN_NAME
Definition: PriorMemoryEditorPlugin.cpp:88
armarx::ArmarXComponentWidgetController
Definition: ArmarXComponentWidgetController.h:39
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28