355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Нейл Мэтью » Основы программирования в Linux » Текст книги (страница 62)
Основы программирования в Linux
  • Текст добавлен: 21 сентября 2016, 17:59

Текст книги "Основы программирования в Linux"


Автор книги: Нейл Мэтью


Соавторы: Ричард Стоунс
сообщить о нарушении

Текущая страница: 62 (всего у книги 67 страниц)

gboolean delete_event_handler(GtkWidget* window, GdkEvent *event,

 gpointer data) {

 return !confirm_exit();

}

5. Следующая функция вызывается, когда мышью щелкается кнопка в диалоговом окне вставки компакт-диска. Если вы щелкнули мышью кнопку OK, программа копирует строки в массив типа char и передает его данные в интерфейсную функцию MySQL add_cd:

void addcd_dialog_button_clicked(GtkDialog * dialog, gint response,

 gpointer userdata) {

 const gchar *artist_const;

 const gchar* title_const;

 const gchar *catalogue_const;

 gchar artist[200];

 gchar title[200];

 gchar catalogue[200];

 gint *cd_id;

 if (response == GTK_RESPONSE_ACCEPT) {

  artist_const = gtk_entry_get_text(GTK_ENTRY(artist_entry));

  title_const = gtk_entry_get_text(GTK_ENTRY(title_entry));

  catalogue_const = gtk_entry_get_text(GTK_ENTRY(catalogue_entry));

  strcpy(artist, artist_const);

  strcpy(title, title_const);

  strcpy(catalogue, catalogue_const);

  add_cd(artist, title, catalogue, cd_id);

 }

 addcd_dialog = NULL;

 gtk_widget_destroy(GTK_WIDGET(dialog));

}

6. Далее идет самая важная часть приложения: извлечение результатов поиска и заполнение объекта GtkTreeView:

void on_search_button_clicked(GtkButton* button, gpointer userdata) {

 struct cd_search_st cd_res;

 struct current_cd_st cd;

 struct current_tracks_st ct;

 gint res1, res2, res3;

 gchar track_title[110];

 const gchar *search_string_const;

 gchar search string[200];

 gchar search_text[200];

 gint i = 0, j = 0;

 GtkTreeStore *tree_store;

 GtkTreeIter parent_iter, child_iter;

 memset(&track_title, 0, sizeof(track_title));

7. Здесь вы получаете строку поиска из виджета ввода, копируете ее в переменную и выбираете соответствующие ID компакт-дисков:

 search_string_const = gtk_entry_get_text(GTK_ENTRY(userdata));

 strcpy(search_string, search_string_const);

 resl = find_cds(search_string, &cd_res);

8. Затем вы обновляете appbar для вывода сообщения, информирующего пользователя о результатах поиска:

 sprintf(search_text, «Displaying %d result(s) for search string ' %s'»,

  MIN(res1, MAX_CD_RESULT), search_string);

 gnome_appbar_push(GNOME_APPBAR(appbar), search_text);

9. Теперь у вас есть результаты поиска, и можно заполнять ими модель GtkTreeStore. Для каждого ID компакт-диска необходимо извлечь соответствующую структуру типа current_cd_st, которая содержит название и исполнителя CD, и затем извлечь список дорожек диска. В заголовочном файле app_mysql.h задано ограничение количества элементов, MAX_CD_RESULT, для того, чтобы не было переполнения модели GtkTreeStore:

 tree_store = gtk_tree_store_new(N_COLUMNS,

  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);

 while (i < res1 && i < MAX_CD_RESULT) {

  res2 = get_cd(cd_res.cd_id[i], &cd);

  /* В модель вставляется новая строка */

  gtk_tree_store_append(tree_store, &parent_iter, NULL);

  gtk_tree_store_set(tree_store, &parent_iter, COLUMN_TITLE,

   cd.title, COLUMN_ARTIST, cd.artist_name, COLUMN_CATALOGUE,

   cd.catalogue, -1);

  res3 = get_cd_tracks(cd_res.cd_id[i++], &ct);

  j = 0;

  /* Заполнение дерева дорожками текущего компакт-диска */

  while (j < res3) {

   sprintf(track_title, " Track %d. ", j+1);

   strcat(track_title, ct.track[j++]);

   gtk_tree_store_append(tree_store, &child_iter, &parent_iter);

   gtk_tree_store_set(tree_store, &child_iter,

    COLUMN_TITLE, track_title, -1);

  }

 }

 gtk_tree_view_set_model(GTK_TREE_VIEW(treeview),

 GTK_TREE_MODEL(tree_store));

}

