Введение в KDevelop
Автор: RaD
Введение
KDevelop является интегрированной средой разработки приложений
под KDE/Qt. KDevelop (http://www.kdevelop.org) обладает необходимой
функциональностью для удобной разработки программ. Среда включает в себя:
- поддержку всех средств разработки на языке C++ (компилятор, линкер, automake, autoconf);
- мастер генерирования основных типов приложений;
- генератор классов для создания новых классов;
- менеджер исходных текстов и документации проектов;
- средства создания документации пользователя в формате SGML/HTML;
- поддержку интернационализации приложений;
- поддержку создания интерфейса приложений с помощью Qt Designer;
- средства поддержки внешних отладчиков.
В данной среде разработки мы создадим небольшое приложение для просмотра свойств WAV файлов.
Операционная система и железо
Разработка приложения производилась на компьютере Intel Celeron 900 (1795 bogomips) / 256 MB RAM / 20 GB HDD.
Программное обеспечение: ASPLinux 7.3 2.96-112 / gcc version 2.96 20000731 / KDevelop 2.1.2 / Qt 3.0.4.
Проект
Для изучения процесса разработки приложений с помощью KDevelop создадим небольшую утилиту просмотра свойств файлов формата WAV. Приложение управляется с помощью меню и отображает основные свойства звукового файла.
Приложение должно:
- иметь простой интерфейс;
- позволять последовательно открывать файлы;
- определять формат файла, отсеивать неподходящие файлы;
- отображать свойства файла.
Создание проекта
Запустим KDevelop и создадим новый проект с помощью меню Project->New. Появится форма (см. рисунок) на которой надо выбрать тип создаваемого приложения. В нашем случае надо выбрать тип KDE Mini.
На следующей странице надо заполнить все поля формы. В поле Project Name надо вписать KWaveInfo. Поле Project Directory автоматически дополнится. Нажимаем на [Next].
На следующей странице можно включить поддержку CVS для вашего проекта. В нашем случае ничего включать не надо. Нажимаем на [Next].
На следующих двух страницах можно отредактировать текст, который будет отображаться в каждом заголовочном файле и в каждом исходнике проекта.
Нажимаем на [Next].
Теперь можно сгенерировать файлы проекта. Нажимаем на [Create] и дожидаемся завершения процесса генерации. Затем нажимаем на [Exit].
Теперь можно заниматься программированием...
Главная форма приложения
Создаём форму
Для создания главной формы приложения необходимо воспользоваться утилитой Qt Designer. Для этого в KDevelop с помощью меню File->New открываем
диалог создания нового файла. В диалоге на вкладке General выбираем Qt Designer File (*.ui) и в поле Filename вводим mainform.ui. При нажатии на [OK] среда
предложит открыть файл в ASCII режиме, от этого надо отказаться. В открывшемся Qt Designer'е выбираем тип создаваемой формы. В нашем варианте это будет Main
Window.
Уберём все галочки в мастере создания формы. Таким образом мы получаем пустую панель. Если редактора свойств нет на экране, то вызываем его с помощью меню Window->Views->Property Editor/Signal Handler. Теперь необходимо заменить в свойствах формы её наименование (name) на MainForm и отображаемый заголовок (caption) на KWaveInfo.
Добавляем меню
Наше приложение будет управляться с помощью меню. Для создания меню надо нажать на правую кнопку мыши на форме и выбрать из контекстного меню элемент Add Menu Item. Переименуем появившийся элемент меню в &File. Также создадим элемент &Help. Для создания подэлементов элемента File необходимо воспользоваться так называемыми "действиями" (actions).
Если окна Actions нет на экране, то это исправляется с помощью меню Window->Views->Action Editor. В этом окне в контекстном меню выбираем элемент New Action, в окне появляется действие с именем Action. Выделяем его мышью и в редакторе свойств производим следующие действия:
- изменяем свойство name на fileExitAction;
- изменяем свойство text на Exit;
- изменияем свойство menuText на E&xit.
Аналогично создаем действия fileOpenAction, fileCloseAction и helpAboutAction.
Сигналы и слоты
Термины "сигнал" и "слот" в данном случае означают в терминах программиста под Win32 "событие" и "обработчик" соответственно.
Для создания слота у формы надо вызвать её контекстное меню и
выбрать элемент Slots..., это приводит к появлению окна редактирования слотов. С
помощью кнопки [New Slot] создаём новый слот. В свойствах слота меняем newSlot()
на ExitSlot() и нажимаем на кнопку [OK]. Аналогично создаём слоты OpenSlot(),
CloseSlot() и AboutSlot().
Теперь надо соединить действие fileExitAction с созданным слотом ExitSlot(). Для этого выделяем действие в окне Actions и нажимаем на синекрасную кнопку расположенную выше списка действий. В открывшемся окне редактирования соединений в левом верхнем углу расположен список сигналов, которые может генерировать объект; в правом верхнем - список слотов главной формы; внизу окна отображаются созданные соединения.
Выделим сигнал activated() и слот ExitSlot(), нажмём на активировавшуюся кнопку [Connect]. В списке созданных соединений появится новая строка.
Делаем аналогичные действия для действий fileOpenAction, fileCloseAction и helpAboutAction.
Сохраняем разработанную форму
Теперь необходимо созранить форму в каталоге проекта, например,
~/kwaveinfo/kwaveinfo/mainform.ui. При этом создаваемый файл перезапишет
файл-пустышку созданный KDevelop. Закрываем Qt Designer и переходим в KDevelop.
Использование формы
Проект созданный мастером использует QWidget для отображения пустой формы. Чтобы подставить созданную форму надо сделать небольшие изменения в исходном тексте файлов kwaveinfo.h и kwaveinfo.cpp.
kwaveinfo.h, до:
#include [kapp.h]
#include [qwidget.h]
/** KWaveInfo is the base class of the project */
class KWaveInfo : public QWidget
kwaveinfo.h, после:
#include [kapp.h]
#include [qwidget.h]
#include "mainform.h"
/** KWaveInfo is the base class of the project */
class KWaveInfo : public MainForm
kwaveinfo.cpp, до:
KWaveInfo::KWaveInfo(QWidget *parent, const char *name) : QWidget(parent, name)
kwaveinfo.cpp, после:
KWaveInfo::KWaveInfo(QWidget *parent, const char *name) : MainForm(parent, name)
Жирным шрифтом выделены изменения внесённые в код.
Использование слотов формы
Ранее в форме был определён слот ExitSlot().
В коде на языке C++ объявление слота выглядит так:
virtual void ExitSlot();
Таким образом, его можно переопределить в класс KWaveInfo, так
как данный класс был порождён от класса MainForm. Переопределяем:
// Закрываем приложение
void ExitSlot(void)
{
exit(0);
}
Теперь напишем код для слота OpenSlot():
#include [qfiledialog.h]
...
// Отображаем диалог открытия файла
QString Filename;
Filename = QFileDialog::getOpenFileName(
"/mnt/winxp", // Стартовый каталог
"Wave Files (*.wav)", // Фильтр для файлов
this, // Указатель на форму
"openfiledialog", // Имя диалога
"Choose a file to open...");// Заголовок диалога
// Проверяем выбор пользователя
if (Filename.isEmpty()) return;
// Изменияем заголовок формы приложения
setCaption(Filename + " - KWaveInfo");
// Вызываем функцию для отбработки указанного файла
GetInfoFromFile(Filename);
Код для слота
CloseSlot() будет выглядеть так:
// Удаляем информацию с формы
DisableAllElements();
edDataSize->setText("");
edCompression->setText("");
edChannels->setText("");
edFrequency->setText("");
// Восстанавливаем заголовок формы
setCaption("KWaveInfo");
Информация об авторе
Теперь напишем код, который будет выполняться при выборе меню
Help->About:
void KWaveInfo::AboutSlot(void)
{
QMessageBox::about(this, "About KWaveInfo",
"KWaveInfo is a simple RIFF file format viewer\n\n"
"Copyright 2003 Ruslan Popov aka RaD.\n"
"This application is freeware. Use it as is. No warranty!\n\n"
"For technical support, call 99-00-00 or see http://ts.kmc.ru/\n");
}
Управление элементами
Нижеприведённый код включает и отключает элементы на форме
приложения:
void KWaveInfo::DisableAllElements(void)
{
edDataSize->setEnabled(FALSE);
edCompression->setEnabled(FALSE);
edChannels->setEnabled(FALSE);
edFrequency->setEnabled(FALSE);
}
void KWaveInfo::EnableAllElements(void)
{
edDataSize->setEnabled(TRUE);
edCompression->setEnabled(TRUE);
edChannels->setEnabled(TRUE);
edFrequency->setEnabled(TRUE);
}
Чтение заголовка WAV файла
Теперь можно прочитать заголовок WAV файла. Для этого создаётся
структура описывающая формат заголовка и заполняется с помощью стандартных
функций файловой системы. Полученные данные отображаются на форме приложения.
void KWaveInfo::GetInfoFromFile(QString Filename)
{
// Variables
RIFF sRiff;
FILE *hF;
QString Temp;
// Get header of wave file
if ((hF = fopen(Filename, "rb")) == NULL) return;
if (fgets((char *)&sRiff, sizeof(RIFF), hF) == NULL) return;
if (hF != NULL) fclose(hF);
// Check file format
if (strncmp(sRiff.Riff, "RIFF", 4) != 0) return;
// Show information
EnableAllElements();
Temp = Temp.setNum(sRiff.DataSize);
edDataSize->setText(Temp + " bytes");
Temp = Temp.setNum(sRiff.CompressType);
switch(sRiff.CompressType)
{
case 0x01: Temp += " / PCM"; break;
case 0x02: Temp += " / MS ADPCM"; break;
case 0x03: Temp += " / Float PCM"; break;
case 0x06: Temp += " / a-law"; break;
case 0x07: Temp += " / u-law"; break;
case 0x11: Temp += " / IMA ADPCM"; break;
case 0x12: Temp += " / Videologic"; break;
case 0x13: Temp += " / Sierra ADPCM"; break;
case 0x20: Temp += " / Yamaha ADPCM"; break;
case 0x55: Temp += " / MPEG"; break;
default: Temp += " / Unknown"; break;
}
edCompression->setText(Temp);
Temp = Temp.setNum(sRiff.Channels);
switch (sRiff.Channels)
{
case 1: Temp += " / Mono"; break;
case 2: Temp += " / Stereo"; break;
case 4: Temp += " / Quadro"; break;
default: Temp += " / Unknown"; break;
}
edChannels->setText(Temp);
Temp = Temp.setNum(sRiff.Frequency);
edFrequency->setText(Temp + " Hz");
}
Внешний вид приложения
Вот так выглядит созданное приложение:
Исходный код приложения
Ниже приведён код, файлов в которые мы вносили изменения.
Остальные файлы проекта, после их автоматической генерации остались без
изменения.
Заголовочный файл
/***************************************************************************
kwaveinfo.h - description
-------------------
begin : Суб Янв 11 02:30:19 KRAT 2003
copyright : (C) 2003 by Ruslan Popov aka RaD
email : rad@kmc.ru
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef KWAVEINFO_H
#define KWAVEINFO_H
#ifdef HAVE_CONFIG_H
#include [config.h]
#endif
#include [kapp.h]
#include [qwidget.h]
#include "mainform.h"
#define UINT unsigned int
#define WORD unsigned short int
#define BYTE unsigned char
// RIFF WAVE header's structure
typedef struct {
char Riff[4];
UINT FileSize;
char Wave[4];
char Fmt[4];
UINT FormatSize;
WORD CompressType;
WORD Channels;
UINT Frequency;
UINT AvgBytesPerSec;
WORD BytesPerSample;
WORD BitsPerSample;
char Data[4];
UINT DataSize;
} RIFF, *PRIFF;
/** KWaveInfo is the base class of the project */
class KWaveInfo : public MainForm
{
Q_OBJECT
public:
/** construtor */
KWaveInfo(QWidget* parent=0, const char *name=0);
/** destructor */
~KWaveInfo();
// Define form's slots
void OpenSlot(void);
void CloseSlot(void);
void ExitSlot(void);
void AboutSlot(void);
// Define functions
void DisableAllElements(void);
void EnableAllElements(void);
void GetInfoFromFile(QString Filename);
};
#endif
Исходный файл
/***************************************************************************
kwaveinfo.cpp - description
-------------------
begin : Суб Янв 11 02:30:19 KRAT 2003
copyright : (C) 2003 by Ruslan Popov aka RaD
email : rad@kmc.ru
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include [qfiledialog.h]
#include [qlineedit.h]
#include [qmessagebox.h]
#include [stdio.h]
#include [string.h]
#include "kwaveinfo.h"
#define CAPTION "KWaveInfo"
KWaveInfo::KWaveInfo(QWidget *parent, const char *name) : MainForm(parent, name)
{
DisableAllElements();
}
KWaveInfo::~KWaveInfo()
{
}
void KWaveInfo::OpenSlot(void)
{
// Open File Dialog
QString Filename;
Filename = QFileDialog::getOpenFileName(
"/mnt/winxp", // Start path
"Wave Files (*.wav)", // Filter
this, // Pointer to parent window
"openfiledialog", // Dialog's name
"Choose a file to open...");// Dialog's caption
// Check existence of filename
if (Filename.isEmpty()) return;
// Set caption
setCaption(Filename + " - " + CAPTION);
// Get WAV format information
GetInfoFromFile(Filename);
}
void KWaveInfo::CloseSlot(void)
{
// Remove information
DisableAllElements();
edDataSize->setText("");
edCompression->setText("");
edChannels->setText("");
edFrequency->setText("");
// Set caption
setCaption(CAPTION);
}
void KWaveInfo::ExitSlot(void)
{
// Exit application
exit(0);
}
void KWaveInfo::AboutSlot(void)
{
QMessageBox::about(this, "About KWaveInfo",
"KWaveInfo is a simple RIFF file format viewer\n\n"
"Copyright 2003 Ruslan Popov aka RaD.\n"
"This application is freeware. Use it as is. No warranty!\n\n"
"For technical support, call 99-00-00 or see http://ts.kmc.ru/\n");
}
void KWaveInfo::DisableAllElements(void)
{
edDataSize->setEnabled(FALSE);
edCompression->setEnabled(FALSE);
edChannels->setEnabled(FALSE);
edFrequency->setEnabled(FALSE);
}
void KWaveInfo::EnableAllElements(void)
{
edDataSize->setEnabled(TRUE);
edCompression->setEnabled(TRUE);
edChannels->setEnabled(TRUE);
edFrequency->setEnabled(TRUE);
}
void KWaveInfo::GetInfoFromFile(QString Filename)
{
// Variables
RIFF sRiff;
FILE *hF;
QString Temp;
// Get header of wave file
if ((hF = fopen(Filename, "rb")) == NULL) return;
if (fgets((char *)&sRiff, sizeof(RIFF), hF) == NULL) return;
if (hF != NULL) fclose(hF);
// Check file format
if (strncmp(sRiff.Riff, "RIFF", 4) != 0) return;
// Show information
EnableAllElements();
Temp = Temp.setNum(sRiff.DataSize);
edDataSize->setText(Temp + " bytes");
Temp = Temp.setNum(sRiff.CompressType);
switch(sRiff.CompressType)
{
case 0x01: Temp += " / PCM"; break;
case 0x02: Temp += " / MS ADPCM"; break;
case 0x03: Temp += " / Float PCM"; break;
case 0x06: Temp += " / a-law"; break;
case 0x07: Temp += " / u-law"; break;
case 0x11: Temp += " / IMA ADPCM"; break;
case 0x12: Temp += " / Videologic"; break;
case 0x13: Temp += " / Sierra ADPCM"; break;
case 0x20: Temp += " / Yamaha ADPCM"; break;
case 0x55: Temp += " / MPEG"; break;
default: Temp += " / Unknown"; break;
}
edCompression->setText(Temp);
Temp = Temp.setNum(sRiff.Channels);
switch (sRiff.Channels)
{
case 1: Temp += " / Mono"; break;
case 2: Temp += " / Stereo"; break;
case 4: Temp += " / Quadro"; break;
default: Temp += " / Unknown"; break;
}
edChannels->setText(Temp);
Temp = Temp.setNum(sRiff.Frequency);
edFrequency->setText(Temp + " Hz");
}
Интернационализация приложения
Что такое i18n
i18n является системой интернационализации, которая
используется для работы с интернационализированными (ну и словечко :) версиями
приложений или проектов. Обычно приложения поддерживают только родной язык
автора, данное обстоятельство немножко напрягает людей не знакомых с языком
автора. Цель интернационализации представлять приложение на языке пользователя.
Как KDE поддерживает интернационализацию
Одной из задач KDE является предоставление
приложений пользователю на его родном языке и упростить для разработчика процесс
перевода своего приложения.
Технически, это реализовано в стандарте KDE File
System, который включает в себя поддержку локализации и предоставляет
приложениям поддержку интернационализации через использование класса KLocale
библиотеки KDE-core.
Со стороны разработчика надо сделать следующее:
- Подключить kapp.h к исходному коду;
- При работе с отображаемым текстом заключать его в i18n()
макрос;
- При использовании локали использовать klocale() макрос.
Это всё, что надо будет помнить при
программировании. Отметьте, что не следует интернационализировать
конфигурационные строки, которые используются KConfig.
Добавляем язык в проект
KDevelop облегчает жизнь разработчика. При создании
проекта в главный каталог проекта добавляется каталог po. Затем в этот каталог
добавляется kwaveinfo.pot (что-то я не нашёл такого у себя). Этот файл должен
содержать все строки для которых был использован i18n макрос, теперь вы должны
писать свой код, не забывая использовать i18n макрос при работе с отображаемыми
строками. Добавлять строки в файл надо время от времени с помощью меню
Project->Make messages and merge.
Добавить новый язык для приложения можно с помощью
меню Project->Add new Translation File, в появившемся окне надо выбрать
требующийся язык. Соответствующий, в нашем случае русский, файл ru.po появится в
каталоге po проекта.
После этого в дереве KWaveInfo, которое находится
на вкладке Groups, в элементе Translations появится элемент ru.po. Кликнем на
него, на вопрос открывать файл как текст, скажем нет. Откроется приложение
KBabel...
Но вся проблема в том, что при создании файла
перевода у меня выскакивает следующая ошибка:
gmake -f admin/Makefile.common package-messages gmake[1]: Вход в каталог `/root/ProjectsQt/kwaveinfo' ./kwaveinfo ./kwaveinfo has *.rc or *.ui files, but not correct messages line gmake[2]: Вход в каталог `/root/ProjectsQt/kwaveinfo/kwaveinfo' xgettext: ошибка открытия файла "/include/kde.pot" для чтения: Нет такого файла или каталога gmake[2]: *** [messages] Ошибка 1 gmake[2]: Выход из каталог `/root/ProjectsQt/kwaveinfo/kwaveinfo' gmake[1]: Выход из каталог `/root/ProjectsQt/kwaveinfo' gmake -C po merge gmake[1]: Вход в каталог `/root/ProjectsQt/kwaveinfo/po' gmake -f ../admin/Makefile.common package-merge POFILES="ru.po" PACKAGE=kwaveinfo gmake[2]: Вход в каталог `/root/ProjectsQt/kwaveinfo/po' admin/cvs.sh: admin/cvs.sh: Нет такого файла или каталога gmake[2]: *** [package-merge] Ошибка 127 gmake[2]: Выход из каталог `/root/ProjectsQt/kwaveinfo/po' gmake[1]: *** [merge] Ошибка 2 gmake[1]: Выход из каталог `/root/ProjectsQt/kwaveinfo/po' gmake: *** [package-messages] Ошибка 2 *** failed ***
Надо как-то решить проблему! Наверное, я просто
дождусь выхода следующей версии KDevelop.
Заключение
Надеюсь эта обзорная статья показала, что под Linux/Qt/KDE можно создавать приложения, пользуясь достаточно удобной интегрированной средой разработки.
|