網上一搜,關於D-Bus和QT的資料不少,但是絕大多數都對傳遞自定義數據類型這個問題閉口不談。看來這個有必要寫個文章記錄一下。
首先要說的是,我這裡不再介紹D-Bus和QDbus的基礎知識,本文直擊要點。另外本文參考了KDE的一些文檔。
需求:使用標准的信號和槽,通過QDBus傳遞自定義的struct或者class數據類型。
首先,需要定義需要通過D-Bus傳遞的自定義數據類型,我們這裡定義一個Message類型:
#include <QtDBus>
class Message
{
public:構造函數等略
friend QDBusArgument &operator<<(QDBusArgument &argument, const Message &message);
friend const QDBusArgument &operator>>(const QDBusArgument &argument, Message &message);
static void registerMetaType();
private:
QString m_strMessage;
};
Q_DECLARE_METATYPE(Message)
可以看到有幾個比較特殊的地方:
首先我們重載了<<和>>兩個運算符,這是將自定義數據類型融合到QT的類型系統所必需的:
QDBusArgument &operator<<(QDBusArgument &argument, const Message& message)
{
argument.beginStructure();
argument << message.m_strMessage;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, Message &message)
{
argument.beginStructure();
argument >> message.m_strMessage;
argument.endStructure();
return argument;
}
其次,這個自定義數據類型需要注冊到QT和D-Bus的類型系統:
void Message::registerMetaType()
{qRegisterMetaType<Message>("Message");
qDBusRegisterMetaType<Message>();
}
有了這個數據類型,就可以寫描述D-Bus接口的XML文件了:
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="demo.Action">
<signal name="messageSent">
<arg name="message" type="a(i)" direction="out"/>
<annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="Message"/>
</signal>
<method name="sendMessage">
<arg name="message" type="a(i)" direction="in"/>
<annotation name="com.trolltech.QtDBus.QtTypeName.In0" value="Message"/>
</method>
</interface>
</node>
這裡有兩個特殊點,一個是參數的數據類型,因為是我們自定義的,不存在於D-Bus規范中,所以參數的type在這裡可以亂寫。另一個就是,既然是自定義的,就要說明這個自定義的數據類型到底是啥(在這裡是Message)。
OK,有了上面這些啰嗦的准備工作,下面調用QT自帶的D-Bus工具,就可以自動生成相關的接口和代理類了:
qdbusxml2cpp Chat.xml -i Message.h -a MessageAdaptor
qdbusxml2cpp Chat.xml -i Message.h -p MessageInterface
後續就是標准的調用QDBus過程了,本文不再廢話,請參考其他入門資料。大體上就是這樣:
接收:
connect(&m_MessageInterface, SIGNAL(messageSent(Message)), SLOT(onMessageSent(Message)));
發送:
Message message(…);
m_MessageInterface.sendMessage(message);