http://wiki.linuxformat.ru/wiki/index.php?title=LXF107:Qt4&feed=atom&action=historyLXF107:Qt4 - История изменений2024-03-28T21:55:11ZИстория изменений этой страницы в викиMediaWiki 1.19.20+dfsg-0+deb7u3http://wiki.linuxformat.ru/wiki/index.php?title=LXF107:Qt4&diff=8495&oldid=prevYaleks в 17:30, 22 августа 20092009-08-22T17:30:06Z<p></p>
<table class='diff diff-contentalign-left'>
<col class='diff-marker' />
<col class='diff-content' />
<col class='diff-marker' />
<col class='diff-content' />
<tr valign='top'>
<td colspan='2' style="background-color: white; color:black;">← Предыдущая</td>
<td colspan='2' style="background-color: white; color:black;">Версия 17:30, 22 августа 2009</td>
</tr><tr><td colspan="2" class="diff-lineno">Строка 33:</td>
<td colspan="2" class="diff-lineno">Строка 33:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Рассмотрим объект, реализующий интерфейс нашего приложениясервера (полный текст вы найдете на диске в архиве '''clipboarviewer.tar.gz'''):</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Рассмотрим объект, реализующий интерфейс нашего приложениясервера (полный текст вы найдете на диске в архиве '''clipboarviewer.tar.gz'''):</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div><source lang=<del class="diffchange diffchange-inline">c</del>></div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><source lang=<ins class="diffchange diffchange-inline">cpp-qt</ins>></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include <QApplication></div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include <QApplication></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include <QtCore></div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include <QtCore></div></td></tr>
<tr><td colspan="2" class="diff-lineno">Строка 87:</td>
<td colspan="2" class="diff-lineno">Строка 87:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Перейдем теперь к функции main(), которая создает и регистрирует объект, реализующий интерфейс.</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Перейдем теперь к функции main(), которая создает и регистрирует объект, реализующий интерфейс.</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div><source lang=<del class="diffchange diffchange-inline">c</del>></div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><source lang=<ins class="diffchange diffchange-inline">cpp-qt</ins>></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include "QCBAdapter.h"</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include "QCBAdapter.h"</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  int main(int argc, char **argv)</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  int main(int argc, char **argv)</div></td></tr>
<tr><td colspan="2" class="diff-lineno">Строка 143:</td>
<td colspan="2" class="diff-lineno">Строка 143:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>сможет использовать средства ''Qt'':</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>сможет использовать средства ''Qt'':</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div><source lang=<del class="diffchange diffchange-inline">c</del>></div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><source lang=<ins class="diffchange diffchange-inline">cpp-qt</ins>></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include <stdio.h></div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include <stdio.h></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include <dbus/dbus.h></div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>  #include <dbus/dbus.h></div></td></tr>
<tr><td colspan="2" class="diff-lineno">Строка 195:</td>
<td colspan="2" class="diff-lineno">Строка 195:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>''sendlines'' (возможно, это первая консольная программа ''Qt'', которую вы видите).</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>''sendlines'' (возможно, это первая консольная программа ''Qt'', которую вы видите).</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div><source lang=<del class="diffchange diffchange-inline">c</del>></div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><source lang=<ins class="diffchange diffchange-inline">cpp-qt</ins>></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>   #include <stdio.h></div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>   #include <stdio.h></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>   #include <QtCore></div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>   #include <QtCore></div></td></tr>
<tr><td colspan="2" class="diff-lineno">Строка 261:</td>
<td colspan="2" class="diff-lineno">Строка 261:</td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Вы, наверное, заметили, что в отношении работы с ''D-Bus'' программа ''sendlines'' не проще, чем написанная на языке ''C''. Пришло время показать, как ''Qt'' действительно может упростить работу с ''D-Bus''. В идеале нам просто хотелось бы иметь класс с тем же набором методов, что и у интерфейса удаленного приложения, так, чтобы при вызове метода локального класса вызывался соответствующий метод интерфейса удаленного приложения. В некоторых случаях этот идеал достижим, причем без особых усилий. Это возможно, если у нас есть описание интерфейса на языке '''XML'''. Сейчас же мы рассмотрим более общий вариант решения:</div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>Вы, наверное, заметили, что в отношении работы с ''D-Bus'' программа ''sendlines'' не проще, чем написанная на языке ''C''. Пришло время показать, как ''Qt'' действительно может упростить работу с ''D-Bus''. В идеале нам просто хотелось бы иметь класс с тем же набором методов, что и у интерфейса удаленного приложения, так, чтобы при вызове метода локального класса вызывался соответствующий метод интерфейса удаленного приложения. В некоторых случаях этот идеал достижим, причем без особых усилий. Это возможно, если у нас есть описание интерфейса на языке '''XML'''. Сейчас же мы рассмотрим более общий вариант решения:</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"></td></tr>
<tr><td class='diff-marker'>−</td><td style="background: #ffa; color:black; font-size: smaller;"><div><source lang=<del class="diffchange diffchange-inline">c</del>></div></td><td class='diff-marker'>+</td><td style="background: #cfc; color:black; font-size: smaller;"><div><source lang=<ins class="diffchange diffchange-inline">cpp-qt</ins>></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>   #include <QtDebug></div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>   #include <QtDebug></div></td></tr>
<tr><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>   #include <QtCore></div></td><td class='diff-marker'> </td><td style="background: #eee; color:black; font-size: smaller;"><div>   #include <QtCore></div></td></tr>
</table>Yalekshttp://wiki.linuxformat.ru/wiki/index.php?title=LXF107:Qt4&diff=8481&oldid=prevCrazy Rebel: викификация, оформление, иллюстрация2009-08-20T11:00:05Z<p>викификация, оформление, иллюстрация</p>
<p><b>Новая страница</b></p><div>: '''Программирование в стиле ''Qt''''' Осваиваем технологии, лежащие в основе нашумевшего KDE4<br />
<br />
[[Категория:Учебники]] {{Цикл/Qt4}}<br />
<br />
==Обмен сообщениями==<br />
<br />
'''ЧАСТЬ 6''' За последние годы ''D-Bus'' стал стандартом де-факто для межпроцессного взаимодействия на рабочем столе Linux. Что здесь может предложить ''Qt''? Разбирается '''Андрей Боровский'''.<br />
<br />
{{Врезка|left|Заголовок=Минуточку внимания!|Содержание=<br />
Берясь за ''QtDBus'', имейте в виду: фирменная документация по<br />
нему зияет пробелами (чего не скажешь о других модулях). Это<br />
тем более странно, что ''QtDBus'' появился в ''Qt 4'' уже давно. Нет,<br />
описания классов модуля ''QtDBus'' присутствуют, и довольно подробны, но вот, например, демонстрационное приложение, описанное на странице http://doc.trolltech.com/4.4/qdbusadaptorexample.html, не только не работает, но даже и не компилируется (текст<br />
этого примера не менялся, кстати, с версии ''Qt 4.2'').|Ширина=200px}}<br />
<br />
В отличие от возможностей ''Qt 4.x'', с которыми мы познакомились ранее, появившийся в ''Qt 4.2'' модуль ''QtDBus'' присутствует только в версиях ''Qt'', предназначенных для Unix-систем. Объясняется это, конечно же, тем, что полнофункциональной версии ''D-Bus'' для Windows не существует (хотя работы в этом направлении ведутся). Мы уже рассматривали архитектуру шины<br />
''D-Bus'' в [[LXF99:D-Bus|LXF99]], и там была высказана мысль, что программуклиент ''D-Bus'', которая только обращается к сервисам другого приложения, нетрудно написать даже на «голом» ''C''. С сервером дела<br />
обстоят сложнее: он должен уметь обрабатывать сообщения ''D-Bus'',<br />
поступающие асинхронно. ''QtDBus'' упрощает решение этой задачи<br />
настолько, насколько это вообще возможно. В качестве демонстрации возможностей ''QtDBus'' мы напишем программу-сервер, которая<br />
будет предоставлять доступ к буферу обмена X-Window консольным приложениям. Во времена господства MS-DOS и Windows 3.1<br />
существовал DOSовский текстовый редактор (название я, к сожалению, уже не помню), который, будучи запущен в DOS-окне Windows,<br />
мог обмениваться данными с буфером обмена Windows. Делалось это с помощью какого-то хитроумного прерывания, и мне тогда<br />
казалось, что это очень круто. Нечто подобное, только для ''X'', мы сейчас и напишем.<br />
<br />
===Программа-сервер===<br />
<br />
Каждое приложение-сервер ''D-Bus'' должно предоставлять как<br />
минимум один интерфейс (то есть описание набора методов, к<br />
которым можно обратиться при помощи ''D-Bus'' из другого приложения). Интерфейсы ''D-Bus'' предоставляются объектами. И если на<br />
уровне ''D-Bus'' объект – понятие скорее условное, то при программировании сервера ''D-Bus'' в ''Qt 4'' самый простой способ объявить интерфейс заключается в том, чтобы реализовать класс, предоставляющий требуемый интерфейс, а затем создать объект этого<br />
класса и зарегистрировать его в качестве поставщика интерфейса.<br />
Рассмотрим объект, реализующий интерфейс нашего приложениясервера (полный текст вы найдете на диске в архиве '''clipboarviewer.tar.gz'''):<br />
<br />
<source lang=c><br />
#include <QApplication><br />
#include <QtCore><br />
#include <QtDBus><br />
#include <QClipboard><br />
class QCBAdapter: public QDBusAbstractAdaptor<br />
{<br />
Q_OBJECT<br />
Q_CLASSINFO("D-Bus Interface", "DBus.Manager.QClipboard")<br />
Q_PROPERTY(QString cbContent READ content WRITE setContent)<br />
private:<br />
QApplication *app;<br />
public:<br />
QCBAdapter(QApplication *application)<br />
: QDBusAbstractAdaptor(application)<br />
{<br />
cb = QApplication::clipboard();<br />
}<br />
Q_INVOKABLE QString content()<br />
{<br />
printf("Запрос содержимого буфера обмена\n");<br />
return cb->text();<br />
}<br />
Q_INVOKABLE void setContent(const QString &newContent)<br />
{<br />
printf("Содержимое буфера обмена изменено\n");<br />
cb->setText(newContent);<br />
}<br />
public slots:<br />
Q_NOREPLY void emptyClipboard()<br />
{<br />
cb->clear();<br />
}<br />
private:<br />
QClipboard * cb;<br />
};<br />
</source><br />
<br />
Помимо прочего, мы включаем в исходный текст заголовочный<br />
файл ''QtDBus''. Кстати, не забудьте добавить строку<br />
<br />
QT += D-Bus<br />
<br />
в '''.pro'''-файл вашего приложения. Основой всех классов, реализующих интерфейсы ''D-Bus'', должен быть класс '''QDBusAbstractAdaptor'''. От него и происходит наш класс '''QCBAdapter'''. Макрос '''Q_CLASSINFO()'''<br />
позволяет определить имя экспортируемого интерфейса в формате, принятом в ''D-Bus'' (один класс может экспортировать несколь-<br />
ко интерфейсов). Интерфейс нашего класса состоит из свойства<br />
'''cbContent''', позволяющего получить доступ к текстовому содержимому буфера обмена (если таковое имеется) и вспомогательных функций: '''content()''' – для чтения содержимого буфера обмена и '''setContent()''' – для его записи. Обратите внимание на то, что оба метода помечены макросом '''Q_INVOKABLE'''. Это необходимо<br />
для того, чтобы программы, которые не умеют выполнять маршаллинг свойств интерфейса, могли обратиться к ним напрямую.<br />
Остальные элементы класса '''QCBAdapter''' не должны вызвать вопросов. Получив указатель на глобальный объект класса '''QClipboard''', мы манипулируем содержимым буфера обмена с помощью методов<br />
'''QClipboard::setText()''' и '''clear()'''. Наш интерфейс предназначен для<br />
чтения и записи только текстовой информации, но консольной программе, скорее всего, большего и не потребуется.<br />
<br />
Перейдем теперь к функции main(), которая создает и регистрирует объект, реализующий интерфейс.<br />
<br />
<source lang=c><br />
#include "QCBAdapter.h"<br />
int main(int argc, char **argv)<br />
{<br />
QApplication app(argc, argv);<br />
QCBAdapter * adapter = new QCBAdapter(&app);<br />
QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "DBus.Manager.QClipboard");<br />
if (connection.isConnected())<br />
printf("Соединение установлено\n");<br />
if (!connection.registerService("DBus.Manager.QClipboard")) {<br />
printf("Не могу зарегистрировать сервис\n");<br />
exit(1);<br />
}<br />
if (!connection.registerObject("/QClipboard", adapter, QDBusConnection::ExportAllContents)) {<br />
printf("Не могу зарегистрировать объект\n");<br />
exit(1);<br />
}<br />
app.exec();<br />
}<br />
</source><br />
<br />
Прежде всего, обратите внимание на то, что в нашей программе<br />
отсутствуют графические элементы. Они нам и не нужны – приложение ''ClipboardViewer'' должно выполняться как сервер. При этом следует учесть, что хотя программа ''ClipboardViewer'' не создает никаких<br />
окон, она связывается с ''X''-сервером (иначе как бы она смогла получить доступ к буферу обмена?), а значит, является полноценным приложением ''X''. После того как мы создали объекты классов '''QApplication''' и '''QCBAdapter''', необходимо выполнить соединение с демоном ''D-Bus''.<br />
Напомню, что в рамках архитектуры ''D-Bus'' любые две программы<br />
могут создать собственную шину ''D-Bus'', однако существуют две стандартные шины – системная ''System Bus'' и пользовательская ''Session Bus''. Наш сервер буфера обмена проще всего подключить к пользовательской шине.<br />
<br />
Соединение ''Qt''-программы с ''D-Bus'' инкапсулируется объектом<br />
класса '''QDBusConnection'''. Мы создаем его с помощью статического<br />
метода '''connectToBus()'''. Вторым аргументом данного метода должно<br />
быть имя соединения, которое программы-клиенты будут использовать для подключения к нашему серверу. Напомню, что по своей<br />
структуре оно напоминает доменное имя Интернета, и если бы у<br />
нашей программы был свой сайт, его имя можно было бы включить<br />
в имя соединения. Многие имена соединений, не связанные с сайтами, все равно начинаются с префиксов '''org.*''' или '''com.*''', но, как мы покажем на практике, следование этому правилу вовсе не является<br />
обязательным.<br />
<br />
Установив соединение с демоном, мы можем зарегистрировать имя сервиса, предоставляемого нашим сервером. Оно имеет ту же структуру, что и имя соединения, и может совпадать с<br />
ним (обратите внимание, что имя сервиса должно совпадать с<br />
именем интерфейса, указанным в объявлении класса адаптера с<br />
помощью '''Q_CLASSINFO()'''). Как вы уже догадались, регистрация<br />
сервиса выполняется методом '''registerService()''' объекта класса<br />
'''QDBusConnection'''.<br />
<br />
Нам осталось лишь зарегистрировать объект, реализующий сервис – это выполняется методом '''registerObject()'''. Первый аргумент<br />
метода – путь к объекту, который используется системой ''D-Bus'' для его идентификации. Выбор '''/QClipboard''' – чисто произвольный, можно указать любое другое значение, например, '''/the/longest/path/to/the/object'''. Последний аргумент метода '''registerObject()''' определяет, какие элементы класса адаптера войдут в описание интерфейса ''D-Bus'' и<br />
станут доступными удаленному приложению. По сути дела, мы сталкиваемся здесь с той же проблемой видимости элементов класса за<br />
пределами приложения, что и в случае со сценариями ''Qt''. Константа '''QDBusConnection::ExportAllContents''' делает класс-адаптер максимально видимым для удаленных приложений, но даже при ее использовании другим программам будет доступно не так уж и много. Например, программа-клиент ''D-Bus'' сможет обращаться только к методам,<br />
помеченным как '''Q_INVOKABLE'''. Если все прошло успешно, нам остается запустить цикл обработки сообщений нашего приложения.<br />
<br />
===Клиент на языке ''С''===<br />
<br />
Настало время написать программу-клиент для взаимодействия<br />
с сервером. Чтобы продемонстрировать универсальный характер<br />
''D-Bus'', напишем сначала программу на языке C. Она естественно, не<br />
сможет использовать средства ''Qt'':<br />
<br />
<source lang=c><br />
#include <stdio.h><br />
#include <dbus/dbus.h><br />
int main (int argc, char **argv)<br />
{<br />
DBusConnection * connection;<br />
DBusError error;<br />
DBusMessage *call;<br />
char * text = "Этот текст будет передан в буфер обмена X-Window";<br />
dbus_error_init(&error);<br />
connection = DBus_bus_get(DBUS_BUS_SESSION, &error);<br />
if (!connection) {<br />
printf("Не могу установить соединение\n", error.message);<br />
dbus_error_free(&error);<br />
return 1;<br />
}<br />
call = DBus_message_new_method_call("DBus.Manager.QClipboard", "/<br />
QClipboard", "DBus.Manager.QClipboard", "setContent");<br />
dbus_message_append_args (call, DBus_TYPE_STRING, &text, DBus_<br />
TYPE_INVALID);<br />
if (!dbus_connection_send(connection, call, NULL)) {<br />
printf("Не могу отправить сообщение\n");<br />
}<br />
dbus_connection_flush(connection);<br />
printf("%s\n", text);<br />
dbus_message_unref(call);<br />
dbus_connection_unref(connection);<br />
return 0;<br />
}<br />
</source><br />
<br />
Программа, исходный текст которой вы найдете в файле<br />
'''sendcontent.c''' в архиве '''clipclients.tar.gz''', записывает строку текста в<br />
буфер обмена ''X'' и распечатывает ее же в окне консоли. Для компиляции программы следует использовать команду<br />
<br />
gcc sendcontent.c `pkg-config --cflags dbus-1` `pkg-config --libs dbus-1` -o sendcontent<br />
<br />
{{Врезка|Содержание=[[Изображение:LXF107_78_1.jpg|Рис. 1|300px]]Рис. 1. В наше прогрессивное время никакие «хитроумные прерывания» не нужны – ''D-Bus'' запросто передаст текст из консоли в окно ''Kwrite''.|Ширина=300px}}<br />
<br />
Разбирать подробно работу программы ''sendcontent'' мы не будем,<br />
так как она не имеет отношения к ''Qt'', и, к тому же, фактически представляет собой сокращенный вариант примера из статьи, опубликованной в [[LXF99:D-Bus|LXF99]]. Заметим только, что функция '''dbus_message_new_method_call()''' использует имя соединения, путь к объекту и имя сервиса, заданные нами в программе-сервере.<br />
<br />
Запустите программу ''ClipBoardViewer'' в окне консоли. Затем в<br />
другом окне запустите программу ''sendcontent''. После этого вы сможете вставить переданную консольной программой ''sendcontent'' строку в буфер обмена ''X-Window'' (рис. 1).<br />
<br />
===Базовый клиент ''D-Bus''===<br />
<br />
Теперь посмотрим, как можно решить ту же задачу базовыми средствами ''Qt''. Мы напишем настоящую консольную ''Qt''-программу. У<br />
нее нет объекта '''QApplication''', нет доступа к объекту '''QClipboard''', а<br />
значит, для передачи данных в буфер обмена ''X'' ей придется воспользоваться нашим сервером. Ниже приводится текст программы<br />
''sendlines'' (возможно, это первая консольная программа ''Qt'', которую вы видите).<br />
<br />
<source lang=c><br />
#include <stdio.h><br />
#include <QtCore><br />
#include <QtDBus><br />
int main(int argc, char **argv)<br />
{<br />
QCoreApplication app(argc, argv);<br />
QDBusConnection connection = QDBusConnection::connectToBus(QDBusConnection::SessionBus, "example.sendlines");<br />
if (connection.isConnected())<br />
printf("Соединение установлено\n");<br />
else {<br />
printf("Не могу установить соединение\n");<br />
return 1;<br />
}<br />
while(true) {<br />
QString string = "";<br />
int ch;<br />
while ((ch = getchar()) != '\n')<br />
string += ch;<br />
QDBusMessage msg = QDBusMessage::createMethodCall("DBus.Manager.QClipboard", "/QClipboard", "DBus.Manager.QClipboard", "setContent");<br />
QList<QVariant> args;<br />
args.append(QVariant(string));<br />
msg.setArguments(args);<br />
connection.send(msg);<br />
QCoreApplication::processEvents();<br />
}<br />
}<br />
</source><br />
<br />
Модуль '''QtGUI''' включается по умолчанию во все проекты ''Qt 4'',<br />
поэтому при создании консольного приложения ''Qt'' в файл '''.pro''', помимо строки<br />
<br />
QT += D-Bus<br />
<br />
следует добавить также<br />
<br />
QT –= gui<br />
<br />
Теперь компоненты графического приложения будут недоступны нашему проекту. Вместо класса '''QApplication''' мы используем<br />
'''QCoreApplication'''. Вместо вызова метода '''exec()''' объекта '''QApplication'''<br />
мы «вручную» создаем цикл обработки событий с помощью статического метода '''QCoreApplication::processEvents()'''. Но самое интересное в нашей программе, конечно, не это.<br />
<br />
Прежде всего, нам опять понадобится объект '''QDBusConnection''',<br />
который мы создаем точно так же, как и в программе ''ClipboardViewer''.<br />
Далее наша программа входит в цикл ввода строк (из которого ее<br />
можно вывести только с помощью комбинации '''Ctrl-C'''). После того,<br />
как пользователь завершает ввод очередной строки, создается<br />
объект '''msg''' класса '''QDBusMessage''' – он инкапсулирует сообщение<br />
''D-Bus''. Мы создаем объект-сообщение типа «вызов метода» с помощью статического метода '''createMethodCall()'''. Аргументами метода '''createMethodCall()''' должны быть соответственно имя сервиса, путь к<br />
объекту, имя интерфейса и имя вызываемого метода.<br />
<br />
{{Врезка|Содержание=[[Изображение:LXF107_79_1.jpg|Рис. 2|300px]]Рис. 2. Базовый клиент ''D-Bus'' может передать в буфер обмена<br />
сразу несколько строк.|Ширина=300px}}<br />
<br />
Те, кто читал статью, посвященную ''D-Bus'', должны помнить, что<br />
с сообщениями этого типа обычно связываются дополнительные<br />
данные, представляющие собой значения аргументов вызываемого<br />
метода удаленного объекта. Они добавляются в объект '''msg''' с помощью метода '''setArguments()'''. Его аргументом должен быть список '''QList''', состоящий из элементов типа '''QVariant'''. Мы создаем последний<br />
с одним-единственным элементом (соответствующим единственному аргументу метода '''setContent'''), вызываем метод '''setArguments()''', после чего отправляем созданное сообщение с помощью метода '''send()''' объекта класса '''QDBusConnection'''. Теперь мы можем передать в буфер<br />
обмена ''X-Window'' серию строк, что можно проследить, например, с<br />
помощью апплета ''Klipper'' (рис. 2).<br />
<br />
=== Использование класса QDBusInterface===<br />
<br />
Вы, наверное, заметили, что в отношении работы с ''D-Bus'' программа ''sendlines'' не проще, чем написанная на языке ''C''. Пришло время показать, как ''Qt'' действительно может упростить работу с ''D-Bus''. В идеале нам просто хотелось бы иметь класс с тем же набором методов, что и у интерфейса удаленного приложения, так, чтобы при вызове метода локального класса вызывался соответствующий метод интерфейса удаленного приложения. В некоторых случаях этот идеал достижим, причем без особых усилий. Это возможно, если у нас есть описание интерфейса на языке '''XML'''. Сейчас же мы рассмотрим более общий вариант решения:<br />
<br />
<source lang=c><br />
#include <QtDebug><br />
#include <QtCore><br />
#include <QtDBus><br />
int main(int argc, char **argv)<br />
{<br />
QCoreApplication app(argc, argv);<br />
QDBusInterface clipboard("DBus.Manager.QClipboard", "/QClipboard", "DBus.Manager.QClipboard");<br />
int ch = 0;<br />
while ((ch = getchar()) != 'q') {<br />
if (ch == 'c')<br />
clipboard.call("setContent", "Data sent from console");<br />
if (ch == 'p') {<br />
QDBusReply<QString> reply = clipboard.call("content");<br />
if (reply.isValid())<br />
qDebug() << reply.value();<br />
else<br />
qDebug() << "Error calling content()";<br />
}<br />
QCoreApplication::processEvents();<br />
}<br />
}<br />
</source><br />
<br />
{{Врезка|Содержание=[[Изображение:LXF107_79_2.jpg|Рис. 3|300px]]Рис. 3. Меньше строк – больше возможностей!|Ширина=300px}}<br />
<br />
Программа ''copypaste'', текст которой приводится выше, представляет собой консольное приложение ''Qt'', которое может вставлять строки в буфер обмена и считывать их из него. Команда "'''c'''" заставляет программу скопировать в буфер заданную строку текста, а команда "'''p'''" читает содержимое буфера (рис. 3).<br />
<br />
Программа ''copypaste'' взаимодействует с ''D-Bus'' с помощью объекта класса '''QDBusInterface''', который не делает ничего «волшебного» – по сути, его методы просто объединяют некоторые рутинные операции, которые нам приходится выполнять, когда мы имеем дело непосредственно с классами '''QDBusConnection''' и '''QDBusMessage''', однако удобство работы значительно возрастает. Самым часто используемым методом класса '''QDBusInterface''' является '''call()''', вызывающий метод интерфейса удаленного приложения. В первом параметре '''call()''' передается строка с именем вызываемого удаленного метода. Далее следуют 8 параметров типа «ссылка на '''QVariant'''» со значениями, присвоенными по умолчанию; они используются для передачи аргументов.<br />
<br />
Такое решение может показаться не очень элегантным, но оно<br />
заметно упрощает работу с удаленными методами. Если у метода<br />
удаленного интерфейса меньше 8 аргументов (а таковых, разумеется, большинство), мы избавлены от необходимости конструирования<br />
списка аргументов на основе''' QList'''. Например, в строке<br />
<br />
clipboard.call("setContent", "Data sent from console");<br />
<br />
мы вызываем метод '''setContent''' с аргументом "'''Data sent from console'''". Если же вызываемый метод имеет более восьми аргументов, к нашим услугам – '''QDBusInterface::callWithArgumentList()''',<br />
принимающий аргументы вызываемого удаленного метода в виде<br />
списка.<br />
<br />
Метод '''call()''' также используется для вызова удаленных методов,<br />
возвращающих значения. При этом приложению-клиенту посылается сообщение определенного типа, которое, помимо прочего,<br />
содержит результат вызова. Ситуация осложняется тем, что при<br />
вызове удаленного метода может возникнуть ошибка. В этом случае клиенту посылается сообщение другого типа. Для обработки<br />
сообщений, возвращаемых удаленными методами, используется<br />
шаблон '''QDBusReply'''. Его параметром является тип значения, возвращаемого методом. Метод '''content()''', который позволяет прочитать содержимое буфера обмена, возвращает значение типа<br />
'''QString''', поэтому объект '''reply''', инкапсулирующий результат вызова<br />
метода, имеет тип '''QDBusReply<QString>'''. Проверить, не возникло<br />
ли в процессе вызова метода ошибки, можно с помощью метода<br />
'''isValid()''' объекта '''reply'''.<br />
<br />
В заключение рассмотрим еще одну интересную возможность модуля '''QtDBus'''. В статье, посвященной ''D-Bus'', я писал о<br />
сообщениях-сигналах и сравнивал их с сигналами ''Qt''. Сравнение<br />
было более чем уместно, так как в ''QtDBus'' действительно существует возможность связывать слот объекта локального приложения с сигналом удаленного приложения. Напомню, что эти сигналы могут быть широковещательными, то есть адресованными не только нашей программе.<br />
<br />
Для связывания удаленного сигнала с текущим слотом можно воспользоваться методом '''connect()''' класса '''QDBusConnection'''.<br />
Первые три аргумента метода – соответственно имя сервиса, путь к<br />
объекту и имя интерфейса. Далее нужно указать имя сигнала, передать указатель на объект-приемник и строку с именем слота, который будет вызываться в ответ на сигнал. Для отсоединения слота<br />
от удаленного сигнала служит метод '''disconnect()''' того же класса<br />
'''QDBusConnection'''.<br />
<br />
На этом мы заканчиваем обзор новшеств ''Qt 4.x'' и переходим на следующий этаж популярной графической системы Linux – KDE 4.x.<br />
'''LXF'''</div>Crazy Rebel