通过 dbus 共享对象
Sharing objects over dbus
我的项目源自这个例子:http://doc.qt.io/qt-5/qtdbus-remotecontrolledshower-example.html
有两个进程,shower和controller,controller可以向shower发送简单的消息(我只是把那个项目中的car重命名为shower),把花哨的car GUI改成了一个简单的Widget。我这样做没有问题。
我的问题是当我尝试使用自定义 class
发送消息时
#ifndef MESSAGE_H
#define MESSAGE_H
#include <QtDBus>
class message
{
public:
QString articleName;
QString categoryName;
message() : articleName(""), categoryName("") {}
message( QString a, QString b ) : articleName(a), categoryName(b) {}
message(const message &other) : articleName( other.articleName ), categoryName( other.categoryName ) {}
message& operator=(const message &other)
{
articleName = other.articleName;
categoryName = other.categoryName;
return *this;
}
//register Message with the Qt type system
static void registerMetaType()
{
qRegisterMetaType<message>("message");
qDBusRegisterMetaType<message>();
}
friend QDBusArgument &operator<<(QDBusArgument &argument, const message &mess )
{
argument.beginStructure();
argument << mess.articleName;
argument << mess.categoryName;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator>>(const QDBusArgument &argument, message &mess )
{
argument.beginStructure();
argument >> mess.articleName;
argument >> mess.categoryName;
argument.endStructure();
return argument;
}
};
Q_DECLARE_METATYPE( message )
#endif // MESSAGE_H
然后我在接收消息对象的地方 class 添加了一个方法
#ifndef shower_H
#define shower_H
#include "ui_Categories.h"
#include "message.h"
class shower : public QWidget
{
Q_OBJECT
public:
shower(QWidget *parent = 0);
//shower();
//QRectF boundingRect() const;
public Q_SLOTS:
void accelerate();
void decelerate();
void turnLeft();
void turnRight();
void doThat();
void addMessage( const message &msg );
QString Get( int param );
Q_SIGNALS:
void crashed();
protected:
void timerEvent(QTimerEvent *event);
private:
Ui::Categories ui;
qreal wheelsAngle; // used when applying rotation
qreal speed; // delta movement along the body axis
};
#endif // shower_H
这是我定义花洒界面的xml
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/com/trollech/examples/shower">
<interface name="org.example.Examples.showerInterface">
<method name="accelerate"/>
<method name="decelerate"/>
<method name="turnLeft"/>
<method name="turnRight"/>
<method name="addMessage">
<arg name="param" type="a(ii)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="message"/>
</method>
<signal name="crashed"/>
</interface>
</node>
和 pro 文件
QT += dbus widgets
DBUS_ADAPTORS += shower.xml
HEADERS += shower.h \
message.h
SOURCES += shower.cpp main.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/dbus/wikidbusqt/shower
INSTALLS += target
FORMS += \
Categories.ui
OTHER_FILES += \
shower.xml
我不能编译这个,我得到这个错误日志
20:45:21: Running steps for project wikidbusqt...
20:45:21: Starting: "/usr/lib/x86_64-linux-gnu/qt5/bin/qmake" /home/hector/workspace/wikidbusqt/shower/shower.pro -r -spec linux-g++-64
20:45:21: The process "/usr/lib/x86_64-linux-gnu/qt5/bin/qmake" exited normally.
20:45:21: Starting: "/usr/bin/make"
/usr/lib/x86_64-linux-gnu/qt5/bin/uic ../../wikidbusqt/shower/Categories.ui -o ui_Categories.h
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -fPIE -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_DBUS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++-64 -I../../wikidbusqt/shower -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtDBus -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I. -I. -I. -o shower.o ../../wikidbusqt/shower/shower.cpp
In file included from /usr/include/qt5/QtCore/qvariant.h:48:0,
from /usr/include/qt5/QtCore/QVariant:1,
from ./ui_Categories.h:12,
from ../../wikidbusqt/shower/shower.h:46,
from ../../wikidbusqt/shower/shower.cpp:42:
/usr/include/qt5/QtCore/qmetatype.h:1708:12: error: specialization of 'QMetaTypeId<message>' after instantiation
struct QMetaTypeId< TYPE > \
^
../../wikidbusqt/shower/message.h:53:1: note: in expansion of macro 'Q_DECLARE_METATYPE'
Q_DECLARE_METATYPE( message )
^
/usr/include/qt5/QtCore/qmetatype.h:1708:12: error: redefinition of 'struct QMetaTypeId<message>'
struct QMetaTypeId< TYPE > \
^
../../wikidbusqt/shower/message.h:53:1: note: in expansion of macro 'Q_DECLARE_METATYPE'
Q_DECLARE_METATYPE( message )
^
/usr/include/qt5/QtCore/qmetatype.h:1491:8: error: previous definition of 'struct QMetaTypeId<message>'
struct QMetaTypeId : public QMetaTypeIdQObject<T>
^
In file included from /usr/include/qt5/QtCore/qatomic.h:42:0,
from /usr/include/qt5/QtCore/qvariant.h:45,
from /usr/include/qt5/QtCore/QVariant:1,
from ./ui_Categories.h:12,
from ../../wikidbusqt/shower/shower.h:46,
from ../../wikidbusqt/shower/shower.cpp:42:
/usr/include/qt5/QtCore/qmetatype.h: In instantiation of 'int qMetaTypeId() [with T = message]':
/usr/include/qt5/QtDBus/qdbusmetatype.h:85:29: required from 'int qDBusRegisterMetaType(T*) [with T = message]'
../../wikidbusqt/shower/message.h:28:40: required from here
/usr/include/qt5/QtCore/qglobal.h:679:85: error: invalid application of 'sizeof' to incomplete type 'QStaticAssertFailure<false>'
enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __COUNTER__) = sizeof(QStaticAssertFailure<!!(Condition)>)}
^
/usr/include/qt5/QtCore/qglobal.h:684:47: note: in expansion of macro 'Q_STATIC_ASSERT'
#define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
^
/usr/include/qt5/QtCore/qmetatype.h:1638:5: note: in expansion of macro 'Q_STATIC_ASSERT_X'
Q_STATIC_ASSERT_X(QMetaTypeId2<T>::Defined, "Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system");
^
make: *** [shower.o] Error 1
20:45:24: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project wikidbusqt (kit: Desktop)
When executing step 'Make'
20:45:24: Elapsed time: 00:03.
我不知道发生了什么,我正在按照本教程中概述的步骤操作:https://techbase.kde.org/Development/Tutorials/D-Bus/CustomTypes#DBusChat.pro 但我不知道我忽略了什么。
您只能在 Q_DECLARE_METATYPE
进入范围后调用 qRegisterMetaType
和类似方法。因此,您必须将 registerMetaType()
的主体从 class 移出到 .cpp
文件中:
message.h(相关片段)
...
class message
{
...
/// Register message with the Qt type system.
static void registerMetaType();
...
};
Q_DECLARE_METATYPE( message )
...
message.cpp(整个文件)
#include "message.h"
void message::registerMetaType()
{
qRegisterMetaType<message>("message");
qDBusRegisterMetaType<message>();
}
您不能将 registerMetaType
的超出 class 的定义放入头文件中,因为它会破坏单一定义规则并且链接器会抱怨多重定义的符号。
我的项目源自这个例子:http://doc.qt.io/qt-5/qtdbus-remotecontrolledshower-example.html
有两个进程,shower和controller,controller可以向shower发送简单的消息(我只是把那个项目中的car重命名为shower),把花哨的car GUI改成了一个简单的Widget。我这样做没有问题。 我的问题是当我尝试使用自定义 class
发送消息时#ifndef MESSAGE_H
#define MESSAGE_H
#include <QtDBus>
class message
{
public:
QString articleName;
QString categoryName;
message() : articleName(""), categoryName("") {}
message( QString a, QString b ) : articleName(a), categoryName(b) {}
message(const message &other) : articleName( other.articleName ), categoryName( other.categoryName ) {}
message& operator=(const message &other)
{
articleName = other.articleName;
categoryName = other.categoryName;
return *this;
}
//register Message with the Qt type system
static void registerMetaType()
{
qRegisterMetaType<message>("message");
qDBusRegisterMetaType<message>();
}
friend QDBusArgument &operator<<(QDBusArgument &argument, const message &mess )
{
argument.beginStructure();
argument << mess.articleName;
argument << mess.categoryName;
argument.endStructure();
return argument;
}
friend const QDBusArgument &operator>>(const QDBusArgument &argument, message &mess )
{
argument.beginStructure();
argument >> mess.articleName;
argument >> mess.categoryName;
argument.endStructure();
return argument;
}
};
Q_DECLARE_METATYPE( message )
#endif // MESSAGE_H
然后我在接收消息对象的地方 class 添加了一个方法
#ifndef shower_H
#define shower_H
#include "ui_Categories.h"
#include "message.h"
class shower : public QWidget
{
Q_OBJECT
public:
shower(QWidget *parent = 0);
//shower();
//QRectF boundingRect() const;
public Q_SLOTS:
void accelerate();
void decelerate();
void turnLeft();
void turnRight();
void doThat();
void addMessage( const message &msg );
QString Get( int param );
Q_SIGNALS:
void crashed();
protected:
void timerEvent(QTimerEvent *event);
private:
Ui::Categories ui;
qreal wheelsAngle; // used when applying rotation
qreal speed; // delta movement along the body axis
};
#endif // shower_H
这是我定义花洒界面的xml
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/com/trollech/examples/shower">
<interface name="org.example.Examples.showerInterface">
<method name="accelerate"/>
<method name="decelerate"/>
<method name="turnLeft"/>
<method name="turnRight"/>
<method name="addMessage">
<arg name="param" type="a(ii)" direction="in"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="message"/>
</method>
<signal name="crashed"/>
</interface>
</node>
和 pro 文件
QT += dbus widgets
DBUS_ADAPTORS += shower.xml
HEADERS += shower.h \
message.h
SOURCES += shower.cpp main.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/dbus/wikidbusqt/shower
INSTALLS += target
FORMS += \
Categories.ui
OTHER_FILES += \
shower.xml
我不能编译这个,我得到这个错误日志
20:45:21: Running steps for project wikidbusqt...
20:45:21: Starting: "/usr/lib/x86_64-linux-gnu/qt5/bin/qmake" /home/hector/workspace/wikidbusqt/shower/shower.pro -r -spec linux-g++-64
20:45:21: The process "/usr/lib/x86_64-linux-gnu/qt5/bin/qmake" exited normally.
20:45:21: Starting: "/usr/bin/make"
/usr/lib/x86_64-linux-gnu/qt5/bin/uic ../../wikidbusqt/shower/Categories.ui -o ui_Categories.h
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -fPIE -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_DBUS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++-64 -I../../wikidbusqt/shower -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtDBus -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I. -I. -I. -o shower.o ../../wikidbusqt/shower/shower.cpp
In file included from /usr/include/qt5/QtCore/qvariant.h:48:0,
from /usr/include/qt5/QtCore/QVariant:1,
from ./ui_Categories.h:12,
from ../../wikidbusqt/shower/shower.h:46,
from ../../wikidbusqt/shower/shower.cpp:42:
/usr/include/qt5/QtCore/qmetatype.h:1708:12: error: specialization of 'QMetaTypeId<message>' after instantiation
struct QMetaTypeId< TYPE > \
^
../../wikidbusqt/shower/message.h:53:1: note: in expansion of macro 'Q_DECLARE_METATYPE'
Q_DECLARE_METATYPE( message )
^
/usr/include/qt5/QtCore/qmetatype.h:1708:12: error: redefinition of 'struct QMetaTypeId<message>'
struct QMetaTypeId< TYPE > \
^
../../wikidbusqt/shower/message.h:53:1: note: in expansion of macro 'Q_DECLARE_METATYPE'
Q_DECLARE_METATYPE( message )
^
/usr/include/qt5/QtCore/qmetatype.h:1491:8: error: previous definition of 'struct QMetaTypeId<message>'
struct QMetaTypeId : public QMetaTypeIdQObject<T>
^
In file included from /usr/include/qt5/QtCore/qatomic.h:42:0,
from /usr/include/qt5/QtCore/qvariant.h:45,
from /usr/include/qt5/QtCore/QVariant:1,
from ./ui_Categories.h:12,
from ../../wikidbusqt/shower/shower.h:46,
from ../../wikidbusqt/shower/shower.cpp:42:
/usr/include/qt5/QtCore/qmetatype.h: In instantiation of 'int qMetaTypeId() [with T = message]':
/usr/include/qt5/QtDBus/qdbusmetatype.h:85:29: required from 'int qDBusRegisterMetaType(T*) [with T = message]'
../../wikidbusqt/shower/message.h:28:40: required from here
/usr/include/qt5/QtCore/qglobal.h:679:85: error: invalid application of 'sizeof' to incomplete type 'QStaticAssertFailure<false>'
enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __COUNTER__) = sizeof(QStaticAssertFailure<!!(Condition)>)}
^
/usr/include/qt5/QtCore/qglobal.h:684:47: note: in expansion of macro 'Q_STATIC_ASSERT'
#define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
^
/usr/include/qt5/QtCore/qmetatype.h:1638:5: note: in expansion of macro 'Q_STATIC_ASSERT_X'
Q_STATIC_ASSERT_X(QMetaTypeId2<T>::Defined, "Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system");
^
make: *** [shower.o] Error 1
20:45:24: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project wikidbusqt (kit: Desktop)
When executing step 'Make'
20:45:24: Elapsed time: 00:03.
我不知道发生了什么,我正在按照本教程中概述的步骤操作:https://techbase.kde.org/Development/Tutorials/D-Bus/CustomTypes#DBusChat.pro 但我不知道我忽略了什么。
您只能在 Q_DECLARE_METATYPE
进入范围后调用 qRegisterMetaType
和类似方法。因此,您必须将 registerMetaType()
的主体从 class 移出到 .cpp
文件中:
message.h(相关片段)
...
class message
{
...
/// Register message with the Qt type system.
static void registerMetaType();
...
};
Q_DECLARE_METATYPE( message )
...
message.cpp(整个文件)
#include "message.h"
void message::registerMetaType()
{
qRegisterMetaType<message>("message");
qDBusRegisterMetaType<message>();
}
您不能将 registerMetaType
的超出 class 的定义放入头文件中,因为它会破坏单一定义规则并且链接器会抱怨多重定义的符号。