JUCE — Кроссплатформенный C++ фреймворк для разработки приложений с пользовательским интерфейсом

от автора

image

Приветствую хабросообщество!
Наверно каждый кто профессионально разрабатывает ПО или просто увлекается программированием, рано или поздно приходил к необходимости создавать пользовательский интерфейс для своей программы. И если не рассматривать нативные для платформ окружения и языки такие как C# для Windows или Objective-C для Mac OS X которые изначально содержат средства для визуализации интерфейса, то выбор оказывается не очень богатым, особенно если мы не горим желанием платить деньги за средства разработки GUI или желаем добиться кроссплатформенности.
В своем первом посте на Хабре я бы хотел рассказать о таком фремворке как JUCE. Поиск по Хабру выдал всего 2 статьи где данный фреймворк только упоминается, но ни какой детальной информации не приводится. Думаю что тем кто только начинает осваивать кроссплатформенные GUI приложения на C++ будет интересно узнать об альтернативе таким монстрам как Qt или таким старичкам как GTK+

Что такое JUCE

Официальный сайт разработчиков: juce.com.

JUCE (Jules’ Utility Class Extensions) это всеохватывающая библиотека классов С++ для разработки кроссплатформенного программного обеспечения.
Он содержит практически все что вам может понадобиться для создания большинства приложений, особенно хорошо подходит для построения сложных GUI, обработки графики и аудио.

Википедия:

Juce — это открытый кроссплатформенный инструментарий разработки ПО (фреймворк) для языка C++, используемый для разработки GUI приложений и плагинов.

JUCE поддерживает следующие платформы и возможности:

  • Mac OS X Приложения и VST/AudioUnit/RTAS/NPAPI плагины компилируются при помощи Xcode. (на 10.7.5 & Xcode 4.6.3 все работает без проблем)
  • Windows Приложения и VST/AudioUnit/RTAS/NPAPI/ActiveX плагины собираются при помощи MS Visual Studio. Результаты полностью совместимы с Windows XP, Vista и Win7/8
  • Linux Приложения и плагины могут быть собраны для любого ядра версии 2.6 и старше.
  • iOS Нативные iPhone и iPad приложения собираются при помощи Xcode
  • Android Android приложения собираются при помощи Ant или Eclipse с использованием Android NDK.

JUCE разрабатывался силами одного человека и из набора классов для личного использования перерос в полноценный фреймворк.
OpenSource лицензия появилась в 2003 году, а с 2005 фреймворк обзавелся платной ее версией для закрытого ПО.

Большинство модулей фреймворка имеют открытую лицензию GPLv2, v3 и AGPLv3, модуль Core имеет лицензию ISC

Если у вас нет желания публиковать исходный код своей программы, то вы можете приобрести коммерческую лицензию по следующим расценкам:

  • Лицензия на один продукт — 399 Английских Фунтов
  • Лицензия на неограниченное колличество продуктов — 699 Фунтов
  • Апгрейд с первой на вторую — 349 Фунтов
  • Апгрейд старых версий — до полной 349 Фунтов до лицензии на один продукт 199 Фунтов

Состав фреймворка и начало работы

Сам JUCE достаточно легковесный, чуть более 28 Мб. Папка docs содержит подробную документацию по установке и подключению фреймворка в различных ОС и средах разработки.
Касательно установки стоит заметить что JUCEпредставляет собой не набор библиотек в привычном смысле или набор исходников из которых вы должны собрать библиотеки для статической или динамической линковки, а набор заголовочных файлов и файлов исходного кода, содержащие все предоставляемые фреймворком классы. Данный подход не только упрощает миграцию с одной платформы на другую, избавляя вас от необходимости включать в состав дистрибутивов библиотеки фреймворка или требовать их наличия на компьютере пользователя, но и решает проблему разрядности библиотек от которых зависит фреймворк. Так как стандартные библиотеки или стандартное окружение современных ОС которое используется в проектах JUCE (все они описываются в документации поставляемой в комплекте с фреймворком) как правило собраны с поддержкой как 32 так и 64 bit. Так что вам стоит следить за битность только тех библиотек которые вы дополнительно используете в своем проекте.
Все модули фреймворка находятся в папке modules. Весь исходный код хорошо структурирован и комментирован, так что проблем с пониманием возникнуть не делжно.
В папке extras можно найти примеры использования фреймворка. Среди прочего там же вы найдете две утилиты, которые помогут вам в разработке. Для этих утилит, да и для всех примеров, уже есть готовые проекты для различных платформ и IDE, все что вам остается это открыть проект и скомпилировать пример или утилиту.
Первая утилита это Introjucer, достаточно аскетичная программа для автоматической генерации проектов, написана с использованием самого JUCE и является ярким примером возможностей фреймворка. В комплекте присутствует мастер по созданию проектов, мастер по созданию шаблонов исходно кода и очень весомое дополнение — визуальный редактор GUI, который просто генерирует на основе ваших манипуляций код на С++ в соответствующий файл исходного кода (который до того был создан при помощи мастера шаблонов), редактор кода, мастер локализации и ряд других достаточно полезных инструментов.

