Журнал LinuxFormat - перейти на главную

LXF82:Qt/KDE

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(Новая: {{Цикл/Qt/KDE}} == Создаем стандартное KDE-приложение == ''ЧАСТЬ 5 Сегодня '''Андрей Боровский''' расскажет вам, к...)
 
м (викификация)
 
Строка 1: Строка 1:
 
{{Цикл/Qt/KDE}}
 
{{Цикл/Qt/KDE}}
 
== Создаем стандартное KDE-приложение ==
 
== Создаем стандартное KDE-приложение ==
''ЧАСТЬ 5 Сегодня '''Андрей Боровский''' расскажет вам, как создаются настоящие KDE-приложения. Ну, или почти настоящие...''
+
''ЧАСТЬ 5 Сегодня '''Андрей Боровский''' расскажет вам, как создаются настоящие KDE-приложения. Ну, или почти настоящие…''
  
 
{| align="right"
 
{| align="right"
|Если в чем-то уверен – проверь еще раз.
+
|Если в чем-то уверен — проверь еще раз.
 
|-
 
|-
 
| <div align="right">Девиз параноика.</div>
 
| <div align="right">Девиз параноика.</div>
 
|}<div style="clear:both;"></div>
 
|}<div style="clear:both;"></div>
[[Изображение:Img 82 98 1.jpg|thumb|Рисунок 1. Программа “images”.]]
+
[[Изображение:Img 82 98 1.jpg|thumb|Рисунок 1. Программа «images».]]
 
В прошлый раз мы научились создавать простейшие
 
В прошлый раз мы научились создавать простейшие
 
KDE-приложения, а также выполнять переводы приложений
 
KDE-приложения, а также выполнять переводы приложений
Строка 27: Строка 27:
 
1). Программа позволяет просматривать графические файлы, а также
 
1). Программа позволяет просматривать графические файлы, а также
 
применять к изображениям преобразования: из цветного в черно-белое,
 
применять к изображениям преобразования: из цветного в черно-белое,
изменение контраста и интенсивности (соответствующая функция называется именно так – intensity).
+
изменение контраста и интенсивности (соответствующая функция называется именно так — intensity).
  
 
[[Изображение:Img 82 99 1.png|thumb|Рисунок 2. Взаимодействие классов приложения.]]
 
[[Изображение:Img 82 99 1.png|thumb|Рисунок 2. Взаимодействие классов приложения.]]
Строка 36: Строка 36:
 
