WxWidgets Hello World в Visual C++ и wxFormBuilder
Cоздаем приложение "Привет, Мир!" в VC++ 2015 и ФормБилдере
правитьВступление
правитьПрежде чем начать этом урок, следует отметить, что он описывает один из наиболее простых способов знакомства с wxWidgets с нуля, при котором вы не просто открываете готовый (и часто непонятный) пример, а создаете свой код. Однако, дальнейшее использование wxFormBuilder предполагает наличие у вас знаний языка C++, в частности понимания наследования классов. Кроме того, рано или поздно вы столкнетесь со ограниченностью возможностей формбилдера и необходимостью написания части кода GUI вручную, либо использования более функциональных конструкторов GUI вроде wxSmith (Code::Blocks) или wxDev-C++.
В wxDev-C++ создать Hello World можно даже меньшими усилиями, однако проект не развивается с 2012 года. Пример создания приложения при помощи wxSmith в Code::Blocks можно найти здесь: Уроки wxSmith: Hello world. Code::Blocks тоже притормозил развитие и поддерживает компиляторы Visual C++ лишь до VS 2010. Это накладывает свои ограничения на применение вышеупомянутых конструкторов GUI и позволяет wxFormBuilder в некоторых случаях конкурировать с ними.
wxFormBuilder позволяет генерировать (и при правильном использовании дорабатывать) код графического интерфейса в проектах Visual Studio современных версий, что позволяет использовать всю мощь современных компиляторов, в частности: совместимость с новыми версиями библиотек, векторизацию и распараллеливание кода, одним словом дает возможность создания современных программ для многоядерных процессоров и гетерогенных вычислений, что "не по зубам" древним компиляторам.
Примечание:
Хорошей альтернативой описанному ниже способу создания графического интерфейса является использование в качестве библиотеки Qt и конструктора GUI Qt Creator, благо их развитие идет динамичнее, чем развитие wxWidgets, Qt имеет средства интеграции в Visual Studio, Qt активнее используют в коммерческих проектах. Однако wxWidgets более компактна (с проистекающими последствиями), а также более лояльна к коммерческому использованию, поэтому интереснее для небольших проектов, где разработчики не могут позволить себе приобретение дорогостоящих средств разработки, но хотели бы коммерциализировать свой проект, не обладая уверенностью, что он будет успешен в денежном выражении.
Итак, какой бы мотивацией вы не руководствовались, начнем наш урок.
Что потребуется:
править- Visual Studio Community 2015 (далее VS), с установленными компонентами:
- Visual C++
- Windows SDK
- wxFormBuilder
- wxWidgets версии 3.0 или выше
Настройка среды разработки
правитьМожно использовать другую версию VS, но возникнут некоторые отличия в сборке библиотек wxWidgets. В VS 2015 это делается очень просто. Вместо VS можно также использовать компилятор Visual C++ с командной строки или свободный компилятор MinGW, однако это тоже усложнит задачу. Кроме того, если использовать wxWidgets версии 2.8 можно собрать проект даже на очень древних компиляторах (например от Borland) благо разработчики wxWindows позаботились об этом.
Вкратце об установке вышеуказанных программных продуктов:
- VS нужно скачать c официального сайта и при установке указать необходимые компоненты;
- wxFormBuilder последней версии можно найти на GitHub, жмем [Clone or download]->[Download ZIP]. Создаем каталог wxFormBuilder (например в корне диска C:) заливаем в него содержимое архива;
- wxWidgets качаем с официального сайта в виде "Windows Installer", устанавливаем (лучше всего в место с не слишком длинным путем и обязательно без русских букв).
Далее нужно собрать библиотеки wxWidgets:
- в подкаталоге библиотеки wxWigdets .\build\msw запускаем wx_vc14.sln
- в открывшемся проекте открываем пункт меню [Build]->[Batch Build...]
- выбираем всё [Select All], жмем [Build]
- ждем завершения процесса сборки (достаточно долгого - можно вполне успеть приготовить и попить кофе с плюшками) и если всё завершится хорошо, то в логе будет что-то вроде "Build: 192 succeeded, 0 failed, 0 up-to-date, 0 skipped".
Если вы решили пойти более сложным путем и выбрали другой компилятор, то, возможно, вам поможет страничка Настройка wxWidgets в Code::Blocks, там описан процесс сборки wxWidgets c командной строки.
Создание приложения
правитьИтак, приступим к созданию нашего суперприложения. Открываем VS и создаем новый проект [File]->[New]->[Project...].
В открывшемся окне выбираем [Installed]->[Templates]->[Visual С++]->[Win32]->[Win32 Project]. Даем проекту имя, например "wxHello".
В открывшемся окне мастера "Overview" жмем Next. Откроется окно настроек проекта "Application Settings". В окне ставим галочку Empty project" чтобы создать пустой проект. Остальные настройки - по умолчанию. Завершаем работу мастера нажатием [Finish].
В обозревателе созданного проекта делаем правый клик на название проекта (wxHello). В открывшемся меню жмем на [Add]->[New Filter]. Даем ему название GUI. Здесь будут ссылки на файлы wxFormBuilder.
Делаем правый клик на папке GUI. Далее [Add]->[Existing Item...].
В открывшемся окне создаем папку GUI. Здесь будет храниться проект GUI и код его элементов.
Далее нажимаем пока что [Отмена] и сворачиваем Visual Studio.
Создание пользовательского интерфейса
правитьОткрываем wxFormBuilder, будет создан проект по умолчанию. Дадим ему имя (name) gui и такое же значение свойству file.
Теперь сохраним проект в папку GUI, которую мы создали в Visual Studio. Она находится в Документы->Visual Studio 2015->Projects->wxHello->wxHello ([User Directory]\Documents\Visual Studio 2015\Projects\wxHello\wxHello). Дадим файлу проекта название gui (gui.fbp). Сохраняем.
В панели компонентов (Component Palette) выбираем вкладку Forms. На ней жмем иконку Frame. Будет создан фрейм (форма). Дадим ей имя frmMain
Теперь перейдем во вкладку Layout и нажмем на первую по счету иконку wxBoxSizer. Внутри проектируемой формы появится красная рамочка - это разместитель (sizer). Он будет управлять размещением вложенных в него компонентов на форме (друг над другом).
Далее перейдем на вкладку Common и нажмем на иконку Static Text. Внутри разместителя в верхнем левом углу формы появится новый объект wxStaticText "MyLabel". Изменим его свойство label на "Hello World!".
В разделе sizeritembase распахнем flags и поставим галочку у флага wxALIGN_CENTER. Теперь надпись будет в центре по горизонтали.
Далее в разделе wxWindow распахнем font и увеличим размер шрифта до 30 (или можете ввести свое значение). Надпись изменит свой размер.
Пока достаточно. Мы неплохо потрудились над дизайном. Попробуем сгенерировать C++ код GUI нашего приложения.
Откроем пункт меню [File]->[Generate Code].
Вроде бы ничего не произошло, но, уверяю вас, наш заветный код форм на C++ сформирован и лежит вместе с файлом проекта. Теперь нажмем [Tools]->[Generate Inherited Class].
Это формирует файлы отнаследованных классов, с которыми мы будем дальше работать. Обратите внимание, что эта процедура должна производиться только один раз! Иначе код который мы создадим в Visual Studio "затрется" заново сгенерированным.
"Но как же так? Как дальше работать с проектом если всё затирается новым кодом?" - наверняка спросите вы и будете абсолютно правы. Да, затирается, но нужно просто не генерировать в дальнейшем отнаследованные классы, а генеровать лишь код базовых (материнских) классов, при этом дочерние классы унаследуют весь дизайн базовых и наш код на С++, который "неимоверными усилиями" мы будем писать дальше никуда не пропадет.
Закончив с этим, не забудьте нажать [File]->[Save], чтобы сохранить проект. Всё, формбилдер можно закрыть.
Объединяем проекты
правитьТеперь давайте вернемся в Visual Studio.
Сделаем правый клик на нашей созданной с большой тщательностью и любовью папке GUI и вновь выберем в выскочившей менюшке [Add]->[Existing Item...]. (Если забыли как - ищите скриншот выше). Заходим в папку GUI в проекте на диске, выбираем файл gui.fbp и нажимаем [Add].
Теперь наш файл gui.fbp добавлен в проект VS. Попробуем его открыть. Делаем на нем правый клик и в выскочившем меню выбираем [Open With...].
В открывшемся окне жмем [Add] и добавляем наш любимый wxFormBuilder в качестве приложения для таких файлов. Выбираем его в предложенном списке (он будет последним). Нажмите [Set as default] чтобы он запускался автоматически.
Теперь закройте это окно с выбором приложения. Дважды кликните на gui.fbp. Должен открыться наш проект GUI в wxFormBuilder.
Далее аналогично добавлению в проект файла gui.fbp добавим все файлы с расширением .h в "Header Files", а с расширением .cpp в "Source Files". Результат должен выглядеть примерно так:
Создаем код приложения
правитьТеперь нам нужно создать файлы приложения. Создаем в Header Files файл HelloApp.h - постарайтесь сами разобраться, как это сделать. Добавляем в него следующий код (объявление класса нашего приложения):
#ifndef HELLOAPP_H #define HELLOAPP_H #include <wx/wx.h> class HelloApp : public wxApp { public: HelloApp(); virtual ~HelloApp(); virtual bool OnInit(); }; DECLARE_APP(HelloApp) #endif
Создаем в Source Files файл HelloApp.cpp , добавляем в него следующий код (определение класса нашего приложения):
#include "HelloApp.h" #include "gui/guifrmMain.h" IMPLEMENT_APP(HelloApp) HelloApp::HelloApp() { } HelloApp::~HelloApp() { } bool HelloApp::OnInit() { guifrmMain* frame = new guifrmMain((wxWindow*)NULL); frame->Show(); SetTopWindow(frame); return true; }
Подключение wxWidgets к проекту и сборка приложения
правитьТеперь нужно настроить компилятор, чтобы он видел заголовки библиотеки wxWidgets. Открываем пункт меню [Project]->[wxHello Properties...]. Выбираем в списке Configuraton: "All Configurations". Ищем внизу VC Directories и добавляем в Include Directories пути "C:\wxWidgets-3.1.2\include;" и "C:\wxWidgets-3.1.2\include\msvc;" (или где там у вас на диске лежит библиотека wxWidgets - нужно "плясать" от нее)
Если вернуться к проекту и попробовать его собрать [Build]->[Build Solution], то можно увидеть, что красные волнистые линии (ошибок в коде) пропали, но он всё еще не собирается из-за ошибки линкера:"Error LNK1104 cannot open file 'wxbase31ud.lib' ". Нужно добавить ссылку на каталог с файлами .lib
Снова открываем пункт меню [Project]->[wxHello Properties...]. На этот раз добавляем в Library Directories путь "C:\wxWidgets-3.1.2\lib\vc_lib;" (с возможной поправкой на ваш путь к библиотеке wxWidgets). Теперь снова запускаем [Build]->[Build Solution] и программа должна собраться: "Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped".
Финал
правитьЖмем кнопку с зеленым треугольником или нажимаем [F5] на клавиатуре и видим работающее приложение:
Всё, урок закончен. Надеюсь, вы удовлетворены проделанной работой.
Дополнение
правитьА давайте проверим, что будет если мы напишем какой-то код, а затем доработаем дизайн формы.
Откроем файл HelloApp.cpp и вставим в конструктор формы команду, которая изменит надпись на "Hello".
#include "guifrmMain.h" guifrmMain::guifrmMain( wxWindow* parent ) : frmMain( parent ) { m_staticText1->SetLabel(_("Hello")); }
Запускаем программу и видим:
Теперь дважды кликнем gui.fbp и будем редактировать интерфейс в wxFormBuilder. Для начала выберем в дереве проекта (Object Tree) разместитель bSizer1. Открываем панель Common добавим в наш разместитель кнопку (wxButton).
Выделим на форме нашу кнопку. Далее в верхней панели инструментов кликаем кнопки [Expand] и [Stretch]. Видим, что свойство prortion стало равно 1, а wxExpand пометилось галочкой. Добавленная нами кнопка при этом стала занимать всё доступное оставшееся место внутри разместителя.
Сделаем в нашей программе обработчик какого-нибудь события, например нажатия добавленной нами кнопки. Зайдем в её свойствах на вкладку Events и зададим свойство OnButtonClick равным MyButtonClick. Сгенерируем код формы и перейдем в Visual Studio.
Попробуем запустить программу, она при этом заново пересоберется.
Как мы видим, наш код в конструкторе формы (пишущий "Hello") продолжает работать, но появилась и кнопка, которую мы добавляли в разместитель. Нажмем на кнопку и убедимся, что пока ничего не происходит. Нужно создать код обработчика.
Закрываем наше чудо-приложение и вставляем в guifrmMain.h объявление обработчика MyButtonClick(). Теперь класс guifrmMain выглядит так:
class guifrmMain : public frmMain { public: /** Constructor */ guifrmMain( wxWindow* parent ); //// end generated class members void MyButtonClick(wxCommandEvent& event); };
Вставляем в guifrmMain.cpp определение обработчика MyButtonClick():
void guifrmMain::MyButtonClick(wxCommandEvent& event) { m_staticText1->SetLabel(_("Hello!")); }
Запускаем.
Теперь при нажатии на кнопку в конце надписи появляется восклицательный знак. Обработчик работает.
На этом всё.