10. Диалоговое окно addcd немодальное. Следовательно, перед его созданием и отображением вы проверяете, не активно ли оно уже:

void on_addcd_activate(GtkMenuItem* menuitem, gpointer user_data) {

 if (addcd_dialog != NULL) return;

 addcd_dialog = create_addcd_dialog();

 gtk_widget_show_all(addcd_dialog);

}

gboolean close_app(GtkWidget * window, gpointer data) {

 gboolean exit;

 if ((exit = confirm_exit())) {

  quit_app(NULL, NULL);

 }

 return exit;

}

11. Когда вы щелкаете мышью кнопку About (О программе), раскрывается стандартное поле about среды GNOME:

void on_about_activate(GtkMenuItem* menuitem, gpointer user_data) {

 const char* authors[] = {"Wrox Press", NULL};

 GtkWidget* about = gnome_about_new(«CD Database», «1.0»,

  « (c) Wrox Press», «Beginning Linux Programming»,

  (const char **)authors, NULL, «Translators», NULL);

 gtk_widget_show(about);

}

Упражнение 16.14. Файл main.c

Введите следующий программный код в файл main.с, содержащий функцию main программы.

1. После операторов include вы ссылаетесь на поля ввода имени пользователя и пароля из файла interface.c:

#include

#include

#include «app_gnome.h»

extern GtkWidget* username_entry;

extern GtkWidget* password_entry;

gint main(gint argc, gchar *argv[]) {

 GtkWidget *main_window;

 GtkWidget *login_dialog;

 const char *user_const;

 const char *pass_const;

 gchar username[100];

 gchar password[100];

 gint result;

2. Инициализируйте как обычно библиотеки GNOME и затем создайте и отобразите на экране главное окно и диалоговое окно вашей регистрации:

 gnome_program_init(«CdDatabase», «0.1», LIBGNOMEUI_MODULE, argc, argv,

  GNOME_PARAM_APP_DATADIR, "", NULL);

 main_window = create_main_window();

 gtk_widget_show_all(main_window);

 login_dialog = create_login_dialog();

3. Вы ждете в цикле, пока пользователь не введет корректную комбинацию имени пользователя и пароля. Он может выйти из приложения, щелкнув мышью кнопку Cancel, причем в этом случае ему придется подтвердить свое действие:

 while (1) {

  result = gtk_dialog_run(GTK_DIALOG(login_dialog));

  if (result != GTK_RESPONSE_ACCEPT) {

   if (confirm_exit()) return 0;

   else continue;

  }

  user_const = gtk_entry_get_text(GTK_ENTRY(username_entry));

  pass_const = gtk_entry_get_text(GTK_ENTRY(password_entry));

  strcpy(username, user_const);

  strcpy(password, pass_const);

  if (database_start(username, password) == TRUE) break;

4. Если функция database_start завершается аварийно, вы выводите сообщение и диалоговое окно регистрации снова отображается на экране:

  GtkWidget* error_dialog =

   gtk_message_dialog_new(GTK_WINDOW(main_window),

    GTK_DIALOG_DESTROY_WITH_PARENT,

    GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,

    «Could not log on! – Check Username and Password»);

  gtk_dialog_run(GTK_DIALOG(error_dialog));

  gtk_widget_destroy(error_dialog);

 }

 gtk_widget_destroy(login_dialog);

 gtk_main();

 return 0;

}

5. Для компиляции этого приложения напишите make-файл. Как и в главе 8, вам, возможно, придется указать место расположения библиотеки mysql-клиента с помощью строки, подобной приведенной далее:

