Dr.Konqi, мы с ним дружим, я его часто вижу %)
Вместо предисловия
Привет!
На хабре уже писали про то, что все плазмоиды нужно портировать на QML/JS, но я все равно продолжаю измываться над трупом CPP и пишу виджеты для плазмы на плюсах. Но, возможно, не все так плохо, %username%?
Для более простого примера написания плазмоида на C++ можно обратиться к этой статье. В настоящей же статье на голый виджет мы попробуем добавить немного фич (в порядке возрастания) — конфигурационный интерфейс, обработку некоторых событий и уведомления.
Если кого заинтересовало — продолжение ниже.
Идея виджета
Так как задачка для меня была исключительно учебно-самообразовательной, то идея виджета проста: возьмем и форкнем виджет Oblique Strategies для GNOME. Таким образом, в нашем виджете будет:
- Label с текстом с карточек
- Label с копирайтом (служит в первую очередь для указания текущей редакции)
- Конфигурационный интерфейс, включающий в себя настройку текста и выбор редакции
- Обновление текста по клику мышкой
- Опциональная функция автообновления
- Опциональная функция вывода текущего сообщения при автоматической смене в стандартные уведомления
Компоненты
Виджет
#ifndef OBLIKUESTRATEGIES_H #define OBLIKUESTRATEGIES_H #include <Plasma/Applet> #include <Plasma/Label> #include <ui_configwindow.h> class QGraphicsLinearLayout; class oblikuestrategies : public Plasma::Applet { Q_OBJECT public: oblikuestrategies(QObject *parent, const QVariantList &args); ~oblikuestrategies(); int setMessagesText(); void init(); public slots: int autoUpdateEvent(); int sendNotification(QString eventId, int num); int updateEvent(); void mousePressEvent(QGraphicsSceneMouseEvent *event); // for configuration interface int setAutoUpdate(); void configAccepted(); void configChanged(); protected: void createConfigurationInterface(KConfigDialog *parent); private: // ui Plasma::Label *main_label; Plasma::Label *info_label; QTimer *timer; // variables bool autoUpdate_bool, notify_bool; int autoUpdate_int, edition, fontSize, fontWeight; QString fontFamily, fontColor, fontStyle; QStringList formatLine, copyright; QList<QStringList> mess; // configuration interface Ui::ConfigWindow uiConfig; }; K_EXPORT_PLASMA_APPLET(oblikue-strategies, oblikuestrategies) #endif /* OBLIKUESTRATEGIES_H */
Это будет эдакая «карта». Суть K_EXPORT_PLASMA_APPLET рассказана в указанной выше статье (это единственная принципиально важная штука в хидере). Подключим первоначальные библиотеки, объявим класс и деструктор
#include "oblikue-strategies.h" #include <QGraphicsLinearLayout> #include <plasma/theme.h> oblikuestrategies::oblikuestrategies(QObject *parent, const QVariantList &args) : Plasma::Applet(parent, args) { setBackgroundHints(DefaultBackground); setHasConfigurationInterface(true); } oblikuestrategies::~oblikuestrategies() { delete info_label; delete main_label; delete timer; }
ничего особо интересно. Замечу только, что мы тут установили, что у апплета есть конфигурационный интерфейс. Суть переменных будет ясна чуть ниже. Далее соберем функцию инициализации:
void oblikuestrategies::init() { if (setMessagesText() != 0) return; // generate ui // layout QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this); layout->setOrientation(Qt::Vertical); // label layout->addStretch(1); main_label = new Plasma::Label(this); main_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); main_label->setToolTip(qApp->translate("tooltip", "Click here to update message")); layout->addItem(main_label); layout->addStretch(1); // copyright label info_label = new Plasma::Label(this); layout->addItem(info_label); }
Функция int setMessagesText() забивает переменные copyright и собственно текст карт (mess), попутно создает список из двух элементов formatLine. Затем мы создаем Layout, на ней две метки — одна для текста, другая для копирайта — и кидаем распорки (stretch) для красивого вида. Далее перейдем к конфигурационному интерфейсу
Конфигурация
Нарисуем формочку. Пусть она будет такой:
Теперь прикрутим функции. Считывание конфига:
void oblikuestrategies::configChanged() { KConfigGroup cg = config(); edition = cg.readEntry("edition", 1); fontFamily = cg.readEntry("font_family", "Terminus"); ... }
Обращу ваше внимание на то, как считываются переменные. Метод readEntry имеет два аргумента — первый имя переменной в конфигурационном файле (в глубине хомяка plasma-desktop-appletrc), второй — дефолтное значение. Настройки, записанные с помощью KConfigGroup, будут сохранены в указанном выше файле. Добавлю, что эта функция автоматически вызовется, если были изменены настройки виджета.
Не забыли про запись конфига:
void oblikuestrategies::configAccepted() { KConfigGroup cg = config(); cg.writeEntry("edition", uiConfig.comboBox_edition->currentIndex()+1); cg.writeEntry("font_family", uiConfig.fontComboBox_font->currentFont().family()); ... }
Аналогично считыванию. Метод writeEntry также имеет 2 аргумента — имя и то, откуда брать значения. Теперь сам интерфейс прикрутим:
void oblikuestrategies::createConfigurationInterface(KConfigDialog *parent) { QWidget *configwin = new QWidget; uiConfig.setupUi(configwin); uiConfig.comboBox_edition->setCurrentIndex(edition-1); ... parent->addPage(configwin, i18n("Oblikue Strategies"), Applet::icon()); connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted())); }
Объявили интерфейс, выставили значения (переменные уже считаны в init() вызовом метода configChanged()). Потом добавили интерфейс к окошечку (метод addPage — первый аргумент что, второй как назвать и третий иконка). И связали кнопку с сохранением настроек. Дальше прикрутим эвенты.
Обработка событий
Пусть у нас есть некоторый метод, который отвечает за обновление текста. Назовем его int updateEvent() (возвращает номер вызванного сообщения). Прикрутим обработку клика мыши:
void oblikuestrategies::mousePressEvent(QGraphicsSceneMouseEvent *event) { // mouse click event if (event->buttons() == Qt::LeftButton) updateEvent(); }
Если двойной клик, то нужно наследоваться от mouseDoubleClickEvent и, очевидно, проверка на кнопку не нужна. Теперь добавим автообновление. Сначала добавим в метод init() объявление таймера:
... // timer timer = new QTimer(this); timer->setSingleShot(false); ...
Установим его в «многоразовое» использование (setSingleShot(false)). Далее прикрутим отключение и включение таймера в методе configChanged():
if (autoUpdate_bool == true) { disconnect(timer, SIGNAL(timeout()), this, SLOT(autoUpdateEvent())); timer->stop(); } // считывание переменных ... if (autoUpdate_bool == true) { connect(timer, SIGNAL(timeout()), this, SLOT(autoUpdateEvent())); timer->start(autoUpdate_int * MSEC_IN_MIN); }
На всякий случай: метод start() имеет аргумент период в мсек. Добавим функцию автообновления:
int oblikuestrategies::autoUpdateEvent() { // auto update text int num = updateEvent(); if (notify_bool == true) if (sendNotification(QString("newMessage"), num) != 0) return 1; return 0; }
Тут то нам и понадобилось значение, возвращаемое методом updateEvent(). Данный метод вызывает обновление текста, затем, если установлено notify_bool == true вызывает метод, который отправляет уведомления в KDE.
Уведомления
Сначала создадим файлик plasma_applet_oblikue-strategies.notifyrc
[Global] IconName=oblikue-strategies Name=Oblikue Strategies Comment=Oblikue Strategies [Event/newMessage] Name=New message Comment=There is auto updated message in widget Action=Popup
Первое — общие настройки, их можно оставить без комментариев. Дальше идет перечисление событий и что они из себя представляют. Теперь вернемся к исходникам. Один единственный метод:
int oblikuestrategies::sendNotification(QString eventId, int num) { // send notification KNotification *notification = new KNotification(eventId); notification->setComponentData(KComponentData("plasma_applet_oblikue-strategies")); notification->setTitle(QString(i18n("Oblikue Strategies"))); notification->setText(mess[edition-1][num]); notification->sendEvent(); delete notification; return 0; }
eventId — собственно наш эвент. В методе setComponentData указываем имя апплета (чтоб не путаться и для упрощения). Ставим подпись, текст и отправляем сообщение в систему.
Сборка
CMakeLists.txt configwindow.ui oblikue-strategies.cpp oblikue-strategies.h oblikue-strategies.png plasma-applet-oblikue-strategies.desktop plasma_applet_oblikue-strategies.notifyrc
project (plasma_applet_oblikue-strategies) find_package (KDE4 REQUIRED) include (KDE4Defaults) add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES}) set (PLUGIN_NAME ${PROJECT_NAME}) file (GLOB PROJECT_DESKTOP *.desktop) file (GLOB PROJECT_ICON *.png) file (GLOB PROJECT_NOTIFY *.notifyrc) file (GLOB PROJECT_SOURCE *.cpp) file (GLOB PROJECT_UI *.ui) kde4_add_ui_files (PROJECT_SOURCE ${PROJECT_UI}) kde4_add_plugin (${PLUGIN_NAME} ${PROJECT_SOURCE}) target_link_libraries (${PLUGIN_NAME} ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS}) # install install (TARGETS ${PLUGIN_NAME} DESTINATION ${PLUGIN_INSTALL_DIR}) install (FILES ${PROJECT_DESKTOP} DESTINATION ${SERVICES_INSTALL_DIR}) install (FILES ${PROJECT_ICON} DESTINATION ${ICON_INSTALL_DIR}) install (FILES ${PROJECT_NOTIFY} DESTINATION ${DATA_INSTALL_DIR}/${PLUGIN_NAME})
Файлик не совсем правильный (с точки зрения человеческого фактора, например), но универсальный (поменять только имя проекта на нужное). Из отличий от обычных файлов сборок — вызов kde4_add_ui_files для создания конфигурационного интерфейса. И установка файла с нотификациями.
Постскриптум
Исходники этого безобразия.
Что получилось:
По материалам
Спасибо за внимание!
ссылка на оригинал статьи http://habrahabr.ru/post/192698/
Добавить комментарий