问题
I am trying to get some basic code running on DBus using PyQt4, specifically QtDBus. I am using a Python3 version of PyQt4. I have already gotten the code I want running on Qt (c++) but I want to get similar code running using only Python. I want to expose Methods, signals/slots and properties on DBus for other Python code to call.
In Qt you use the Q_CLASSINFO macro/function to do DBus introspection. While I have pulled in the Q_CLASSINFO method, i can't get it to produce the same type of functionality. As far as I can tell there is zero documentation on the Q_CLASSINFO method, so I'm not sure if there is another way. Using D-Feet i can clearly see that no methods are exposed automatically, so I'm kind of stuck.
Here is what I have so far.
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()
While I really like the using QtDBus in C++ because of how I want to structure this large project of mine, I really need the object accessed via DBus to be written in Python3.
回答1:
There are several problems with your program. I recommend having a look at the remotecontrolledcar
and pingpong
examples from the latest PyQt sources, they're pretty helpful. The main points to note are:
- You should pass a
MyServer
instance (notServerAdaptor
) toregisterObject()
- Add
pyqtSlot()
decorators to the functions you wish to expose via D-Bus - Call
Q_CLASSINFO()
at the top of the adaptor class, not in its__init__()
function - Also set the "D-Bus Interface" using
Q_CLASSINFO()
- Your introspection XML contained a typo ('directory' instead of 'direction')
Here's a stripped-down example that works for me (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()
来源:https://stackoverflow.com/questions/11731709/how-does-one-expose-methods-and-properties-on-dbus-using-a-qdbusabstractadaptor