-L/usr/lib/mysql

После опции -L поместите каталог, в котором ваша система хранит библиотеки MySQL:

all: app

app: app_mysql.c callbacks.с interface.c main.с app_gnome.h app_mysql.h

 gcc -o app -I/usr/include/mysql app_mysql.с callbacks.с interface.c main.с -lmysqlclient `pkg-config –cflags –libs libgnome-2.0 libgnomeui-2.0`

clean:

 rm -f app

6. Теперь для компиляции приложения для работы с компакт-дисками просто воспользуйтесь командой make:

make -f Makefile

Когда вы запустите приложение арр, то получите ваше приложение для работы с базой данных компакт-дисков в стиле GNOME (рис. 16.15)!

Рис. 16.15

Резюме

В этой главе вы узнали о программировании с помощью библиотек GTK+/GNOME для создания приложений с профессионально выглядящем интерфейсом GUI. Сначала вы рассмотрели с X Window System и научились применять комплекты инструментальных средств, а затем вкратце познакомились с принципами работы GTK+ под управлением системы объектов и механизма сигналов/обратных вызовов этого комплекта инструментов.

Далее вы перешли к API виджетов GTK+, продемонстрировав их применение на простых и более сложных примерах, приведенных в нескольких листингах программ. Рассмотрев виджет GnomeApp, вы научились легко создавать меню с помощью вспомогательных макросов. В заключение вы узнали, как создавать модальные и немодальные диалоговые окна для взаимодействия с пользователем.

И в конце главы вы создали средствами GNOME/GTK+ интерфейс пользователя для вашей базы данных компакт-дисков, который позволяет регистрироваться в базе данных, искать компакт-диски и пополнять базу данных новыми CD.

В главе 17 вы познакомитесь с комплектом инструментальных средств, конкурирующим с GTK+, и научитесь программировать в среде KDE, применяя комплект Qt.

Глава 17
Программирование в KDE с помощью Qt

В главе 16 вы познакомились с библиотеками GUI графической среды GNOME/GTK+, предназначенными для создания пользовательского графического интерфейса под управлением системы X. Эти библиотеки – лишь половина истории, другой крупный игрок на поле GUI в системе Linux – графическая среда KDE/Qt, и в этой главе мы рассмотрим ее библиотеки и увидим, как они развиваются в условиях конкуренции.

Комплект инструментальных средств Qt написан на языке С++, стандартный язык для написания приложений Qt/KDE, поэтому в данной главе вам придется отойти от обычного языка С и испачкать свои руки С++. Возможно, вы воспользуетесь этой возможностью и освежите свои знания языка С++, вспомнив прежде всего принципы наследования и инкапсуляции, метод переопределения и виртуальные функции.

В этой главе мы обсудим следующие темы:

□ знакомство с комплектом инструментов Qt;

□ установка Qt;

□ практическое применение;

□ механизм "сигнал/слот";

□ виджеты Qt;

□ диалоговые окна;

□ создание меню и панелей инструментов с помощью KDE;

□ разработка средствами KDE/Qt вашего приложения для работы с базой данных компакт-дисков.

Введение в KDE и Qt

KDE (Desktop Environment, K-среда рабочего стола) – графическая среда рабочего стола с открытым программным кодом, основанная на библиотеке графического пользовательского интерфейса Qt. В состав KDE входит множество приложений и утилит, включая полный офисный пакет, Web-обозреватель и даже полнофункциональную IDE (интегрированная среда разработки) для программирования приложений KDE/Qt (KDevelop обсуждалась в главе 9). Профессиональное признание функциональных возможностей развитых приложений KDE пришло, когда компания Apple выбрала Web-обозреватель KDE в качестве ядра основного Web-обозревателя для системы Mac OS X, названного Safari и известного как очень быстрый обозреватель.

Главная страница проекта KDE находится по адресу http://www.kde.org, на ней вы найдете подробные сведения, файлы загрузки среды KDE и ее приложения, документацию, сможете присоединиться к списку адресатов файлов рассылок и получить другую информацию для разработчиков.

Примечание

