2016-09-28 4 views
1

Проблемы:qdbusxml2cpp генерирует QDBusAbstractInterface суб-класса, методы выборка D-Bus отвечает асинхронно, но я хочу, чтобы быть синхронными (т.е. он должен блокировать, пока не будет получен ответ).Как создать синхронный интерфейс с qdbusxml2cpp? Резюме

XML вход:

<?xml version="1.0"?> 
<!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="some.interface.Foo"> 
    <method name="GetValues"> 
    <arg name="values" type="a(oa{sv})" direction="out"/> 
     <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList&lt;SomeStruct&gt;" /> 
    </method> 
</interface> 
</node> 

С помощью этой команды заголовка и .cpp файла (не показан) генерируется:

qdbusxml2cpp-qt5 -c InterfaceFoo -p interface_foo foo.xml 

Сгенерированный заголовок:

class InterfaceFoo: public QDBusAbstractInterface 
{ 
    Q_OBJECT 
public: 
    static inline const char *staticInterfaceName() 
    { return "some.interface.Foo"; } 

public: 
    InterfaceFoo(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); 

    ~InterfaceFoo(); 

public Q_SLOTS: // METHODS 
    inline QDBusPendingReply<QList<SomeStruct> > GetValues() 
    { 
     QList<QVariant> argumentList; 
     // NOTICE THIS LINE. 
     return asyncCallWithArgumentList(QStringLiteral("GetValues"), argumentList); 
    } 

Q_SIGNALS: // SIGNALS 
}; 

namespace some { 
namespace interface { 
    typedef ::InterfaceFoo Foo; 
} 
} 
#endif 

Как вам может видеть, что генерируемый метод asyncCallWithArgumentList() является асинхронным: он ожидает быть connect() ed в слот, который запускается при получении ответа D-Bus.

Вместо этого я хочу, чтобы быть в состоянии сделать:

some::interface::Foo *interface = new some::interface::Foo("some::interface", "/Foo", QDBusConnection::systemBus(), this); 
// THIS SHOULD block until a reply is received or it times out. 
QList<SomeStruct> data = interface->GetValues(); 
+1

Mabye не решение, которое вы ищете, но вы можете называть 'interface-> GetValues ​​(). Value()' блокировать до тех пор, пока не поступит ответ –

ответ

1

Вы можете использовать value() на возвращаемое значение, чтобы заблокировать, с GetValues() как есть:

auto reply = interface->GetValues(); 
auto data = reply.value<QList<QVariant>>(); 

Увы, генерируемый интерфейс должен быть создан один раз, а затем стать частью ваших источников. Вы должны изменить его, чтобы использовать блокирующий вызов, и добавить преобразование из варианта к конкретному типу:

inline QDBusPendingReply<QList<SomeStruct>> GetValues() 
{ 
    QList<QVariant> argumentList; 
    auto msg = callWithArgumentList(QDBus::Block, QStringLiteral("GetValues"), argumentList); 
    Q_ASSERT(msg.type() == QDBusMessage::ReplyMessage); 
    QList<SomeStruct> result; 
    for (auto const & arg : msg.arguments()) 
     result << arg.value<SomeStruct>(); 
    return result; 
} 

Наконец, вы можете захотеть пересмотреть делает его синхронным: реальный мир является асинхронным, поэтому писать код как если бы это было не так часто контрпродуктивно. Если ваш код работает в основном потоке и есть gui, вы будете плохо работать с пользователем. Если вы перемещаете свой код в рабочий поток, вы теряете весь поток только для поддержки синхронного стиля кодирования. Даже если вы пишете то, что составляет неинтерактивную пакетную утилиту/услугу, вы потенциально увеличиваете задержку, например. не выдавая вызовы параллельно.

+0

Большое спасибо за ответ и совет в последнем абзаце. Это помогло! – DBedrenko

+0

Хотя в верхней части сгенерированных файлов источника/заголовка говорится: «Это автоматически сгенерированный файл. Не редактируйте! Все внесенные в него изменения будут потеряны». который звучит так, будто он не предназначен для модификации, а файл .xml является основным файлом ... – DBedrenko

+0

@Dee Это ваша вселенная, вы ее хозяин, вы устанавливаете правила. Вы используете инструмент. Это не дар богов. –

Смежные вопросы