Вместо предисловия.
К сожалению по wxWidgets очень мало литературы. В руки попала книга "Cross-Platform GUI Programming with wxWidgets" авторы Julian Smart и Kevin Hock вместе с Stefan Csomor. Книга на английском языке. Решил некоторые главы перевести, а так как в книге написано — This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/), то решил результаты выложить у себя в блоге.
Сразу же хочу заявить, что к переводу который находиться здесь http://forums.realcoding.net/index.php?showtopic=20649 отношения не имею.
В этой главе мы изучим структуру простой программы на wxWidgets используя небольшой пример. Мы рассмотрим, где и как wxWidgets приложение начинает и заканчивает свою работу, как отобразить главное окно, и как реагировать на команды от пользователя.
Следуя wxWidgets философии, мы собираемся охватить всё что можно сделать хорошо в этой главе. Вы можете также обратиться к Приложению A, “ Установка wxWidgets.”
Небольшой пример на WXWIDGETS.
Рисунок 2_1 показывает, что наш пример напоминает стандартное Windows приложение.
Рис. 2_1 минимальное приложение под Windows.
Минимальное wxWidgets приложение отображает главное окно (wxFrame) со строкой меню (menu bar) и строкой состояния (status bar). Меню позволит Вам отобразить "about box" или выйти из программы. Всего этого достаточно чтобы показать основные принципы wxWidgets и заверить Вас, что Вы сможете запустить простой пример, и пройти весь путь до законченного приложения, тогда вера в себя и профессионализм вырастут.
THE APPLICATION CLASS - класс приложения.
Каждое wxWidgets приложение определяет класс приложений, производный от wxApp. Есть только один пример, и он представляет работающее приложение. По крайней мере, ваш класс должен определить функцию OnInit которая вызывается, когда wxWidgets начинает выполнять ваш код (эквивалент main или WinMain при программировании приложения C или Win32). Вот минимальное обьявление класса приложений, которое Вы можете записать:
__________________________________________________________________________
// ОБьявление класса приложения
class MyApp : public wxApp
{
public:
// Вызвать приложение для выполнения
virtual bool OnInit();
};
___________________________________________________________________________
При выполнение OnInit создается не менее одного окна, интерпретируются параметры командной строки, устанавливаются данные для приложения, и выполняются любые другие задачи инициализации, требуемые для приложения. Если функция возвращает истина (true), wxWidgets запускает цикл обработки сообщений, который будет обрабатывать пользовательский ввод и запускает, если необходимо обработчики событий. Если функция возвращает ложь (false), wxWidgets очистит его внутренние структуры, и приложение завершится.
Вот как выглядит простая реализация OnInit:
___________________________________________________________________________
bool MyApp::OnInit()
{
// Создать основное окно приложения
MyFrame *frame = new MyFrame(wxT(“Minimal wxWidgets App”));
// Показать
frame->Show(true);
// Запустить цикл обработки сообщений
return true;
}
___________________________________________________________________________
Мы создали пример нашего нового класса MyFrame (который мы позже определим), отображает его, и возвращает истину, чтобы запустить цикл обработки сообщений. В отличие от дочерних окон, окна верхнего уровня типа фреймов и диалогов нужно показать явно после создания. Заголовок фрейма передают к конструктору, обернутому в макрокоманду wxT () . Вы увидите, что это применяется во многих примерах wxWidgets и в библиотечном коде непосредственно- преобразовывает строку и символы к соответствующему типу, чтобы откомпилировать приложение в режиме Unicode. Эта макрокоманда также известна как алиас _T (). Её также можно использовать.
(Вы увидите, что макрокоманда символа подчеркивания _ () используется и говорит wxWidgets о переводе строки. См. Главу 16, “ Запись международных Приложений, ” для подробностей.)
Где же код, который создает пример MyApp? Это происходит внутри библиотеки wxWidgets, но Вы должны указать wxWidgets какой объект создавать. Так Вы должны добавить макрокоманду в ваш исполняемый файл:
___________________________________________________________________________
// Дать wxWidgets средства создать MyApp объект
IMPLEMENT_APP(MyApp)
___________________________________________________________________________
Не определив класс, wxWidgets не знал бы, как создать новый прикладной объект. Эта макрокоманда также вставляет код, который проверяет, что приложение и библиотека была откомпилирована, используя ту же самую конфигурацию компоновки, разрешённую
wxWidgets, чтобы сообщить о случайных несоответствиях, которые могли бы позже вызвать hard-todebug, отказ во время выполнения.
Когда wxWidgets создает объект MyApp, помещая результат в глобальную переменную wxTheApp. Вы можете использовать это в вашем приложении, но более удобно, если Вы не должны были привести wxApp указатель к MyApp. Вставте эту макрокоманду после объявления класса вашего приложения:
___________________________________________________________________________
// Принадлежность MyApp& wxGetApp()
DECLARE_APP(MyApp)
___________________________________________________________________________
Вы можете вызвать функцию wxGetApp, который возвращает ссылку на объект MyApp.
Совет
Даже если Вы не используете DECLARE_APP, Вы можете использовать переменную wxTheApp вызывая функцию wxApp. В этом случае нет потребности включать определенный вами заголовок приложения. Это может быть полезно в пределах кода (типа библиотеки) которая не знает об определенных классах приложения, и сохранять время компиляции.
THE FRAME CLASS - класс фрейма.
Давайте расмотрим класс фрейма MyFrame. Фрейм - окно верхнего уровня, которое содержит другие окна, и обычно имеют область заголовка и строку меню. Наш пример объявление класса фрейма, который мы поместим после объявления MyApp:
___________________________________________________________________________
// Объявить наш главный класс фрейма
class MyFrame : public wxFrame
{
public:
// Конструктор
MyFrame(const wxString& title);
// Обработчики событий
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
private:
// Это класс обработчиков событий
DECLARE_EVENT_TABLE()
};
___________________________________________________________________________
Наш класс фрейма имеет конструктор, два обработчика события, чтобы связать команды меню с кодом C++, и макрокоманда, чтобы указать wxWidgets, что этот класс обрабатывает события.
THE EVENT HANDLERS - обработчики событий.
Поскольку Вы, возможно заметили, что функции обработчика событий в MyFrame не виртуальны и не должны быть виртуальны. Как, тогда, их вызывают? Ответ находится в таблице обработчиков, вот она:
___________________________________________________________________________
// таблица обработчиков для MyFrame
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
EVT_MENU(wxID_EXIT, MyFrame::OnQuit)
END_EVENT_TABLE()
___________________________________________________________________________
Эта таблица, которая помещена в исполняемый файл, говорит wxWidgets как события исходящие либо от пользователя, либо от других источников направлены к членам функции.
В этой таблице при нажатии нажатии мышью на кнопках меню идентификаторы wxID_EXIT и wxID_ABOUT направлены к функциям MyFrame:: OnQuit и MyFrame:: OnAbout, соответственно. EVT_MENU - только один из множества макроопределений таблицы обработчиков, которые Вы можете использовать, чтобы указать wxWidgets какой обработчик должен быть направлен к какой функции.
Идентификаторы, используемые здесь предопределены wxWidgets, но Вы будете часто пределять ваши собственные идентификаторы, используя перечисления, константы, или предопределения препроцессора.
Этот вид таблицы обрабочиков - статический способ направить события, и не может быть измененно во время выполнения. В следующей главе, мы опишем, как установить динамическую обработку событий.
Работая с таблицами обработчиков, давайте расмотрим две функции, использованные как обработчики события.
___________________________________________________________________________
void MyFrame::OnAbout(wxCommandEvent& event)
{
wxString msg;
msg.Printf(wxT(“Hello and welcome to %s”),
wxVERSION_STRING);
wxMessageBox(msg, wxT(“About Minimal”),
wxOK | wxICON_INFORMATION, this);
}
void MyFrame::OnQuit(wxCommandEvent& event)
{
// уничтожить фрейм
Close();
}
___________________________________________________________________________
MyFrame:: OnAbout показывает окно сообщения, когда пользователь нажимает на пункт меню About/
wxMessageBox содержит сообщение, заголовок, комбинацию стилей, и родительское окно.MyFrame:: OnQuit вызывается, когда пользователь нажимает по пункту меню Quit, благодаря таблице обработчиков. Происходит закрытие и уничтожение фрейма, вызывая, закрытие приложения, так как нет других фреймов. Фактически закрытие не уничтожает фрейм, это генерирует wxEVT_CLOSE_WINDOW - событие, и заданный по умолчанию обработчик для этого события уничтожает фрейм, используя wxWindow::Destroy.
Также фрейм может быть закрыт, а значит и закрыто приложение, если пользователь нажмет на кнопке x расположенную на фрейме или с помощью команды ситемы упраления Windows.
Как вызывается OnQuit в этом случае? wxWidgets посылает wxEVT_CLOSE_WINDOW событие фрейму через Close (как используется в OnQuit). wxWidgets обрабатывает это событие, значение по умолчанию и уничтожает окно. Ваше приложение может изменить это поведение если обеспечить его собственным обработчиком событий, если Вы хотите спросить пользователя для подтверждения перед закрытием. Для подробностей, пожалуйста см. Главу 4, “Основы окон.”
Данный пример не нуждается в этом, но большинство приложений должно обеспечить OnExit функцию в ее прикладном классе, чтобы очистить структуры данных перед выходом. Обратите внимание, что эту функцию вызывают только, если OnInit возвращает истину.
THE FRAME CONSTRUCTOR - конструктор фрейма.
Наконец, мы имеем конструктор фрейма, который создаёт иконку у фрейма, строку меню, и строку состояния.
___________________________________________________________________________
#include “mondrian.xpm”
MyFrame::MyFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title)
{
// Установить иконку фрейма
SetIcon(wxIcon(mondrian_xpm));
// Создать строку меню
wxMenu *fileMenu = new wxMenu;
// пукт “About” должен быть в меню справки
wxMenu *helpMenu = new wxMenu;
helpMenu->Append(wxID_ABOUT, wxT(“&About...\tF1”),
wxT(“Show about dialog”));
fileMenu->Append(wxID_EXIT, wxT(“E&xit\tAlt-X”),
wxT(“Quit this program”));
// Теперь добавьте в конец недавно созданного меню строку меню...
wxMenuBar *menuBar = new wxMenuBar();
menuBar->Append(fileMenu, wxT(“&File”));
menuBar->Append(helpMenu, wxT(“&Help”));
// ...и прикрепляют эту строку меню к фрейму
SetMenuBar(menuBar);
//Создать строку состояния для примера
CreateStatusBar(2);
SetStatusText(wxT(“Welcome to wxWidgets!”));
}
___________________________________________________________________________
Этот конструктор вызывает основной конструктор с родительским окном (с пустым указателем)), идентификатор окна, и заголовок. Параметр идентификатора - wxID_ANY, который говорит wxWidgets непосредственно генерировать идентификатор .Основной
конструктор создает фактическое окно, связанное с образцовым или вызвать заданный по умолчанию конструктор базового класса, и затем явно вызвать wxFrame::Create внутри MyFrame конструктора.
Маленькие точечные рисунки и иконки могут быть созданы, используя формат XPM на всех платформах. XPM файлы имеют правильный синтаксис C++ и могут быть включены как показано; строка SetIcon создает значок на стеке, используя C++ переменные mondrian_xpm определенный в mondrian.xpm, и ассоциированы с фреймом.
Следующей создана cтрока меню . Пункты меню добавляются, используя идентификатор (типа стандартного идентификатора wxID_ABOUT), метки, которая будет отображена, и помогает строке быть показанной на строке состояния. В пределах каждой метки, мнемонического символа отмечен предыдущим амперсандом, и акселератору предшествуют
cимвол табуляции (\t). Мнемонический - символ, который пользователь нажимает, чтобы подсветить элемент пункта, когда меню отображено. Акселератор - ключевая комбинация (типа Alt+X), который может использоваться, чтобы исполнить действие, не показывая меню вообще.
Последнее что делает конструктор, создаёт строку состояния с двумя полями внизу фрейма и устанавливает в первое поле строку “Добро пожаловать к wxWidgets! ”
Вся программа.
Внизу представлен листинг программы, которую мы рассматривали полностью. Принято отделять файл реализации от заголовочных файлов, но в данном случае так как размер программы небольшой мы объеденим всё в одном файле.
___________________________________________________________________________
Listing 2-1 The Complete Example
// Name: minimal.cpp
// Purpose: Minimal wxWidgets sample
// Author: Julian Smart
#include “wx/wx.h”
// Declare the application class
class MyApp : public wxApp
{
public:
// Called on application startup
virtual bool OnInit();
};
// Declare our main frame class
class MyFrame : public wxFrame
{
public:
// Constructor
MyFrame(const wxString& title);
// Event handlers
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
private:
// This class handles events
DECLARE_EVENT_TABLE()
};
// Implements MyApp& GetApp()
DECLARE_APP(MyApp)
// Give wxWidgets the means to create a MyApp object
IMPLEMENT_APP(MyApp)
// Initialize the application
bool MyApp::OnInit()
{
// Create the main application window
MyFrame *frame = new MyFrame(wxT(“Minimal wxWidgets App”));
// Show it
frame->Show(true);
// Start the event loop
return true;
}
// Event table for MyFrame
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
EVT_MENU(wxID_EXIT, MyFrame::OnQuit)
END_EVENT_TABLE()
void MyFrame::OnAbout(wxCommandEvent& event)
{
wxString msg;
msg.Printf(wxT(“Hello and welcome to %s”),
wxVERSION_STRING);
wxMessageBox(msg, wxT(“About Minimal”),
wxOK | wxICON_INFORMATION, this);
}
void MyFrame::OnQuit(wxCommandEvent& event)
{
// Destroy the frame
Close();
}
#include “mondrian.xpm”
MyFrame::MyFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title)
{
// Set the frame icon
SetIcon(wxIcon(mondrian_xpm));
// Create a menu bar
wxMenu *fileMenu = new wxMenu;
// The “About” item should be in the help menu
wxMenu *helpMenu = new wxMenu;
helpMenu->Append(wxID_ABOUT, wxT(“&About...\tF1”),
wxT(“Show about dialog”));
fileMenu->Append(wxID_EXIT, wxT(“E&xit\tAlt-X”),
wxT(“Quit this program”));
// Now append the freshly created menu to the menu bar...
wxMenuBar *menuBar = new wxMenuBar();
menuBar->Append(fileMenu, wxT(“&File”));
menuBar->Append(helpMenu, wxT(“&Help”));
// ... and attach this menu bar to the frame
SetMenuBar(menuBar);
// Create a status bar just for fun
CreateStatusBar(2);
SetStatusText(wxT(“Welcome to wxWidgets!”));
}
___________________________________________________________________________
ПРОЦЕСС ВЫПОЛНЕНИЯ ПРОГРАММЫ
Последовательность выполнения приложения:
1. В зависимости от платформы выполняется main, WinMain, или эквивалентная функция wxWidgets инициализирует внутренние данные, структурируются и создают образец MyApp.
2. wxWidgets вызывает MyApp:: OnInit, который создает образец MyFrame.
3. MyFrame конструктор создает окно через wxFrame конструктор и добавляет иконку, строку меню, и строку состояния.
4. MyApp:: OnInit отображает фрейм и возвращает истину.
5. wxWidgets начинает цикл обработки сообщений, ждущий событий и диспетчеризации их на соответствующие обработчики.Как отмечено здесь, приложение заканчивается, когда фрейм закрыт, если пользователь или выбирает пункт меню Quit или закрывает фрейм через
стандартные кнопки или меню (они будут отличаться в зависимости от платформы).
РЕЗЮМЕ
Эта глава даёт Вам понять об относительно простой работе wxWidgets. Мы затронули wxFrame класс, обработку событий, прикладную инициализацию, и создание строки меню и строки состояния. Ваш более сложный собственный код складывается, используя основные принципы как мы показали в этом небольшом примере. В следующей главе, мы рассмотрим события и как ваше приложение обрабатывает их.
перевёл Goodluck Дмитрий(Cema)
По сути…
Спасибо…