Как выставить методы и свойства в DBus с помощью QDBusAbstractAdaptor с PyQt4?

Я пытаюсь запустить базовый код на DBus, используя PyQt4, в частности QtDBus. Я использую версию PyQt4 для Python3. У меня уже есть код, который я хочу запустить на Qt (С++), но я хочу, чтобы аналогичный код работал только на 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()

Хотя мне очень нравится использование QtDBus в C++ из-за того, как я хочу структурировать свой большой проект, мне действительно нужно, чтобы объект, доступ к которому осуществляется через DBus, был написан на Python3.


person Mike    schedule 31.07.2012    source источник


Ответы (1)


Есть несколько проблем с вашей программой. Я рекомендую взглянуть на примеры remotecontrolledcar и pingpong из последних исходников PyQt, они очень полезны. Основные моменты, на которые следует обратить внимание:

  • Вы должны передать экземпляр MyServer (не ServerAdaptor) в registerObject()
  • Добавьте декораторы pyqtSlot() к функциям, которые вы хотите предоставить через D-Bus.
  • Вызовите Q_CLASSINFO() в верхней части класса адаптера, а не в его функции __init__()
  • Также установите «Интерфейс D-Bus» с помощью Q_CLASSINFO()
  • В XML-файле самоанализа содержится опечатка («каталог» вместо «направление»)

Вот урезанный пример, который работает для меня (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()
person evadeflow    schedule 01.08.2012
comment
Потрясающий. Спасибо за помощь! Работает именно так, как я хотел. Я обнаружил, что примеры QT хорошо объясняют это в QT, но не в PyQT. Таким образом, свойства работают одинаково с раскрытием самих себя, пока Q_CLASSINFO имеет узлы свойств? (И используя pyProperties или любой другой атрибут). Последнее, что мне нужно сделать, это попробовать порт Windows DBus и запустить его... тогда я готовлю на огне. знак равно - person Mike; 03.08.2012
comment
Да, свойства работают почти так, как вы могли бы ожидать. Я изменил свой пример, чтобы сделать name свойством. Можете ли вы пойти дальше и принять мой ответ? :-} - person evadeflow; 03.08.2012