состояния и центральная область, которая используется для ввода/вывода данных (в терминологии «офисного» программирования эта область
 
состояния и центральная область, которая используется для ввода/вывода данных (в терминологии «офисного» программирования эта область
 
называется представлением (view). Все эти элементы в нашем приложении уже присутствуют. Самые важные и интересные файлы для нас
 
называется представлением (view). Все эти элементы в нашем приложении уже присутствуют. Самые важные и интересные файлы для нас
images.h/cpp и imagesview.h/cpp. Эти файлы содержат определения классов images и imagesView соответственно. Имя первого класса
+
images.h/cpp и imagesview.h/cpp. Эти файлы содержат определения классов images и imagesView соответственно. Имя первого класса
 
совпадает с именем проекта и приложения, имя второго класса получено
 
совпадает с именем проекта и приложения, имя второго класса получено
 
из первого добавлением View. Класс images является потомком класса
 
из первого добавлением View. Класс images является потомком класса
Строка 184: Строка 184:
  
 
Прежде чем мы перейдем к написанию класса images, ответственного за поведение интерфейса нашей программы, нам понадобится
 
Прежде чем мы перейдем к написанию класса images, ответственного за поведение интерфейса нашей программы, нам понадобится
создать один дополнительный элемент интерфейса – диалоговое окно
+
создать один дополнительный элемент интерфейса — диалоговое окно
 
для настройки параметров изображения. Это окно изображено на приведенном выше снимке экрана. Оно содержит горизонтальный ползунок
 
для настройки параметров изображения. Это окно изображено на приведенном выше снимке экрана. Оно содержит горизонтальный ползунок
(объект класса QSlider) и две кнопки – OK и Cancel. Будет логично, если
+
(объект класса QSlider) и две кнопки — OK и Cancel. Будет логично, если
 
для создания диалогового окна мы воспользуемся методами визуального программирования, и спроектируем окно в самой среде KDevelop,
 
для создания диалогового окна мы воспользуемся методами визуального программирования, и спроектируем окно в самой среде KDevelop,
 
используя встроенный в нее редактор KDevelop Designer (см. врезку).
 
используя встроенный в нее редактор KDevelop Designer (см. врезку).
Строка 195: Строка 195:
 
[[Изображение:Img 82 100 2.png|thumb|Рисунок 4. Проект диалогового окна.]]
 
[[Изображение:Img 82 100 2.png|thumb|Рисунок 4. Проект диалогового окна.]]
 
В открывшемся диалоговом окне (рис. 3) укажите имя нового файла
 
В открывшемся диалоговом окне (рис. 3) укажите имя нового файла
SettingsDialog и тип – Dialog (ui). После этого будет открыт редактор
+
SettingsDialog и тип — Dialog (ui). После этого будет открыт редактор
 
окон, подобный Qt Designer, однако для того, чтобы добраться до окна
 
окон, подобный Qt Designer, однако для того, чтобы добраться до окна
 
формы, придется «разгрести» множество служебных окон (при разрешении 1024x768 окно формы оказывается полностью «похороненным» под
 
формы, придется «разгрести» множество служебных окон (при разрешении 1024x768 окно формы оказывается полностью «похороненным» под
 
ними). Перенесите в окно формы две кнопки PushButton и ползунок
 
ними). Перенесите в окно формы две кнопки PushButton и ползунок
 
Slider и объедините их в группы (рис. 4). Сигнал clicked() кнопки OK
 
Slider и объедините их в группы (рис. 4). Сигнал clicked() кнопки OK
соедините со слотом accept() класса Form1 (для тех, кто забыл, напомним, что соответствующее окно вызывается командой Соединения...
+
соедините со слотом accept() класса Form1 (для тех, кто забыл, напомним, что соответствующее окно вызывается командой Соединения…
 
контекстного меню или с помощью клавиши F3). Сигнал clicked() кнопки Cancel следует соединить со слотом reject() класса Form1. Вызов
 
контекстного меню или с помощью клавиши F3). Сигнал clicked() кнопки Cancel следует соединить со слотом reject() класса Form1. Вызов
 
слотов accept() и reject() приводит к закрытию диалогового окна. При
 
слотов accept() и reject() приводит к закрытию диалогового окна. При
Строка 207: Строка 207:
  
 
Теперь вернитесь в Automake Manager, щелкните правой кнопкой
 
Теперь вернитесь в Automake Manager, щелкните правой кнопкой
мыши по имени файла SettingsDialog.ui и в контекстном меню выберите команду Создать или выбрать класс реализации....
+
мыши по имени файла SettingsDialog.ui и в контекстном меню выберите команду Создать или выбрать класс реализации….
  
 
На самом деле мы создаем не класс реализации, а наследуем
 
На самом деле мы создаем не класс реализации, а наследуем
от класса формы. В открывшемся окне введите имя нового класса – SettingsDialogImpl. Закройте окна созданных файлов
+
от класса формы. В открывшемся окне введите имя нового класса — SettingsDialogImpl. Закройте окна созданных файлов
 
settingsdialogimpl.h и settingsdialogimpl.cpp. В редакторе форм
 
settingsdialogimpl.h и settingsdialogimpl.cpp. В редакторе форм
создайте новый слот (команда Слоты... контекстного меню) void
+
создайте новый слот (команда Слоты… контекстного меню) void
 
sliderMoved(int i) и соедините его с сигналом sliderMoved(int) объекта slider1. Теперь закройте окно визуального редактора (не забыв сохранить файл SettingsDialog.ui) и откройте файл settingsdialogimpl.h.
 
sliderMoved(int i) и соедините его с сигналом sliderMoved(int) объекта slider1. Теперь закройте окно визуального редактора (не забыв сохранить файл SettingsDialog.ui) и откройте файл settingsdialogimpl.h.
 
В объявление класса SettingsDialogImpl добавьте закрытую переменную _sliderpos и метод getSliderValue():
 
В объявление класса SettingsDialogImpl добавьте закрытую переменную _sliderpos и метод getSliderValue():
Строка 246: Строка 246:
 
меры, мы удалим все, что связано с выводом данных на печать, в том
 
меры, мы удалим все, что связано с выводом данных на печать, в том
 
числе метод filePrint() и поле m_printer. На поле m_printer ссылается конструктор images, в него тоже нужно внести изменения. Удалим
 
числе метод filePrint() и поле m_printer. На поле m_printer ссылается конструктор images, в него тоже нужно внести изменения. Удалим
методы saveProperties() и readProperties() они нам сейчас не
+
методы saveProperties() и readProperties() — они нам сейчас не
 
нужны. Также следует удалить содержимое методов load(), fileSave() и
 
нужны. Также следует удалить содержимое методов load(), fileSave() и
fileSaveAs(), а сами методы – оставить. Если удаление всего ненужного
+
fileSaveAs(), а сами методы — оставить. Если удаление всего ненужного
 
выполнено грамотно, приложение должно скомпилироваться и запуститься. Возможно, вы заметили, что хотя код, выполняющий команды
 
выполнено грамотно, приложение должно скомпилироваться и запуститься. Возможно, вы заметили, что хотя код, выполняющий команды
 
File|New и File|Print удален, пункт меню и кнопка быстрого доступа остались. Для того, чтобы удалить их, нужно прейти в метод setupActions()
 
File|New и File|Print удален, пункт меню и кнопка быстрого доступа остались. Для того, чтобы удалить их, нужно прейти в метод setupActions()
Строка 275: Строка 275:
 
Весь код, отвечающий за добавление новых элементов интерфейса,
 
Весь код, отвечающий за добавление новых элементов интерфейса,
 
мы сгруппируем в новом методе setup_Controls(). В среде KDevelop
 
мы сгруппируем в новом методе setup_Controls(). В среде KDevelop
новые методы классов можно добавить вручную, а можно – автоматически. Откройте вкладку Классы, расположенную с правой стороны главного
+
новые методы классов можно добавить вручную, а можно — автоматически. Откройте вкладку Классы, расположенную с правой стороны главного
 
окна KDevelop. Раскройте группу src, щелкните правой кнопкой мыши по
 
окна KDevelop. Раскройте группу src, щелкните правой кнопкой мыши по
 
классу images и в открывшемся контекстном меню выберите команду
 
классу images и в открывшемся контекстном меню выберите команду
Добавить метод.... Откроется окно создания нового метода, похожее на
+
Добавить метод…. Откроется окно создания нового метода, похожее на
 
окно создания нового слота в Qt Designer.
 
окно создания нового слота в Qt Designer.
  
Строка 296: Строка 296:
 
одноименного метода). Кроме указателя на объект класса KPopupMenu
 
одноименного метода). Кроме указателя на объект класса KPopupMenu
 