Во время написания книги последней версией KDE была версия 3.5.7, и поскольку эта версия включена в современные дистрибутивы Linux, мы считаем, что у вас установлена версия KDE 3.5 или более свежая. Продолжается работа над крупным обновлением – KDE 4.0. Вы можете также загрузить из Интернета предварительные версии KDE 4.0. Точно так же самая свежая версия Qt – 4.3, но в большинстве дистрибутивов Linux установлена версия Qt 3, например версия 3.3, как стандартная версия Qt. В этой главе обсуждается Qt 3.3, потому что она встречается чаще других.

С точки зрения программиста, KDE предлагает десятки виджетов KDE, обычно унаследованных от их аналогов Qt, но улучшенных и облегчающих использование. Виджеты KDE обеспечивают более тесную связь с рабочим столом KDE, чем сам по себе комплект инструментов Qt; у вас появляется, например, возможность управления сеансами.

Qt – тщательно продуманный межплатформный комплект инструментов GUI, написанный на языке С++. Это детище норвежской компании Trolltech, разрабатывающей, продающей и осуществляющей техническую поддержку Qt и сопутствующего программного обеспечения для промышленного рынка. Trolltech во всеуслышание рекламирует межплатформные возможности комплекта Qt, которые бесспорно впечатляющи, Qt поддерживается в ОС Linux и модификациях UNIX, Windows, Mac OS X и даже на встроенных платформах, явно отдающих предпочтение комплекту Qt по сравнению с его конкурентами.

Примечание

Специализированная версия Qt выполняется на сотовых телефонах. Еще одна версия работает на PDA (Personal Digital Assistant, электронный секретарь) Sharp Zaurus и аналогичных платформах. Qt Jambi представляет собой версию комплекта инструментов для языка Java.

В настоящее время компания Trolltech продает коммерческие версии Qt случайным пользователям и любителям по завышенным ценам. К счастью, Trolltech понимает важность бесплатной версии для сообщества, распространяющего свободное программное обеспечение, и предлагает свободно распространяемую версию Qt Open Source Edition для. ОС Linux, Windows и Mac OS X. В ответ Trolltech получает большую базу пользовательских установок, обширное сообщество программистов и высокое реноме своего продукта.

Qt Open Source Edition распространяется на условиях лицензии GPL, т.е. вы можете программировать, используя библиотеки-Qt, и распространять бесплатно собственное программное обеспечение, отвечающее требованиям лицензии GPL. Насколько мы можем судить, у свободно распространяемой версии есть два основных отличия от коммерческих версий: отсутствие технической поддержки и запрет на применение программного обеспечения Qt в коммерческих приложениях. Вся необходимая вам документация по API есть на Web-сайте Trolltech по адресу http://www.trolltech.com.

Установка Qt

Если у вас нет особых причин для компиляции из исходного программного кода, самый простой путь – найти для вашего дистрибутива двоичный пакет или пакет RPM. Дистрибутив Fedora Linux 7 поставляется с пакетом qt-3.3.8-4.i386.rpm, который можно установить с помощью следующей команды.

$ rpm -Uvh qt-3.3.3-4.i386.rpm

Комплект Qt и библиотеки программирования KDE можно также установить с помощью приложения Package Manager (Диспетчер пакетов) – рис. 17.1.

Рис. 17.1

Если вы хотите загрузить из Интернета исходный программный код и сформировать Qt самостоятельно, самый свежий программный код можно получить с FTP-сайта Trolltech по адресу ftp://ftp.trolltech.com/qt/source/. Пакет исходного программного кода приходит с подробнейшими инструкциями, касающимися компиляции и установки Qt и хранящимися в файле INSTALL, упакованном программой tar.

$ сd /usr/local

$ tar -xvzf qt-x11-free-3.3.8.tar.gz

$ ./configure

$ make

Также следует добавить в файл /etc/ld.so.conf следующую строку:

/usr/lib/qt-3.3/lib

Вставить ее можно в любое место файла.

Примечание

