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"
{
class MyGuiPlugin :
public ArmarXGuiPlugin
{
public:
MyGuiPlugin()
{
addWidget<MyWidgetController>();
}
QString getPluginName()
{
return "MyGuiPlugin";
}
};
}
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
#include "ui_MyGuiPluginWidget.h"
#include "ui_MyConfigDialog.h"
#include <QtGui/QMainWindow>
#include <memory>
#include <Inventor/nodes/SoNode.h>
{
class MyGuiPluginWidgetController :
{
Q_OBJECT
public:
explicit MyGuiPluginWidgetController();
virtual ~MyGuiPluginWidgetController() {}
virtual void onInitComponent();
virtual void onConnectComponent();
virtual void onExitComponent();
virtual QString getWidgetName() const
{
return "MyWidgetController";
}
virtual void loadSettings(QSettings * settings);
virtual void saveSettings(QSettings * settings);
virtual QPointer<QDialog> getConfigDialog(QWidget* parent = 0);
virtual void configured();
virtual SoNode* getScene();
signals:
public slots:
private:
Ui::MyGuiPluginWidget widget;
QPointer<MyConfigDialog> dialog;
const std::string DEFAULT_SETTINGS_CUSTOM_TEXT;
};
}
#endif
The corresponding cpp file (MyGuiPluginWidgetController.cpp) :
#include "MyGuiPluginWidgetController.h"
{
MyGuiPluginWidgetController::MyWidgetController() :
DEFAULT_SETTINGS_CUSTOM_TEXT("custom text")
{
widget.setupUi(getWidget());
}
void MyGuiPluginWidgetController::onInitComponent()
{
}
void MyGuiPluginWidgetController::onConnectComponent()
{
}
void MyGuiPluginWidgetController::onExitComponent()
{
}
QPointer<QDialog> MyGuiPluginWidgetController::getConfigDialog(QWidget* parent)
{
if (!dialog)
{
dialog = new MyConfigDialog(parent);
dialog->ui->editCustomText->setText(QString::fromStdString(DEFAULT_SETTINGS_CUSTOM_TEXT));
}
return qobject_cast<MyConfigDialog*>(dialog);
}
void MyGuiPluginWidgetController::configured()
{
std::string customText = dialog->ui->editCustomText->text().toStdString();
this->setInstanceName(dialog->ui->editMyGuiName->text());
}
void MyGuiPluginWidgetController::loadSettings(QSettings* settings)
{
std::string customText = settings->value("CustomText", QString::fromStdString(myCustomTextVariable)).toString().toStdString();
}
void MyGuiPluginWidgetController::saveSettings(QSettings* settings)
{
settings->setValue("CustomText", QString::fromStdString(myCustomTextVariable));
}
SoNode* MyGuiPluginWidgetController::getScene()
{
return myOpenInventorModel;
}
void MyGuiPluginWidgetController::myButtonPressed()
{
}
}
A CMakeLists.txt file to compile this gui plugin:
# Qt
# Eigen
# VirtualRobot (adds dependencies to Coin3D and SoQt)
if (QT_FOUND AND Eigen3_FOUND AND Simox_FOUND)
include(${QT_USE_FILE})
include_directories(
${Eigen3_INCLUDE_DIRS}
${Simox_INCLUDE_DIRS})
# MyConfigDialog.cpp is optional
MyGuiPluginWidgetController.cpp
MyConfigDialog.cpp
)
# MyConfigDialog.h is optional
MyGuiPlugin.h
MyGuiPluginWidgetController.h
MyConfigDialog.h
)
# MyConfigDialog.h is optional
MyGuiPlugin.h
MyGuiPluginWidgetController.h
MyConfigDialog.h
)
# generates ui_MyGuiPlugin.h
# MyConfigDialog.ui is optional
MyGuiPluginWidget.ui
MyConfigDialog.ui
)
# You may want to add more libraries here
set(COMPONENT_LIBS ArmarXInterfaces ArmarXGuiBase ArmarXCore ${QT_LIBRARIES} ${Simox_LIBRARIES})
# 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.