методу insertItem() передается имя нового меню, его идентификатор
 
методу insertItem() передается имя нового меню, его идентификатор
id и индекс – позиция в главной строке меню (значению 1 соответствует
+
id и индекс — позиция в главной строке меню (значению 1 соответствует
 
вторая позиция, после File). Идентификатор должен быть положительным
 
вторая позиция, после File). Идентификатор должен быть положительным
 
числом. Если insertItem() передать отрицательное значение идентификатора, insertItem() вернет значение нового уникального идентификатора для меню.
 
числом. Если insertItem() передать отрицательное значение идентификатора, insertItem() вернет значение нового уникального идентификатора для меню.
Строка 309: Строка 309:
 
и форм (в том числе, в черно-белую пиктограмму для заблокированной
 
и форм (в том числе, в черно-белую пиктограмму для заблокированной
 
команды). Слот proc_toBlacknWhite() будет содержать код обработки
 
команды). Слот proc_toBlacknWhite() будет содержать код обработки
команды. Последний параметр – имя объекта-команды. Имена могут быть
+
команды. Последний параметр — имя объекта-команды. Имена могут быть
 
у всех объектов Qt/KDE, наследующих QObject, но это первый случай,
 
у всех объектов Qt/KDE, наследующих QObject, но это первый случай,
 