В системах Linux Fedora и Red Hat эту строку нужно сохранить в файле /etc/ld.so.conf.d/qt-i386.conf. Если вы устанавливали Qt, как показано на рис. 17.1, этот этап уже будет пройден.

Если комплект Qt установлен корректно, переменная окружения QTDIR будет содержать каталог установки. Проверить это можно следующим образом:

$ echo $QTDIR

/usr/lib/qt-3.3

Убедитесь также в том, что каталог lib добавлен в файл /etc/ld.so.conf. Затем выполните как суперпользователь следующую команду:

# ldconfig

Испытайте простейшую программу с применением Qt и убедитесь в том, что ваша установка функционирует должным образом (упражнение 17.1).

Упражнение 17.1. Окно QMain

Введите (или скопируйте и вставьте программный код из загруженного файла) приведенную далее программу и назовите ее qt1.cpp:

#include

#include

int main(int argc, char **argv) {

 QApplication app(argc, argv);

 QMainWindow* window = new QMainWindow();

 app.setMainWidget(window);

 window->show();

 return app.exec();

}

При компиляции вам необходимо указать Qt-каталоги include и lib:

$ g++ -о qt1 qt1.cpp -I$QTDIR/include -L$QTDIR/lib -lqui

Примечание

На некоторых платформах в конце строки указывается библиотека -lqt. В версии Qt 3.3, тем не менее, используйте -lqui.

Выполнив приложение, вы должны получить окно Qt (рис. 17.2).

$ ./qtl

Рис. 17.2

Как это работает

В отличие от GTK+ здесь нет вмещающего в себя все заголовочного файла qt.h, поэтому вы должны явно включать заголовочные файлы всех используемых объектов.

Первый объект, с которым вы встречаетесь, – QApplication. Это главный объект Qt, который вы должны сформировать, передав ему в самом начале аргументы командной строки. У каждого приложения Qt должен быть один и только один объект типа QApplication, который вы должны создать перед тем, как делать что-то еще. QApplication имеет дело с внутренними встроенными операциями Qt, такими как обработка событий, размещение строк и управление внешним представлением.

Вы будете применять два метода QApplication: setMainWidget, который создает главный виджет вашего приложения, и exec, который запускает выполнение цикла отслеживания событий. Метод exec не возвращает управление до тех пор, пока либо не будет вызван метод QApplication::quit(), либо не будет закрыт главный виджет.

QMainWindow – базовый виджет окна в Qt, который поддерживает меню, панель инструментов и строку состояния. Он будет играть важную роль в этой главе, по мере того, как вы научитесь расширять его возможности и вставлять в него виджеты, формирующие интерфейс.

Далее мы обсудим механизм программирования, управляемого событиями, и вы вставите в приложение виджет PushButton.

Сигналы и слоты

Как вы видели в главе 16, сигналы и их обработка – главные механизмы, используемые приложениями GUI для реагирования на ввод пользователя, и ключевые функции библиотек GUI. Механизм обработки сигналов комплекта Qt состоит из сигналов и слотов или приемников, называемых сигналами и функциями обратного вызова в комплекте инструментов GTK+ или событиями и обработчиками событий в языке программирования Java.

Примечание

Имейте в виду, что сигналы Qt отличаются от сигналов UNIX, обсуждавшихся в главе 11.

Вот как устроено программирование, управляемое событиями: графический интерфейс пользователя состоит из меню, панелей инструментов, кнопок, полей ввода и множества других элементов GUI, называемых виджетами. Когда пользователь взаимодействует с виджетом, например, активизирует пункт меню или вводит какой-то текст в поле ввода, виджет порождает именованный сигнал, такой как clicked, text_changed или key_pressed. Как правило, вам захочется сделать что-то в ответ на действие пользователя, например, сохранить документ или выйти из приложения, и вы выполняете это, связав сигнал с функцией обратного вызова или слотом на языке Qt.

Применение сигналов и слотов довольно специфично – Qt определяет два новых соответствующим образом описанных псевдоключевых слова, signals и slots для обозначения в вашем программном коде классов сигналов и слотов. Это замечательно с точки зрения читаемости и сопровождения программного кода, но вы вынуждены пропускать свой код через отдельный этап препроцессорной обработки для поиска и замены этих псевдоключевых слов дополнительным кодом на языке С++.