Немного картинок для наглядности

Конфигурация проекта

Редактор кода
image
Редактор GUI
image
Добавление sourcecode файлов
image

Приятной изюменкой в Introjucer является наличие собственного файла проекта, настроенного под все IDE и платформы которые поддерживаются фреймворком. Для переноса кода от разработчика не потребуется ни чего, кроме наличи на целевой системе утилиты Introjucer. Каждый проект сформированный утилитой можно открыть в целевой IDE которую вы используете для своей ОС.
image

Вторая утилита это binarybuilder, которая позволяет вам перенести бинарные файлы непосредственно в код ваших исходных файлов. На пример картинки и логотипы превратятся в набор бинарных данных которые вы можете использовать в своем коде. Эта утилита так же является частью Introjucer и используется там в менеджере ресурсов при редактировании GUI. Но может быть собрана как отдельное консольное приложение.
image

Hello World

И куда же без примера кода…
Рассмотрим подробнее пример поставляемый с фреймворком:
../extras/example projects:
В проектах JUCE все заголовочные файлы в конечном итоге вкладываются в один файл "../JuceLibraryCode/JuceHeader.h".
Так что разработчику не приходится подключать весь ворох классов из фреймворка вручную в каждом исходном файле.
В рассматриваемом примере присутствует два модуля программы:

  • Main.cpp который отвечает не посредственно за само наше приложение — старт, вывод окна на экран, завершение и т.д.
  • MainComponent.cpp(.h) который отвечает за наполнение нашего окна — кнопки, фон, поля для ввода текста и т.д.

Стоит заметить что в JUCE все содержимое GUI является классом, наследуемым от класса JUCE Component.
Рассмотрим наш MainComponent.h:

#ifndef __JUCE_HEADER_9002020A4DD09B20__ #define __JUCE_HEADER_9002020A4DD09B20__  //Подключаем наш фреймворк #include "../JuceLibraryCode/JuceHeader.h"  //И описываем наш класс class MainComponent  : public Component, //Наследуем от основного класса фреймворка                                              public ButtonListener //данный клас отвечает за прослушивание событий кнопок интерфейса 

Далее требуется описать поведение класса, его конструкторы и деструкторы.
В секции public находится следующий код:

MainComponent ();  ~MainComponent();      void paint (Graphics& g); //метод отвечающий за отрисовку в canvas     void resized(); //метод вызываемый при изменении размера     void buttonClicked (Button* buttonThatWasClicked); //метод вызываемый при нажатии на кнопку 

В секции private находятся непосредственно наши элементы интерфейса:

    ScopedPointer<Label> helloWorldLabel;     ScopedPointer<TextButton> quitButton;     Path internalPath1; 

Перейдем непосредственно к логике работы нашего GUI в MainComponent.cpp:

