如何使用带有PyQt4的QDBusAbstractAdaptor在DBus上公开方法和属性



我正在尝试使用PyQt4,特别是QtDBus,在DBus上运行一些基本代码。我使用的是PyQt4的Python3版本。我已经得到了我想在Qt(c++)上运行的代码,但我想只使用Python运行类似的代码。我想在DBus上公开方法、信号/插槽和属性,供其他Python代码调用。

在Qt中,您使用Q_CLASSINFO宏/函数来执行DBus内省。虽然我已经引入了Q_CLASSINFO方法,但我无法让它产生相同类型的功能。据我所知,Q_CLASSINFO方法没有任何文档,所以我不确定是否有其他方法。使用D-Feet,我可以清楚地看到没有任何方法是自动暴露的,所以我有点卡住了。

这是我迄今为止所拥有的。

from PyQt4 import QtDBus
from PyQt4.QtCore import QCoreApplication, QObject, Q_CLASSINFO, pyqtSlot, pyqtProperty
from PyQt4.QtDBus import QDBusConnection, QDBusAbstractAdaptor
SERVICE = 'com.home.dbus'
class MyServer(QObject):

    def __init__(self):
        QObject.__init__(self)
        self.__dbusAdaptor = ServerAdaptor(self)
    def close(self):
        pass
    def echo(self, value):
        echoed = 'Received {0}'.format(value)
        return echoed
    def name(self):
        return 'myname'
    def dbus_adaptor(self):
        return self.__dbusAdaptor
class ServerAdaptor(QDBusAbstractAdaptor):
    """ This provides the DBus adaptor to the outside world"""
    def __init__(self, parent):
        super().__init__(parent)
        self.__parent = parent
        Q_CLASSINFO("D-Bus Introspection",
        "  <interface name="com.home.dbus">n"
        "    <method name="name">n"
        "      <arg direction="out" type="s" name="name"/>n"
        "    </method>n"
        "    <method name="echo">n"
        "      <arg direction="in" type="s" name="phrase"/>n"
        "      <arg directory="out" type="s" name="echoed"/>n"
        "    </method>n"
        "  </interface>n")
    def close(self):
        parent.close()
    def echo(self, value):
        return parent.echo(value)
    def name(self):
        return parent.name
def start():
    app = QCoreApplication([])
    if QDBusConnection.sessionBus().isConnected() == False:
        print('Cannot connect to D-Bus session bus')
        return
    print('Starting')
    server = MyServer()
    if not QDBusConnection.sessionBus().registerService(SERVICE):
        print('Unable to register service name')
        return
    if not QDBusConnection.sessionBus().registerObject('/mydbus', server.dbus_adaptor):
        print('Unable to register object at service path')
        return
    app.exec();
    print('Exited')
if __name__ == '__main__':
    start()

虽然我真的很喜欢在C++中使用QtDBus,因为我想构建我的这个大型项目,但我真的需要通过DBus访问的对象用Python3编写。

您的程序有几个问题。我建议您看看最新PyQt源中的remotecontrolledcarpingpong示例,它们非常有用。需要注意的要点是:

  • 您应该将MyServer实例(而不是ServerAdaptor)传递给registerObject()
  • pyqtSlot()装饰器添加到希望通过D-Bus公开的函数中
  • 在适配器类的顶部调用Q_CLASSINFO(),而不是在其__init__()函数中调用
  • 同时使用Q_CLASSINFO()设置"D总线接口"
  • 您的内省XML包含一个拼写错误("directory"而不是"direction")

下面是一个适用于我的精简示例(Python 3.2.3/Qt 4.8.2/PyQt 4.9.4):

from PyQt4 import QtDBus
from PyQt4.QtCore import (QCoreApplication, QObject, Q_CLASSINFO, pyqtSlot,
                          pyqtProperty)
from PyQt4.QtDBus import QDBusConnection, QDBusAbstractAdaptor
class MyServer(QObject):
    def __init__(self):
        QObject.__init__(self)
        self.__dbusAdaptor = ServerAdaptor(self)
        self.__name = 'myname'
    def echo(self, value):
        return'Received: {0}'.format(value)
    @property
    def name(self):
        return self.__name
    @name.setter
    def name(self, value):
        self.__name = value

class ServerAdaptor(QDBusAbstractAdaptor):
    """ This provides the DBus adaptor to the outside world"""
    Q_CLASSINFO("D-Bus Interface", "com.home.dbus")
    Q_CLASSINFO("D-Bus Introspection",
    '  <interface name="com.home.dbus">n'
    '    <property name="name" type="s" access="readwrite"/>n'
    '    <method name="echo">n'
    '      <arg direction="in" type="s" name="phrase"/>n'
    '      <arg direction="out" type="s" name="echoed"/>n'
    '    </method>n'
    '  </interface>n')
    def __init__(self, parent):
        super().__init__(parent)
    @pyqtSlot(str, result=str)
    def echo(self, phrase):
        return self.parent().echo(phrase)
    @pyqtProperty(str)
    def name(self):
        return self.parent().name
    @name.setter
    def name(self, value):
        self.parent().name = value
def start():
    app = QCoreApplication([])
    bus = QDBusConnection.sessionBus()
    server = MyServer()
    bus.registerObject('/mydbus', server)
    bus.registerService('com.home.dbus')
    app.exec()
if __name__ == '__main__':
    start()

最新更新