Примечание

Таким образом, программный код с использованием Qt – не настоящий программный код на С++. Порой это становится проблемой для некоторых разработчиков. См. документацию Qt на Web-сайте http://doc.trolltech.com/, чтобы понять причину применения этих новых псевдоключевых слов в С++. Более того, применение сигналов и слотов не так уж отличается от Microsoft Foundation Classes (MFC, библиотека базовых классов Microsoft) в ОС Windows, в которой также используется модифицированное определение языка С++.

На способы применения сигналов и слотов в Qt есть несколько ограничений, но они не слишком существенные:

□ сигналы и слоты должны быть функциями-методами класса-потомка QObject;

□ при использовании множественного наследования QObject должен быть первым в списке класса;

□ оператор Q_OBJECT должен появляться первым в объявлении класса;

□ сигналы нельзя применять в шаблонах;

□ указатели на функцию не могут использоваться как аргументы в сигналах и слотах;

□ сигналы и слоты не могут переопределяться или обновляться до статуса public (общедоступный).

Поскольку вы должны писать ваши сигналы и слоты как потомков объекта QObject, логично создавать ваш интерфейс, расширяя и настраивая виджет, начиная с QWidget, базового виджета Qt, потомка виджета QObject. В комплекте Qt вы почти всегда будете создавать интерфейсы, расширяя такие виджеты, как QMainWindow.

Типичное определение класса в файле MyWindow.h для вашего GUI будет напоминать приведенное далее:

class MyWindow : public QMainWindow {

 Q_OBJECT

public:

 MyWindow();

 virtual ~MyWindow();

signals:

 void aSignal();

private slots:

 void doSomething();

}

Ваш класс – наследник объекта QMainWindow, который определяет функциональные возможности главного окна в приложении. Аналогичным образом при создании диалогового окна вы определите подкласс QDialog. Первым указан оператор Q_OBJECT, действующий как метка для препроцессора, за которым следуют обычные объявления конструктора и деструктора. Далее даны определения сигнала и слота.

У вас есть один сигнал и один слот, оба без параметров. Для порождения сигнала aSignal() вам нужно всего лишь в любом месте программы вызвать функцию emit:

emit aSignal();

Это означает, что все остальное обрабатывается Qt. Вам даже не потребуется реализация aSignal().

Для применения слотов их нужно связать с сигналом. Делается это соответствующим образом с помощью названного статического метода connect класса QObject:

bool QObject::connect(const QObject * sender, const char* signal,

 const QObject * receiver, const char * member);

Просто передайте объект, владеющий сигналом (отправитель), функцию сигнала, объект, владеющий слотом (приемником), и в завершение укажите имя слота.

В примере MyWindow, если бы вы захотели связать сигнал clicked виджета QPushButton с вашим слотом doSomething, вы бы написали:

connect(button, SIGNAL(clicked()), this, SLOT(doSomething()));

Учтите, что необходимо применять макросы SIGNAL и SLOT для выделения функций сигналов и слотов. Как и в комплекте GTK+, вы можете связать ряд слотов с заданным сигналом и также связать слот с любым количеством сигналов с помощью множественных вызовов функции connect. Если она завершается аварийно, то возвращает FALSE.

Остается реализовать ваш слот в виде обычной функции-метода:

void MyWindow::doSomething() {

 // Код слота

}

Выполните упражнение 17.2.

Упражнение 17.2. Сигналы и слоты

Теперь, зная основы использования сигналов и слотов, применим их в примере. Усовершенствуйте QMainWindow, вставьте в него кнопку и свяжите сигнал кнопки clicked со слотом.

1. Введите следующее объявление класса и назовите файл ButtonWindow.h:

#include

class ButtonWindow : public QMainWindow {

 Q_OBJECT

public:

 ButtonWindow(QWidget *parent = 0, const char *name = 0);

 virtual ~ButtonWindow();

private slots:

 void Clicked();

};

2. Далее следует реализация класса в файле ButtonWindow.cpp:

#include «ButtonWindow.moc»

#include

#include

#include

3. В конструкторе вы задаете заголовок окна, создаете кнопку и связываете сигнал нажатия кнопки с вашим слотом. setCaption – метод объектов типа QMainWindow, который, что неудивительно, задает заголовок окна:

ButtonWindow::ButtonWindow(QWidget *parent, const char* name) : QMainWindow(parent, name) {

 this->setCaption(«This is the window Title»);

 QPushButton *button = new QPushButton(«Click Me!», this, «Button1»);

 button->setGeometry(50, 30, 70, 20);

 connect(button, SIGNAL(clicked()), this, SLOT(Clicked()));

}

4. Qt автоматически удаляет виджеты, поэтому ваш деструктор пуст:

ButtonWindow::~ButtonWindow() {}

5. Затем реализация слота:

void ButtonWindow::Clicked(void) {

 std::cout << «clicked!n»;

}

6. И наконец, в функции main вы просто создаете экземпляр типа ButtonWindow, делаете его главным окном вашего приложения и отображаете окно на экране:

int main(int argc, char **argv) {

 QApplication app(argc, argv);

 ButtonWindow *window = new ButtonWindow();

 app.setMainWidget(window);

 window->show();

 return app.exec();

}

7. Прежде чем вы сможете откомпилировать данный пример, необходимо запустить препроцессор для заголовочного файла. Программа этого препроцессора называется Meta Object Compiler (moc, компилятор метаобъекта) и должна быть включена в пакет комплекта Qt. Выполните moc для файла ButtonWindow.h, сохранив результат в файле ButtonWindow.moc:

$ moc ButtonWindow.h -о ButtonWindow.moc

Теперь можно компилировать как обычно, скомпоновав с результатом команды moc.

$ g++ -о button ButtonWindow.срр -I$QTDIR/include -L$QTDIR/lib -lqui

Выполнив программу, вы получите пример, показанный на рис. 17.3.

Рис. 17.3

Как это работает

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

Конструктор объекта QPushButton очень прост.

QPushButton::QPushButton(const QString &text, QWidget *parent,

 const char* name=0);

Первый аргумент – текст метки кнопки, далее родительский виджет и последний аргумент – имя кнопки, обычно применяемое Qt для внутренних операций.

Параметр родительского виджета, общий для всех объектов, – QWidget, он управляет отображением и уничтожением и разными другими свойствами. Передача NULL в качестве родительского объекта означает виджет верхнего уровня, при этом создается содержащее его пустое окно. В примере вы передаете текущий объект ButtonWindow с помощью ключевого слова this, что приводит к вставке кнопки в основную область окна ButtonWindow.

Аргумент name задает имя виджета для внутреннего использования Qt. Если комплект Qt обнаружит ошибку, имя виджета будет выведено в сообщении об ошибке, поэтому неплохо выбирать подходящие имена виджетов, поскольку при отладке это сбережет массу времени.

Вы могли заметить, что объект QPushButton очень примитивно вставляется в окно ButtonWindow, с помощью параметра parent конструктора QPushButton, без указания положения кнопки, ее размера, рамки или чего-либо еще. Если вы хотите управлять внешним видом кнопки, что очень важно для создания привлекательного интерфейса, следует применять виджеты компоновки комплекта Qt. Давайте их сейчас рассмотрим,

В Qt есть целый ряд способов размещения и компоновки виджетов. Вы уже видели использование абсолютных координат с помощью вызова setGeometry, но они редко применяются, поскольку виджеты не масштабируются и не меняют размеры при изменении величины окна.

Предпочтительный метод компоновки виджетов – применение классов QLayout или виджетов-контейнеров, которые изменяют свои размеры соответствующим образом после задания им подсказок, касающихся отступов и расстояний между виджетами.

Ключевое различие между классами QLayout и упаковочными контейнерами заключается в том, что объекты класса QLayout не являются виджетами.

Классы компоновки – потомки объектов, типа QObject, а не QWidget, поэтому их применение ограничено. Например, вы не можете создать объект QVBoxLayout – основной виджет объекта QMainWindow.

Виджеты упаковочных контейнеров (такие, как QHBox и QVBox) напротив – потомки объекта типа QWidget следовательно, вы можете применять их как обычные виджеты. Возможно, вас удивляет, что в Qt есть и классы QLayout, и виджеты QBox с дублирующимися функциональными возможностями. На самом деле виджеты QBox существуют только для удобства и по существу служат оболочкой классов QLayout в типе QWidget. Объекты QLayout обладают возможностью автоматического изменения размеров, в то время как размеры виджетов нужно изменять вручную с помощью вызова метода QWidget::resizeEvent().

Подклассы QLayout: QVBoxLayout и QHBoxLayout, – самый распространенный способ создания интерфейса, и именно их вы будете чаще всего встречать в программном коде с применением Qt.

QVBoxLayout и QHBoxLayout – невидимые объекты-контейнеры, хранящие другие виджеты и схемы размещения с вертикальной и горизонтальной ориентациями соответственно. Вы сможете создавать сколь угодно сложные компоновки виджетов, поскольку допускается использование вложенных компоновок, например, за счет вставки как элемента горизонтальной схемы размещения внутрь вертикального упаковочного контейнера.

Есть три конструктора QVBoxLayout, заслуживающих внимания (у объектов QHBoxLayout идентичный API).

QVBoxLayout::QVBoxLayout(QWidget *parent, int margin, int spacing,

 const char *name)

QVBoxLayout::QVBoxLayout(QLayout *parentLayout, int spacing,

 const char * name)

QVBoxLayout::QVBoxLayout(int spacing, const char *name)

Родителем объекта QLayout может быть либо виджет, либо другой объект типа QLayout. Если не задавать родительский объект, вы сможете только вставить позже данную схему размещения в другой объект QLayout с помощью метода addLayout.

Параметры margin и spacing задают пустое пространство в пикселах вокруг схемы размещения QLayout и между отдельными виджетами в ней.

После создания вашей схемы размещения QLayout вы можете вставлять дочерние виджеты или схемы с помощью следующей пары методов:

QBoxLayout::addWidget(QWidget *widget, int stretch = 0, int alignment = 0);

QBoxLayout::addLayout(QLayout *layout, int stretch = 0);

Выполните упражнение 17.3.

Упражнение 17.3. Применение классов QBoxLayout

В этом примере вы увидите в действии классы QBoxLayout при размещении виджетов QLabel в окне QMainWindow.

1. Сначала введите заголовочный файл LayoutWindow.h:

#include

class LayoutWindow : public QMainWindow {

 QOBJECT

public:

 LayoutWindow(QWidget *parent = 0, const char *name = 0);

virtual ~LayoutWindow();

};

2. Теперь введите реализацию в файл LayoutWindow.cpp:

#include

#include

#include

#include «LayoutWindow.moc»

LayoutWindow::LayoutWindow(QWidget* parent, const char *name) :

 QMainWindow(parent, name) {

 this->setCaption(«Layouts»);

3. Необходимо создать фиктивный QWidget для хранения объекта QHBoxLayout, поскольку его нельзя напрямую вставить в объект QMainWindow:

 QWidget *widget = new QWidget(this);

 setCentralWidget(widget);

 QHBoxLayout *horizontal = new QHBoxLayout(widget, 5, 10, «horizontal»);

 QVBoxLayout *vertical = new QVBoxLayout();

 QLabel* label1 = new QLabel(«Top», widget, «textLabel1»);

 QLabel* label2 = new QLabel(«Bottom», widget, «textLabel2»);

 QLabel* label3 = new QLabel(«Right», widget, «textLabel3»);

 vertical->addwidget(label1);

 vertical->addwidget(label2);

 horizontal->addLayout(vertical);

 horizontal->addWidget(label3);

 resize(150, 100);

}

LayoutWindow::~LayoutWindow() { }

int main(int argc, char **argv) {

 QApplication app(argc, argv);


    Ваша оценка произведения:

Популярные книги за неделю