//Не забываем подключить заголовочный файл нашего класса #include "MainComponent.h"  //Добовляем логику для конструктора MainComponent::MainComponent () {     addAndMakeVisible (helloWorldLabel = new Label (String::empty,                                                     "Hello World!")); //Добавляем наш текстовый лэйбл, делаем его видимым и добавляем дополнительные параметры     helloWorldLabel->setFont (Font (40.00f, Font::bold));     helloWorldLabel->setJustificationType (Justification::centred);     helloWorldLabel->setEditable (false, false, false);     helloWorldLabel->setColour (Label::textColourId, Colours::black);     helloWorldLabel->setColour (TextEditor::textColourId, Colours::black);     helloWorldLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));      addAndMakeVisible (quitButton = new TextButton (String::empty)); //То же самое делаем с нашей кнопкой     quitButton->setButtonText ("Quit");     quitButton->addListener (this);      setSize (600, 300); //Задаем размер нашего содержимого  }  //Деструктор просто уничтожает содержимое нашего GUI  MainComponent::~MainComponent() {        helloWorldLabel = nullptr;     quitButton = nullptr;  }  //И описываем все методы нашего класса void MainComponent::paint (Graphics& g) {      g.fillAll (Colour (0xffc1d0ff));      g.setColour (Colours::white);     g.fillPath (internalPath1);     g.setColour (Colour (0xff6f6f6f));     g.strokePath (internalPath1, PathStrokeType (5.200f));  }  void MainComponent::resized() {     helloWorldLabel->setBounds (152, 80, 296, 48);     quitButton->setBounds (getWidth() - 176, getHeight() - 60, 120, 32);     internalPath1.clear();     internalPath1.startNewSubPath (136.0f, 80.0f);     internalPath1.quadraticTo (176.0f, 24.0f, 328.0f, 32.0f);     internalPath1.quadraticTo (472.0f, 40.0f, 472.0f, 104.0f);     internalPath1.quadraticTo (472.0f, 192.0f, 232.0f, 176.0f);     internalPath1.lineTo (184.0f, 216.0f);     internalPath1.lineTo (200.0f, 168.0f);     internalPath1.quadraticTo (96.0f, 136.0f, 136.0f, 80.0f);     internalPath1.closeSubPath();   }  void MainComponent::buttonClicked (Button* buttonThatWasClicked) {      if (buttonThatWasClicked == quitButton)     {          JUCEApplication::quit();      }  } 

На этом наш класс готов к тому что бы поселиться в окне приложения. Перейдем к Main.cpp и посмотрим каким образом инициализируется и запускается наш пример.

//Поключаем наш фреймворк и класс контента #include "../JuceLibraryCode/JuceHeader.h" #include "MainComponent.h"  //Описываем окно нашего приложения class HelloWorldWindow  : public DocumentWindow { public:  HelloWorldWindow(): DocumentWindow ("JUCE Hello World!",                           Colours::lightgrey,                           DocumentWindow::allButtons,                           true) {         // Заполняем окно нашим содержимым         setContentOwned (new MainComponent(), true);          // Задаем положение по центру         centreWithSize (getWidth(), getHeight());          // И отображаем его         setVisible (true);     }  ~HelloWorldWindow()     {         // Описываем деструктор если он нам нужен     }  void closeButtonPressed()     {                  // Описываем реакцию на нажатие кнопки закрытия         JUCEApplication::quit();     } }; 

Окно мы описали, теперь очередь за самим приложением:

class JUCEHelloWorldApplication : public JUCEApplication //Наследуем от основного класса приложения JUCE { public:     JUCEHelloWorldApplication() {}      void initialise (const String& commandLine)     {         // Инициализируем приложение создавая наше окно         helloWorldWindow = new HelloWorldWindow();     }      void shutdown()     {                  // Описываем поведение при закрытии приложения         helloWorldWindow = nullptr;     }     //Далее задаются методы для получения некоторой информации о приложении     const String getApplicationName()     {         return "Hello World for JUCE";     }      const String getApplicationVersion()     {         //  ProjectInfo::versionString автоматически обновляется Jucer, и         // описывается в JuceHeader.h который генерируется для нашего проекта         return ProjectInfo::versionString;     }      bool moreThanOneInstanceAllowed() //Разрешаем запуск нескольких версий     {         return true;     }      void anotherInstanceStarted (const String& commandLine)     {     }  private:     ScopedPointer<HelloWorldWindow> helloWorldWindow; //свойства класса нашего приложения, по сути все окна которые в нем содержаться  // Этот макрос создает точку входа main() нашего приложения. START_JUCE_APPLICATION (JUCEHelloWorldApplication) 

Все готово, если наш проект собрать и запустить то мы получаем вот такой результат:
image

Если вы желаете посмотреть на что еще способен JUCE рекомендую собрать и запустить приложение Demo из папки extras, в котором показаны основные возможности данного фреймворка, но не забывайте что их гораздо больше и все зависит от того как вы примените то что имеете.

Полезные ссылки

Послесловие

Надеюсь кому то мой экспромт окажется полезным.
Мое личное мнение таково: данный фреймворк заслуживает внимания и того, что бы использоваться в малых и больших проектах.
С удовольствием приму любую критику и замечания, спасибо что обратили внимание на данный пост!

ссылка на оригинал статьи http://habrahabr.ru/post/209956/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *