通过 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 的定义放入头文件中,因为它会破坏单一定义规则并且链接器会抱怨多重定义的符号。