когда они нам действительно пригодятся.
 
когда они нам действительно пригодятся.
Строка 339: Строка 339:
 
интерфейса, нужно получить доступ к соответствующему объекту
 
интерфейса, нужно получить доступ к соответствующему объекту
 
действия. Доступ к коллекции объектов мы получаем с помощью
 
действия. Доступ к коллекции объектов мы получаем с помощью
метода actionCollection(), а сами объекты можем найти по имени – строке, переданной конструктору Kaction.
+
метода actionCollection(), а сами объекты можем найти по имени — строке, переданной конструктору Kaction.
  
 
Мы научились создавать приложения KDE со стандартным
 
Мы научились создавать приложения KDE со стандартным
 
графическим интерфейсом. Но в мире программирования KDE
 
графическим интерфейсом. Но в мире программирования KDE
это – только начало. В следующих статьях мы узнаем, как создавать
+
это — только начало. В следующих статьях мы узнаем, как создавать
 
KDE-приложения специальных типов, а также познакомимся с некоторыми полезными службами KDE, такими как менеджер сессий.
 
KDE-приложения специальных типов, а также познакомимся с некоторыми полезными службами KDE, такими как менеджер сессий.

Текущая версия на 16:45, 14 декабря 2008

[править] Создаем стандартное KDE-приложение

ЧАСТЬ 5 Сегодня Андрей Боровский расскажет вам, как создаются настоящие KDE-приложения. Ну, или почти настоящие…

Если в чем-то уверен — проверь еще раз.
Девиз параноика.
(thumbnail)
Рисунок 1. Программа «images».

В прошлый раз мы научились создавать простейшие KDE-приложения, а также выполнять переводы приложений KDE на разные языки. Было показано, как можно заставить наше приложение использовать ресурсы другого приложения и как добавлять переводы к уже существующим программам. В принципе, изложенных навыков достаточно, чтобы заново выполнить перевод всей среды KDE (сделать, например, перевод с особым цинизмом). Однако, приложения из прошлой статьи не выполняли никакой полезной работы, в том числе потому, что у них отсутствовал сколько-нибудь развитый пользовательский интерфейс. В этой статье мы не будем заниматься переводами (если захотите, можете выполнить их сами), зато напишем «почти настоящее» приложение KDE, использующее меню, панель быстрого доступа и другие интерфейсные элементы, предоставляемые KDE. Наше приложение «почти» (а не совсем) настоящее потому, что оно все еще игнорирует некоторые важные функции среды KDE, однако его уже можно использовать в практических целях. Работающее приложение (исходные тексты вы найдете на диске) выглядит вполне серьезно (рис. 1). Программа позволяет просматривать графические файлы, а также применять к изображениям преобразования: из цветного в черно-белое, изменение контраста и интенсивности (соответствующая функция называется именно так — intensity).

(thumbnail)
Рисунок 2. Взаимодействие классов приложения.

