I am trying to create a very simple example of dbus marshaling, using cmake as the build system. Complete code is found at the end of the question.
The problem I am facing, is how to include the header defining structures for the messages in the generated adapter. The qdbusxml2cpp tool allows passing required includes, but cmake's qt4_add_dbus_adaptor macro doesn't seems to accept more then include header.
The error is :
chatadaptor.moc:59:72: error: invalid use of incomplete type ‘struct MessageData’
I know I could manually add the include, but I want cmake to do it for me.
So, how can I enable dbus marshaling combined with cmake?
I am not sure if it matters, but I haven't found a way to have dbus marshaling even with qmake.
CMakeLists.txt :
CMAKE_MINIMUM_REQUIRED( VERSION 2.6 )
PROJECT( CustomDbusTypes )
FIND_PACKAGE( Qt4 COMPONENTS QtCore QtGui QtDBUS REQUIRED )
include(${QT_USE_FILE})
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
SET( CustomDbusTypes_SRC
main.cpp
MyMessages.cpp
DbusMessagesReceiver.cpp
)
SET( CustomDbusTypes_HEADERS
MyMessages.hpp
DbusMessagesReceiver.hpp
)
QT4_WRAP_CPP( CustomDbusTypes_MOC ${CustomDbusTypes_HEADERS} )
SET( HEADERS_NEEDED_FOR_DBUS_ADAPTER
DbusMessagesReceiver.hpp
MyMessages.hpp
)
qt4_add_dbus_adaptor( CustomDbusTypes_ADAPTOR_SRC
com.demo.Chat.xml
DbusMessagesReceiver.hpp
DbusMessagesReceiver )
SET( CustomDbusTypes_QT_GENERATED_FILES
${CustomDbusTypes_MOC}
${CustomDbusTypes_ADAPTOR_SRC} )
add_executable( chat ${CustomDbusTypes_SRC} ${CustomDbusTypes_QT_GENERATED_FILES} )
target_link_libraries( chat
${QT_LIBRARIES}
)
main.cpp :
#include <QApplication>
int main( int argc, char* argv[] )
{
QApplication app( argc, argv );
return app.exec();
}
MyMessages.hpp :
#ifndef MYMESSAGES_HPP
#define MYMESSAGES_HPP
#include <QString>
#include <QMetaType>
#include <QtDBus>
struct MessageData
{
QString sender;
QString message;
};
QDBusArgument& operator<<( QDBusArgument & argument, const MessageData & data );
const QDBusArgument& operator>>( const QDBusArgument & argument, MessageData & data );
void registerCommTypes();
Q_DECLARE_METATYPE(MessageData)
#endif
MyMessages.cpp :
#include "MyMessages.hpp"
QDBusArgument &operator<<( QDBusArgument & argument, const MessageData & data )
{
argument.beginStructure();
argument << data.sender << data.message;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>( const QDBusArgument & argument, MessageData & data )
{
argument.beginStructure();
argument >> data.sender >> data.message;
argument.endStructure();
return argument;
}
void registerCommTypes()
{
qDBusRegisterMetaType<MessageData>();
}
DbusMessagesReceiver.hpp :
#ifndef DBUSMESSAGESRECEIVER_HPP
#define DBUSMESSAGESRECEIVER_HPP
#include <QObject>
#include <QString>
struct MessageData;
class DbusMessagesReceiver : public QObject
{
Q_OBJECT
public:
/// Slots called by the DBUS messaging system when a message arrives
public slots:
void OnMessageData( const MessageData & data );
};
#endif
DbusMessagesReceiver.cpp :
#include "DbusMessagesReceiver.hpp"
#include "MyMessages.hpp"
#include <iostream>
void DbusMessagesReceiver::OnMessageData( const MessageData & data )
{
std::cout << data.sender.toStdString() << std::endl;
}
Finally, I figured out, and it is quite easy.
The problem was that I forward declared the MessageData structure in the header file (in DbusMessagesReceiver.hpp to be precise) that is included in the generated source file.
Once I included the header including the definition of the MessageData structure in this header, the problem disappeared.
So, the solution is to change DbusMessagesReceiver.hpp to this:
#ifndef DBUSMESSAGESRECEIVER_HPP
#define DBUSMESSAGESRECEIVER_HPP
#include <QObject>
#include <QString>
#include "MyMessages.hpp"
class DbusMessagesReceiver : public QObject
{
Q_OBJECT
public:
/// Slots called by the DBUS messaging system when a message arrives
public slots:
void OnMessageData( const MessageData & data );
};
#endif
Pretty smart from cmake developers - too bad it is not documented :(
Related
While creating a web server using proxygen, I included proxygen::HTTPServer in another subdirectory, and I get an error.
But
I included the same library in another directory, but I can not get an error.
In file included from /usr/local/include/folly/FBString.h:60:0,
from /usr/local/include/folly/Demangle.h:19,
from /usr/local/include/folly/Conv.h:40,
from /usr/local/include/folly/String.h:27,
from /usr/local/include/folly/io/async/SSLContext.h:35,
from /usr/local/include/wangle/ssl/SSLContextConfig.h:19,
from /usr/local/include/proxygen/httpserver/HTTPServer.h:12,
from /home/skyend/ds/sentencer-backend-engine/include/router/src/Router.h:9,
from /home/skyend/ds/sentencer-backend-engine/include/router/src/Router.cpp:5:
/usr/local/include/folly/memory/Malloc.h: In lambda function:
/usr/local/include/folly/memory/Malloc.h:196:38: error: inconsistent types ‘int’ and ‘bool’ deduced for lambda return type
return (origAllocated != *counter);
include/router/CMakeListx.txt
add_library(sbx_router src/Router.cpp src/Router.h)
target_link_libraries(sbx_router r3 folly)
include/router/src/Router.h ( Error )
#include <iostream>
#include <router/src/r3.h>
#include <proxygen/httpserver/HTTPServer.h>
#include <proxygen/httpserver/RequestHandlerFactory.h>
src/http/service/CMakeLists.txt
add_library(sbx_services
LoggingHandlerFactory.h)
src/http/service/LoggingHandlerFactory.h ( Well Compile )
#include "libs/stringUtils.h"
#include <proxygen/httpserver/HTTPServer.h>
#include <proxygen/httpserver/RequestHandlerFactory.h>
#include <boost/algorithm/string.hpp>
#include <vector>
namespace sbx::http::service {
class LoggingHandlerFactory : public proxygen::RequestHandlerFactory {
public:
void onServerStart(folly::EventBase * /*evb*/) noexcept override {}
void onServerStop() noexcept override {}
proxygen::RequestHandler *onRequest(proxygen::RequestHandler * nextHandler, proxygen::HTTPMessage * msg) noexcept override {
std::string method = "unknown";
if( msg->getMethod().hasValue() ) {
method = proxygen::methodToString(msg->getMethod().value());
}
std::cout << "[" << method << "] " << msg->getPath() << std::endl;
if( nextHandler != nullptr ){
return nextHandler;
}
}
};
}
CMakeLists.txt
...
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
# Things to always src as flags. Change as needed.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
# Build-type specific flags. Change as needed.
SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
SET(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
...
why occurs error?
router.h:9
#include <proxygen/httpserver/HTTPServer.h>
Router.cpp:5
#include <proxygen/httpserver/HTTPServer.h>
Thank you for help.
Solution:
Add resource files in the add_executable() statement
Problem
(not in the add_library())
Fail to set main window icon.
Notes:
When I don't use AUTORCC I run into some compilation problems:
QtCore/qglobal.h: no such file or directory. But, I do prefer AUTORCC as a more modern CMake approach.
Without the AUTORCC (different CMakeLists.txt than the provided) and Qt-4.6.2 the current code worked.
different CMakeLists.txt)
Code
This is a minimized code of my project. Tree:
|- CMakeLists.txt
|- main_window.hpp
|- main_window.cpp
|- main.cpp
|- resources
| - resources.qrc
| - images
| - logo.png
main_window.cpp
#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
};
#endif
main_window.cpp
#include "main_window.hpp"
MainWindow::MainWindow()
{
// i tried ":/images.png", ":/resources/images/logo.png", ":/logo.png"
setWindowIcon(QIcon(":images/logo.png"));
}
main.cpp
#include <QApplication>
#include "main_window.hpp"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setOrganizationName("Organization");
app.setApplicationName("Application Example");
MainWindow mainWin;
mainWin.show();
return app.exec();
}
CMakeLists.txt.
cmake_minimum_required(VERSION 3.1)
project(qt_project)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt4 4.6 REQUIRED)
set(QT_USE_QTGUI TRUE)
set(QT_USE_QTXML TRUE)
include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
// NOTE: it would be more convenient to be able to add the
// resource file here upon the creation of the library
add_library(mylib main_window.cpp)
// SOLVED
// BEFORE: add_executable(qt_test main.cpp)
add_executable(qt_test main.cpp resources/resources.qrc)
target_link_libraries(qt_test
mylib
${QT_LIBRARIES}
)
resources/resources.qrc
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/logo.png</file>
</qresource>
</RCC>
Edit
This is the generated qrc_resources.cxx
#include <QtCore/qglobal.h>
static const unsigned char qt_resource_data[] = {
// /users/ddakop/dev/misc/qt/resources/images/logo.png
// ... removed hex data
};
static const unsigned char qt_resource_name[] = {
// images
// ... removed hex data
// logo.png
// ... removed hex data
};
static const unsigned char qt_resource_struct[] = {
// :
0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,
// :/images
0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,
// :/images/logo.png
0x0,0x0,0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,
};
QT_BEGIN_NAMESPACE
extern Q_CORE_EXPORT bool qRegisterResourceData
(int, const unsigned char *, const unsigned char *, const unsigned char *);
extern Q_CORE_EXPORT bool qUnregisterResourceData
(int, const unsigned char *, const unsigned char *, const unsigned char *);
QT_END_NAMESPACE
int QT_MANGLE_NAMESPACE(qInitResources_resources)()
{
QT_PREPEND_NAMESPACE(qRegisterResourceData)
(0x01, qt_resource_struct, qt_resource_name, qt_resource_data);
return 1;
}
Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qInitResources_resources))
int QT_MANGLE_NAMESPACE(qCleanupResources_resources)()
{
QT_PREPEND_NAMESPACE(qUnregisterResourceData)
(0x01, qt_resource_struct, qt_resource_name, qt_resource_data);
return 1;
}
Q_DESTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qCleanupResources_resources))
System
CentOS-5, Qt-4.8.6, CMake-3.2.1, gcc-4.8.2
I think you need to link qrc_resources generated file.
I suppose you know the next info:
http://www.cmake.org/cmake/help/latest/manual/cmake-qt.7.html
Where you can see the next line:
add_executable(myexe main.cpp resource_file.qrc)
More info:
http://www.cmake.org/cmake/help/latest/prop_tgt/AUTORCC.html
I'm not sure if this is new or not, but I have figured out a way to add resources to libraries.
In my library's CMakeLists.txt I have the following:
list (APPEND RESOURCES library.qrc)
qt5_add_resources (RCC_SOURCES ${RESOURCES})
...
add_library(library ${RCC_SOURCES} ${SOURCES})
In the library, in one of my "main classes" (for me, this class was the first thing that gets created in the library and the last thing that gets destroyed), I did the following:
class libClass : public QMainWindow {
Q_OBJECT
public:
libClass() : QMainWindow(nullptr, 0) {
Q_INIT_RESOURCE(library);
}
~libClass() {
Q_CLEANUP_RESOURCE(library);
}
};
I am new to Dbus, and off course QDBUS. I am trying to replicate the example from the nokia developer -QT forum. I have a xml file, through which I have generated the qdbus interface adaptor.cpp and .h. Now, I am trying to include this file, and build it. However, I get the compilation error. Can you please him to fix this one?
(.text.startup+0x4c):-1: error: undefined reference to `MyDemo::MyDemo(QObject*)'
generated- adaptor.cpp
/*
* This file was generated by qdbusxml2cpp version 0.7
* Command line was: qdbusxml2cpp -c DemoIfAdaptor -a demoifadaptor.h:demoifadaptor.cpp com.nokia.Demo.xml
*
* qdbusxml2cpp is Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#include "demoifadaptor.h"
#include <QtCore/QMetaObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
/*
* Implementation of adaptor class DemoIfAdaptor
*/
DemoIfAdaptor::DemoIfAdaptor(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
// constructor
setAutoRelaySignals(true);
}
DemoIfAdaptor::~DemoIfAdaptor()
{
// destructor
}
void DemoIfAdaptor::SayBye()
{
// handle method call com.nokia.Demo.SayBye
QMetaObject::invokeMethod(parent(), "SayBye");
}
void DemoIfAdaptor::SayHello(const QString &name, const QVariantMap &customdata)
{
// handle method call com.nokia.Demo.SayHello
QMetaObject::invokeMethod(parent(), "SayHello", Q_ARG(QString, name), Q_ARG(QVariantMap, customdata));
}
Generated Adaptor.h
/*
* This file was generated by qdbusxml2cpp version 0.7
* Command line was: qdbusxml2cpp -c DemoIfAdaptor -a demoifadaptor.h:demoifadaptor.cpp com.nokia.Demo.xml
*
* qdbusxml2cpp is Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#ifndef DEMOIFADAPTOR_H_1392803889
#define DEMOIFADAPTOR_H_1392803889
#include <QtCore/QObject>
#include <QtDBus/QtDBus>
class QByteArray;
template<class T> class QList;
template<class Key, class Value> class QMap;
class QString;
class QStringList;
class QVariant;
/*
* Adaptor class for interface com.nokia.Demo
*/
class DemoIfAdaptor: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.nokia.Demo")
Q_CLASSINFO("D-Bus Introspection", ""
" <interface name=\"com.nokia.Demo\">\n"
" <method name=\"SayHello\">\n"
" <annotation value=\"QVariantMap\" name=\"com.trolltech.QtDBus.QtTypeName.In1\"/>\n"
" <arg direction=\"in\" type=\"s\" name=\"name\"/>\n"
" <arg direction=\"in\" type=\"a{sv}\" name=\"customdata\"/>\n"
" </method>\n"
" <method name=\"SayBye\"/>\n"
" <signal name=\"LateEvent\">\n"
" <arg direction=\"out\" type=\"s\" name=\"eventkind\"/>\n"
" </signal>\n"
" </interface>\n"
"")
public:
DemoIfAdaptor(QObject *parent);
virtual ~DemoIfAdaptor();
public: // PROPERTIES
public Q_SLOTS: // METHODS
void SayBye();
void SayHello(const QString &name, const QVariantMap &customdata);
Q_SIGNALS: // SIGNALS
void LateEvent(const QString &eventkind);
};
#endif
main.cpp file -
#include <QtCore/QCoreApplication>
#include <QVariant>
#include <QDBusAbstractInterface>
#include "demoifadaptor.h"
class MyDemo : public QObject
{
Q_OBJECT
public:
explicit MyDemo(QObject *parent = 0);
public Q_SLOTS:
void SayBye();
void SayHello(const QString &name, const QVariantMap &customdata);
Q_SIGNALS:
void LateEvent(const QString &eventkind);
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyDemo* demo = new MyDemo;
new DemoIfAdaptor(demo);
QDBusConnection connection = QDBusConnection::sessionBus();
bool ret = connection.registerService("com.nokia.Demo");
ret = connection.registerObject("/", demo);
return a.exec();
}
MyDemo.pro file.
#-------------------------------------------------
#
# Project created by QtCreator 2014-02-19T15:30:36
#
#-------------------------------------------------
QT += core
QT -= gui
QT += dbus
TARGET = MyDemo
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
demoifadaptor.cpp
HEADERS += \
demoifadaptor.h
Your example presents a declaration of explicit MyDemo(QObject *parent = 0); but doesn't supply it's definition. Thus the linker error. The rest of MyDemo methods must be defined as well.
You also need to run the Meta Object Compiler on the source file to avoid
"vtable..."
errors. Try re-run qmake. Any time you add a new call to the Q_OBJECT macro, you need to run qmake again. The vtables issue you're referring to in comments is directly related to that.
In case error still persist add #include "MyDemo.moc" at the end of main.cpp
I have copied some of the files from my existing project into new project. Everything works fine but I have started getting
error LNK2001: unresolved external symbol "class MessagingInterface message" (?message##3VMessagingInterface##A)
The file which throws above error has extern MessagingInterface message ; declared in .cpp file. I have two other files MessagingInterface.h and .cpp which declares and defines function for MessagingInterface class.
The interesting thing to note is both these projects are build under vs2010 but the new one has some qt functions in it so obviously I am building with qt plugin and moc files etc
I have added files in the build using Cmake.
Any tiny help will be fruitful for me..
MessageInterface.h
//#include <afxmt.h>
#include <iostream>
#include <sstream>
#include <QMutex>
#include <QString>
#include "sms_list.h"
class sms_list;
/* Macro to output the current position in the code
*/
#define CODE_CHECKPOINT message( MessageType::CODE ) \
<< __FILE__ << ", line " << __LINE__ << std::endl
/** Centralised messaging interface for printing messages to the display and to
* disk
*/
class MessagingInterface
{
public:
/** Which messages to write to which stream
*/
struct Config
{
std::ostream* os;
MessageType::Enum types[ MessageType::NUMBER_OF_MESSAGE_TYPES ];
};
/** Allows more than one stream to be written to at the same time
*/
class Proxy
{
friend class MessagingInterface;
public:
~Proxy();
std::ostream& getStream( void ) const;
private:
Proxy( MessagingInterface* ptr );
Proxy( const Proxy& other ) {}
MessagingInterface* parent_;
};
friend class Proxy;
MessagingInterface( const Config* cstart, const Config* cend );
/** Give responsibility to write to the streams to a proxy that will do the
* work for the messaging class
*/
Proxy operator() ( const MessageType::Enum type );
template<typename Type>
void operator ()( const Type& value )
{
QMutex mutex;
mutex.lock();
//CSingleLock lock( &criticalSection_, true );
for( const Config* iter = start_; iter != end_; ++iter )
*(iter->os) << value;
}
/** Outputs the value straight to all the streams
*/
template<typename Type>
void operator ()( const Type& value )
{
QMutex mutex;
mutex.lock();
//CSingleLock lock( &criticalSection_, true );
for( const Config* iter = start_; iter != end_; ++iter )
*(iter->os) << value;
}
void timestamp( void );
/** Timestamps the specified stream
*/
void timestamp( std::ostream& os );
private:
/** Outputs the message and the type
*/
void output( const MessageType::Enum type, QString str ) const;
sms_list* sms_list_;
std::stringstream ss_;
MessageType::Enum type_;
const Config* start_;
const Config* end_;
//mutable CCriticalSection criticalSection_;
mutable QMutex mutex_;
};
/** Outputs a CString as text instead of as a pointer
*/
inline std::ostream& operator <<( std::ostream& os, const QString& str )
{
os << ( str ).toStdString();
return os;
}
/** Outputs the value to the proxy stream then returns a reference to the
* stream so other items can be sent to it
*/
template<typename Type>
std::ostream& operator <<( MessagingInterface::Proxy& proxy, const Type& value )
{
//somecode
}
// MessageInterface.cpp
#include "MessagingInterface.h"
#include "SMS_list.h"
#include "lib_utils/Exception.h"
#include <boost/function.hpp>
#include <algorithm>
#include <fstream>
#include <QString>
#include <QTime>
#include <qvariant.h>
#include <QDateTime>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
using namespace MessageType;
using namespace std;
using namespace platform;
namespace
{
bla bla .. some functions
}
MessagingInterface::MessagingInterface( const Config* cstart, const Config* cend )
: message_list_( NULL ), start_( cstart ), end_( cend )
{
ss_.setf( ios::boolalpha );
}
/** Give responsibility to write to the streams to a proxy that will do the
* work for the messaging class
*/
MessagingInterface::Proxy MessagingInterface::operator() ( const MessageType::Enum type )
{
type_ = type;
return this;
}
// some other functions
Calling.cpp
#some other files
#include "MessagingInterface.h"
#include "calling.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
extern MessagingInterface message;
// some other functions
//calling.h
#pragma once
#include <string>
#include "MessagingInterface.h"
//extern MessagingInterface message; // commented out as declared in cpp file. But I have tried uncommenting here n commenting on cpp and vice versa
HI Guys , if i just use extern MessageInterface message in calling.cpp it compiles fine but if i use even one function or macro from MessageInterface it throws linker error. For example I have used CODE_CHECKPOINT in calling.cpp and it start throwing linker error .. IM completely clueless
This
extern MessagingInterface message ;
its a declaration. It should be included in a header file. Apart from this you should also define this variable in some module. It is being done by either removing keyword extern or by keeping this keyword but initializing this variable.
Solved ..
extern MessagingInterface message was throwing error in calling .cpp as Message was not defined . Since I have copy and paste few files from existinmg project into new project , I failed to define message . After defining it in some other files it works fine now.
If you check the qnamespace.h from Qt source code, you get to see something like this:
#ifndef Q_MOC_RUN
namespace
#else
class Q_CORE_EXPORT
#endif
Qt {
#if defined(Q_MOC_RUN)
Q_OBJECT
#endif
#if (defined(Q_MOC_RUN) || defined(QT_JAMBI_RUN))
// NOTE: Generally, do not add Q_ENUMS if a corresponding Q_FLAGS exists.
Q_ENUMS(ScrollBarPolicy FocusPolicy ContextMenuPolicy)
Q_ENUMS(ArrowType ToolButtonStyle PenStyle PenCapStyle PenJoinStyle BrushStyle)
Q_ENUMS(FillRule MaskMode BGMode ClipOperation SizeMode)
Q_ENUMS(BackgroundMode) // Qt3
My interpretation of this code is, that the moc preprocessor is fooled into generating meta-type information for a fake Qt object. How can I access this "fake" meta-object to get, for example, a QMetaEnum for ArrowType and other enums?
The code below does it. The output is:
LeftArrow
#include <QtCore/QTextStream>
#include <QtCore/QMetaEnum>
struct StaticQtMetaObject : public QObject
{
static inline const QMetaObject& get() {return staticQtMetaObject;}
};
int main(int argc, char *argv[])
{
const QMetaObject& mo = StaticQtMetaObject::get();
int index = mo.indexOfEnumerator("ArrowType");
QMetaEnum me = mo.enumerator(index);
Qt::ArrowType arrowType = Qt::LeftArrow;
QTextStream(stdout) << me.valueToKey(arrowType) << endl;
return 0;
}
Courtesy of http://qt-project.org/forums/viewthread/658