Процесс QDBusPendingCallWatcher приводит к PyQt4?
Я хотел бы сделать неблокирующий вызов функции в удаленном сервисе D-Bus с использованием PyQt4.QtDBus. Адаптируясь из документации Qt C++, я разработал следующую тестовую программу:
from PyQt4 import QtCore, QtDBus
class DeviceInterface(QtDBus.QDBusAbstractInterface):
def __init__(self, service, path, connection, parent=None):
super().__init__(service, path, 'org.freedesktop.UDisks.Device',
connection, parent)
@QtCore.pyqtSlot(QtDBus.QDBusArgument)
def callFinishedSlot(self, arg):
print("Got result:", arg)
if __name__ == '__main__':
import sys
app = QtCore.QCoreApplication(sys.argv)
dev = DeviceInterface('org.freedesktop.UDisks',
'/org/freedesktop/UDisks/devices/sda1',
QtDBus.QDBusConnection.systemBus(), app)
async = dev.asyncCall("FilesystemListOpenFiles");
watcher = QtDBus.QDBusPendingCallWatcher(async, dev)
watcher.finished.connect(dev.callFinishedSlot)
sys.exit(app.exec_())
Вроде работает. Когда я запускаю его, он печатает:
Got result: <PyQt4.QtDBus.QDBusPendingCallWatcher object at 0xb740c77c>
Проблема в том, что я не знаю, как конвертировать QDBusPendingCallWatcher
к чему-то (например, QDBusMessage
) что я могу извлечь результаты. Пример из документации C++ делает это:
void MyClass.callFinishedSlot(QDBusPendingCallWatcher *call)
{
QDBusPendingReply<QString, QByteArray> reply = *call;
if (reply.isError()) {
showError();
} else {
QString text = reply.argumentAt<0>();
QByteArray data = reply.argumentAt<1>();
showReply(text, data);
}
call->deleteLater();
}
Может кто-нибудь сказать мне, как перевести слот C++ в то, что будет работать с PyQt4? (Я использую PyQt4.9.1 с Qt 4.8.1.)
1 ответ
Ладно, похоже, хитрость заключается в создании QDBusPendingReply
от QDBusPendingCallWatcher
экземпляр (большое спасибо Филу Томпсону за то, что он указал на это в списке рассылки PyQt). Оказывается, эта же техника работает и в C++. У меня был неправильный путь к объекту UDisk в моем исходном коде, плюс несколько других мелких опечаток, так что вот полный, рабочий пример для потомков:
from PyQt4 import QtCore, QtDBus
class DeviceInterface(QtDBus.QDBusAbstractInterface):
def __init__(self, service, path, connection, parent=None):
super().__init__(service, path, 'org.freedesktop.UDisks.Device',
connection, parent)
def callFinishedSlot(self, call):
# Construct a reply object from the QDBusPendingCallWatcher
reply = QtDBus.QDBusPendingReply(call)
if reply.isError():
print(reply.error().message())
else:
print(" PID UID COMMAND")
print("------- ------- ------------------------------------")
for pid, uid, cmd in reply.argumentAt(0):
print("{0:>7d} {1:>7d} {2}".format(pid, uid, cmd))
# Important: Tell Qt we are finished processing this message
call.deleteLater()
if __name__ == '__main__':
import sys
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
app = QtCore.QCoreApplication(sys.argv)
dev = DeviceInterface('org.freedesktop.UDisks',
'/org/freedesktop/UDisks/devices/sda1',
QtDBus.QDBusConnection.systemBus(), app)
async = dev.asyncCall("FilesystemListOpenFiles");
watcher = QtDBus.QDBusPendingCallWatcher(async, dev)
watcher.finished.connect(dev.callFinishedSlot)
sys.exit(app.exec_())
Это должно работать на большинстве последних дистрибутивов Linux и является хорошим примером использования PyQt для вызова метода D-Bus, который возвращает составной тип.