Мы начнем разработку нашего приложения в среде KDevelop, используя заготовку Application framework (надеюсь, вы помните, как ее найти). Назовем наш проект images. В результате выполнения соответствующего мастера будет создана директория images с поддиректориями и много файлов .cpp, .h и других типов. Это обилие может напугать начинающего программиста, но на самом деле все не так страшно. Application framework представляет собой заготовку классического офисного приложения KDE. У него есть строка меню, панель быстрого доступа, строка состояния и центральная область, которая используется для ввода/вывода данных (в терминологии «офисного» программирования эта область называется представлением (view). Все эти элементы в нашем приложении уже присутствуют. Самые важные и интересные файлы для нас — images.h/cpp и imagesview.h/cpp. Эти файлы содержат определения классов images и imagesView соответственно. Имя первого класса совпадает с именем проекта и приложения, имя второго класса получено из первого добавлением View. Класс images является потомком класса KMainWindow, реализующего главное окно офисного приложения. Окно KMainWindow позволяет легко управлять такими элементами интерфейса как главное меню, панель инструментов, строка состояния и, конечно, представление. Представление реализовано в классе imagesView. Объект класса images выполняет роль главного визуального элемента для объекта app, класса KApplication. Объект app объявлен в файле main.cpp, в котором реализована функция main() нашего приложения (нам не нужно модифицировать этот файл). Объекты menuBar, toolBar и statusBar (все они являются членами класса KMainWindow) представляют соответственно строку меню, панель инструментов и строку состояния. Схема взаимодействия классов приложения не должна выглядеть очень сложной (рис. 2, под именами классов подписаны имена объектов этих классов, объявленных в классе images). Класс images выполняет роль связующего звена между элементами пользовательского интерфейса и представлением данных imagesView. Методы этого класса являются обработчиками событий интерфейса и вызывают соответствующие методы класса представления.


Для того, чтобы открыть в KDevelop файлы исходных текстов, нужно открыть вкладку Группы файлов, расположенную у левого края главного окна среды, и выбрать в ней группу Sources. Перед вами появится список файлов исходных текстов. Откройте нужный файл щелчком мыши.

В файле imagesview.h внесите изменения в объявление класса imagesView так, чтобы он стал потомком класса QLabel (напомню, что класс QLabel способен выводить изображения). Класс imagesView является также потомком класса imagesIface, но эта «наследственная линия» нас сейчас не интересует, и мы оставим ее без изменений. Естественно, в файл imagesview.h следует добавить директиву

#include <qpixmap.h>

Удалим из объявления imagesView ненужные члены и добавим нужные. После этого объявление класса будет выглядеть так:

class imagesView : public QLabel, public imagesIface
{
Q_OBJECT
public:
imagesView(QWidget *parent);
virtual ~imagesView();
void toBlacknWhite();
void setContrast(int c);
void setIntensity(int i);
};

Помимо конструктора и деструктора у класса imagesView появились три новых метода. Эти методы выполняют преобразования изображения, хранящегося в imagesView. Метод toBlacknWhite() выполняет преобразование палитры из цветной в черно-белую, метод setContrast() позволяет настроить контрастность изображения, а с помощью метода setIntensity() можно изменить интенсивность.

Теперь перейдем в файл imagesview.cpp. Добавим в этот файл две директивы включения заголовочных файлов:

#include <kpixmap.h>
#include <kpixmapeffect.h>
Теперь приступим к реализации методов:
imagesView::imagesView(QWidget *parent)
: QLabel(parent),
DCOPObject("imagesIface")
{
setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
}
imagesView::~imagesView()
{
}
void imagesView::toBlacknWhite()
{
if (pixmap() == NULL)
{
kdDebug() << k_funcinfo << "Trying to modify an empty pixmap" <<
endl;
return;
}
KPixmap kpm(* pixmap());
KPixmapEffect::toGray(kpm, FALSE);
setPixmap(kpm);
}
void imagesView::setContrast(int c)
{
if (pixmap() == NULL)
{
kdDebug() << k_funcinfo << "Trying to modify an empty pixmap" <<
endl;
return;
}
KPixmap kpm(* pixmap());
KPixmapEffect::contrast(kpm, (c – 50)*5);
setPixmap(kpm);
}
void imagesView::setIntensity(int i)
{
if (pixmap() == NULL)
{
kdDebug() << k_funcinfo << "Trying to modify an empty pixmap" <<
endl;
return;
}
KPixmap kpm(* pixmap());
KPixmapEffect::intensity(kpm, (i-50)/10);
setPixmap(kpm);
}

В конструкторе класса мы устанавливаем горизонтальное и вертикальное выравнивание для содержимого метки.

Для того, чтобы понять, как работают три метода, выполняющих преобразования изображения, рассмотрим классы KDE KPixmap и KPixmapEffect. Первый из этих классов представляет собой улучшенный вариант QPixmap, второй класс предназначен для применения различных эффектов к изображению, хранящемуся в KPixmap. Эффекты реализованы в виде статических методов класса KPixmapEffect. Методы модифицируют содержимое переданного им объекта (а не создают новый). Для выполнения обработки изображения нам приходится преобразовывать QPixmap в KPixmap. Фактически наш класс imagesView представляет собой модифицированный вариант QLabel, способный выполнять преобразования над загруженным изображением. Для вывода сообщения об ошибке (которая никогда не должна возникнуть) мы используем функцию kdDebug(), которая возвращает нам объект потока C++ для вывода отладочных сообщений (можно было бы воспользоваться и printf(), но это же все-таки C++!). Макрос k_funcinfo выводит информацию о функции, из которой был вызван. Функция kdDebug() и макрос k_funcinfo объявлены в заголовочном файле kdebug.h. В том же файле объявлен макрос k_lineinfo, который ограничивается вводом информации о файле строке исходного текста, в которой был вызван.

Прежде чем мы перейдем к написанию класса images, ответственного за поведение интерфейса нашей программы, нам понадобится создать один дополнительный элемент интерфейса — диалоговое окно для настройки параметров изображения. Это окно изображено на приведенном выше снимке экрана. Оно содержит горизонтальный ползунок (объект класса QSlider) и две кнопки — OK и Cancel. Будет логично, если для создания диалогового окна мы воспользуемся методами визуального программирования, и спроектируем окно в самой среде KDevelop, используя встроенный в нее редактор KDevelop Designer (см. врезку). В окне Automake Manager, щелкните правой кнопкой мыши по строке images (Программа в bin) и выберите команду Создать файл.

(thumbnail)
Рисунок 3. Окно создания нового файла.
(thumbnail)
Рисунок 4. Проект диалогового окна.

В открывшемся диалоговом окне (рис. 3) укажите имя нового файла — SettingsDialog и тип — Dialog (ui). После этого будет открыт редактор окон, подобный Qt Designer, однако для того, чтобы добраться до окна формы, придется «разгрести» множество служебных окон (при разрешении 1024x768 окно формы оказывается полностью «похороненным» под ними). Перенесите в окно формы две кнопки PushButton и ползунок Slider и объедините их в группы (рис. 4). Сигнал clicked() кнопки OK соедините со слотом accept() класса Form1 (для тех, кто забыл, напомним, что соответствующее окно вызывается командой Соединения… контекстного меню или с помощью клавиши F3). Сигнал clicked() кнопки Cancel следует соединить со слотом reject() класса Form1. Вызов слотов accept() и reject() приводит к закрытию диалогового окна. При этом значение, которое окно передает программе после своего закрытия, определяет, какая из кнопок была нажата.

Теперь вернитесь в Automake Manager, щелкните правой кнопкой мыши по имени файла SettingsDialog.ui и в контекстном меню выберите команду Создать или выбрать класс реализации….

На самом деле мы создаем не класс реализации, а наследуем от класса формы. В открывшемся окне введите имя нового класса — SettingsDialogImpl. Закройте окна созданных файлов settingsdialogimpl.h и settingsdialogimpl.cpp. В редакторе форм создайте новый слот (команда Слоты… контекстного меню) void sliderMoved(int i) и соедините его с сигналом sliderMoved(int) объекта slider1. Теперь закройте окно визуального редактора (не забыв сохранить файл SettingsDialog.ui) и откройте файл settingsdialogimpl.h. В объявление класса SettingsDialogImpl добавьте закрытую переменную _sliderpos и метод getSliderValue():

class SettingsDialogImpl: public Form1 {
Q_OBJECT
public:
SettingsDialogImpl(QWidget *parent = 0, const char *name = 0);
public slots:
int getSliderValue();
protected slots:
void sliderMoved(int i);
private:
int _sliderpos;
};

В файл settingsdialogimpl.cpp добавьте реализацию метода

getSliderValue()и слота sliderMoved():
void SettingsDialogImpl::sliderMoved(int i)
{
_sliderpos = i;
}
int SettingsDialogImpl::getSliderValue()
{
return _sliderpos;
}

На этом разработка диалогового окна закончена. В файл images. cpp необходимо добавить директиву

#include "settingsdialogimpl.h"

Теперь мы можем приступить к написанию, а точнее, к модификации класса images. Дело в том, что этот класс, связующее звено нашего приложения, довольно сложен и значительная его часть была сгенерирована автоматически, так что лучше всего трансформировать класс, созданный по умолчанию, в тот класс, который нам нужен, путем постепенных изменений. Что мы хотим изменить в классе images? Мы хотим удалить все ненужное. Наше приложение предназначено для редактирования существующих графических файлов, но не для создания новых, поэтому удалим метод fileNew() Кроме того, дабы не усложнять наш проект сверх меры, мы удалим все, что связано с выводом данных на печать, в том числе метод filePrint() и поле m_printer. На поле m_printer ссылается конструктор images, в него тоже нужно внести изменения. Удалим методы saveProperties() и readProperties() — они нам сейчас не нужны. Также следует удалить содержимое методов load(), fileSave() и fileSaveAs(), а сами методы — оставить. Если удаление всего ненужного выполнено грамотно, приложение должно скомпилироваться и запуститься. Возможно, вы заметили, что хотя код, выполняющий команды File|New и File|Print удален, пункт меню и кнопка быстрого доступа остались. Для того, чтобы удалить их, нужно прейти в метод setupActions() и удалить строки

KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
KStdAction::print(this, SLOT(filePrint()), actionCollection());

Что делали две удаленные строки? Они добавляли в приложения два стандартных действия (см. врезку). Для стандартных действий система сама предоставляет пиктограмму, название и клавишу быстрого доступа. Статическим методам класса KStdAction передается указатель на класс, реализующий обработку команды, слот, обрабатывающий команду, а также указатель на коллекцию действий actionCollection (возвращается методом actionCollection()). Программа будет работать даже если слотов, связанных с действиями, не существует, только в стандартный поток вывода будет выведено предупреждающее сообщение. Такова динамическая природа модели сигнал/слот.

Обратите внимание, что мы не прибегаем к визуальному программированию при проектировании главного окна нашего офисного приложения. Дело в том, что для разработки главного окна визуальное программирование нам и не нужно, поскольку вид этого окна однозначно определен принципами построения приложения «офисного» типа.

Теперь подумаем о том, что следует добавить в класс images. В главную строку меню приложения мы добавим пункт Processing, который будет открывать подменю, содержащее команды обработки изображения To Black & White (в черно-белый), Contrast (контраст) и Intensity (интенсивность). Кнопки новых команд нужно добавить на панель быстрого доступа. Все эти изменения должны быть отражены в классе images, отвечающем за интерфейс. Ну и конечно, в images нужно добавить код, выполняющий новые команды. Именно в таком порядке мы и будем вносить изменения в класс.

Весь код, отвечающий за добавление новых элементов интерфейса, мы сгруппируем в новом методе setup_Controls(). В среде KDevelop новые методы классов можно добавить вручную, а можно — автоматически. Откройте вкладку Классы, расположенную с правой стороны главного окна KDevelop. Раскройте группу src, щелкните правой кнопкой мыши по классу images и в открывшемся контекстном меню выберите команду Добавить метод…. Откроется окно создания нового метода, похожее на окно создания нового слота в Qt Designer.

После добавления нового метода можно приступать к его реализации. В методе setup_Controls() мы создаем подменю Processing главного меню, добавляем разделительную полосу на панель быстрого доступа (просто для красоты), создаем и настраиваем три объекта действия (объекты классы KAction), и делаем соответствующие команды доступными в меню и на панели быстрого доступа. Рассмотрим все эти этапы подробнее.

void images::setup_Controls()
{
KPopupMenu * procMenu = new KPopupMenu(); //Processing
menuBar()->insertItem(i18n("&Processing"), procMenu, 0, 1);

Создаем меню Processing. Подменю главного меню должно быть объектом класса KPopupMenu. Для того, чтобы указать, что новое всплывающее меню принадлежит главному меню, мы вызываем метод insertItem() поля menuBar (к которому мы получаем доступ с помощью одноименного метода). Кроме указателя на объект класса KPopupMenu методу insertItem() передается имя нового меню, его идентификатор id и индекс — позиция в главной строке меню (значению 1 соответствует вторая позиция, после File). Идентификатор должен быть положительным числом. Если insertItem() передать отрицательное значение идентификатора, insertItem() вернет значение нового уникального идентификатора для меню.

toolBar()->insertLineSeparator(3);

Добавляем линию-разделитель

KAction * command = new KAction(i18n(“To &Black && White”),
QIconSet(QPixmap(“c1.xpm)), 0, this,
SLOT(proc_toBlacknWhite()),
actionCollection(), “bw_command”);

Создаем объект-действие для команды To Black & White. Файл c1.xpm содержит пиктограмму команды (этот файл должен быть доступен программе во время выполнения). Класс QIconSet преобразует переданный ему графический файл в набор пиктограмм различный размеров и форм (в том числе, в черно-белую пиктограмму для заблокированной команды). Слот proc_toBlacknWhite() будет содержать код обработки команды. Последний параметр — имя объекта-команды. Имена могут быть у всех объектов Qt/KDE, наследующих QObject, но это первый случай, когда они нам действительно пригодятся.

command->setToolTip(i18n(“Transforms image palette to grayscale”));
command->setEnabled(FALSE);

В этих строках мы добавляем всплывающую подсказку и указываем, что по умолчанию команда заблокирована. Последнее нужно для того, чтобы пользователь не пытался обрабатывать еще не существующее изображение. Правда, методы класса imagesView все равно этого не допустят, но лучше перестраховаться (см. эпиграф).

command->plug(procMenu);
command->plug(toolBar(), -1);

С помощью метода plug() мы указываем объекту действия, что соответствующая команда должна быть доступна в меню procMenu и на панели быстрого доступа.

Добавление двух остальных команд выполняется аналогично. Добавим вызов метода setup_Controls() в конструктор images после вызова setupGUI(). Теперь можно запустить программу и полюбоваться на новый интерфейс. Правда, слоты для новых команд еще не созданы, так что новые команды пока не работают. Прежде чем создать слоты, вернемся в конструктор images и добавим в него строки

actionCollection()->setHighlightingEnabled(TRUE);
connect(actionCollection(),SIGNAL(actionStatusText(const QString&)),statusBar(), SLOT(message ( const QString& )));
connect(actionCollection(),SIGNAL(clearStatusText()),statusBar(), SLOT(clear()));

после вызова statusBar()->show(). Это стандартная последовательность вызовов, предназначенная для того, чтобы всплывающие подсказки отображались в строке состояния. Теперь мы можем добавить слот proc_toBlacknWhite(), и слоты для двух других команд: proc_Contrast() и proc_Intensity(). В коде этих слотов (см. исходные тексты на диске) для нас нет почти ничего нового, отметим только один момент. Для того, чтобы разблокировать/заблокировать команды пользовательского интерфейса, нужно получить доступ к соответствующему объекту действия. Доступ к коллекции объектов мы получаем с помощью метода actionCollection(), а сами объекты можем найти по имени — строке, переданной конструктору Kaction.

Мы научились создавать приложения KDE со стандартным графическим интерфейсом. Но в мире программирования KDE это — только начало. В следующих статьях мы узнаем, как создавать KDE-приложения специальных типов, а также познакомимся с некоторыми полезными службами KDE, такими как менеджер сессий.

Персональные инструменты
купить
подписаться
Яндекс.Метрика