вторник, 19 октября 2010 г.

Интеграция Silverlight в Qt приложения

Хотелось бы опубликовать статью на русском языке об интеграции роликов Silverlight в Qt приложения.
Для этого используется библиотека Qtitan, она коммерческая, увы, но может быть кого-то заинтересует. К тому же ее вполне можно использовать в демо-режиме в некоммерческих целях.
Статья публикуется с негласного соглашения авторов фреймворка Qtitan Multimedia.

Интеграция Silverlight в Qt приложения


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

Мы тоже любим Qt, и мы захотели расширить наш любимый фреймворк возможностью работы с современной векторной графикой, например, мы захотели интегрировать в приложение ролики Adobe Flash или Microsoft Silverlight.

среда, 13 октября 2010 г.

QScintilla: определяем styleText

Вот мы и добрались до самой важной функции лексера void styleText(int start, int end)

Займемся ее реализацией.

void LexerZ::styleText(int start, int end)
{
  //editor() - функция из родительского класса.
  //Возвращает указатель на QsciScintilla
  if (!editor())
   return;

  //получить исходник
  //выделим кусок памяти
  // +1 - под \0
  char * chars = new char[end - start + 1];
  //заполним кусок обратившись сцинтилле
  editor()->SendScintilla(QsciScintilla::SCI_GETTEXTRANGE,
              start, end, chars);
  //преобразуем в строку
  QString source(chars);
  delete [] chars;
 
  //Оптимизация - кэшируем уже ранее отрисованную строку
  if (source == cache)
   return;
  else
   cache = source;
  //Не работаем с пустой строкой
  if (source.isEmpty())
   return;
  //вызываем функцию отрисовки комментария
  //передаем исходную строку, начало и конец
  commentStyling(source, start, end);
}

* This source code was highlighted with Source Code Highlighter.


В комментариях описано, что мы делаем в этой функции. Здесь мы получаем строку, которую требуется отрисовать (это может быть не только текущая строка, а в том числе и соседние строки, сцинтилла в этом плане довольно умна).
Дальше вызываем функцию commentStyling(source, start, end);

Ее реализация приведена ниже:

понедельник, 11 октября 2010 г.

QScintilla: раскрашиваем комментарии

Сегодня мы будем раскрашивать комментарии для некого гипотетического языка Z.
Допустим в этом языке комментарии строк принято обозначать символом **, аналогично // в C++. Давайте предположим, что цвет шрифта комментария - синий, цвет фона - светло-зеленый, а сам шрифт - Comic Sans.
Начнем изменения в нашем коде Lexer.cpp и Lexer.h. (Можно переименовать эти файлы в LexerZ.h и LexerZ.cpp).

пятница, 8 октября 2010 г.

QScintilla: пишем Lexer

Перед дальнейшим написанием лексера нужно уяснить парадигму паттерна "Виртуальный метод", который использует QScintilla.
Лескер состоит из набора виртуальный функций, которые нужно переопределить. Класс QsciScintilla при необходимости вызывает виртуальные методы базового класса, однако в соответствии с полиморфизмом, будут вызываться методы нашего лексера.
Вот перечень виртуальных функций, необходимых для переопределения:
  //! Возвращает название языка
  virtual const char * language() const;
  //! Цвета для стилей
  virtual QColor defaultColor(int style) const;
  //! Шрифты для стилей
  virtual QFont defaultFont(int style) const;
  //! Бакгроунд для стилей
  virtual QColor defaultPaper(int style) const;
  //! Разбор текста на стили
  virtual void styleText (int start, int end);
  //! Описание
  virtual QString description (int style) const;

* This source code was highlighted with Source Code Highlighter.
Переменная style - это просто идентификатор стиля. Мы сами ее определяем. Для этого в лексере мы определяем некий enum для наших стилей.
  enum
  {
   Default = 0,
   Comment = 1,
   Binary  = 2,
   String  = 3,
   Keyword1 = 4,
   Keyword2 = 5,
   Keyword3 = 6,
   Keyword4 = 7,
   Const  = 8
  };

* This source code was highlighted with Source Code Highlighter.
Имена стилей и их числовые обозначения значения не имеют, далее станет ясно почему.
Самой важной виртуальной функцией является   virtual void styleText (int start, int end);

Именно она отвечает за отрисовку. К этой функции QScintilla обращается всякий раз, когда ей надо перерисовать кусок текста начиная с позиции start до позиции end.

четверг, 7 октября 2010 г.

QScintilla: создаем свой лексер

Как уже было сказано ранее, QScintilla поддерживает около 80 языков, раскрашивая каждый в соответствии с их синтаксисом. Т.е. для C++ комментарии задаются символом //, а для языка R символом #. Соответственно, раскрашивать в каждом случае надо по своему.

Трудно представить, что кроме этих 80 языков вам может понадобиться что-то свое, но тем не менее такая ситуация возникнуть может и надо знать как тут поступать.

Вообще, есть два способа добавить свой язык для раскраски.
Первый - это правка собственно исходного кода библиотеки qscintilla2.dll.
Достоинства этого метода - простота добавления. Достаточно взять за пример уже какой-нибудь существующий лексер, скопировать его в новый файл, исправить несколько строк, пересобрать библиотеку и, вуаля, новый лексер готов.
Недостаток этого метода очевиден - необходимость пересобирать библиотеку. Хотелось бы обойтись без этого.
Для этого в QScintilla есть путь истинного воина - наследование от QsciLexerCustom и самостоятельное написание алгоритмов раскраски. Это более сложный путь, на мой взгляд, но зато более правильный с концептуальной точки зрения, т.к. не нужно пересобирать библиотеку.

Итак, первое что мы должны сделать - это отнаследоваться от QsciLexerCustom:

#include <qsci/qscilexercustom.h>

class Lexer : public QsciLexerCustom
{
  Q_OBJECT
public:
  //! Конструктор
  Lexer(QObject * parent = 0);
  //! Деструктор
  virtual ~Lexer();
private:
  Lexer(const Lexer &);
  Lexer &operator=(const Lexer &);
};

* This source code was highlighted with Source Code Highlighter.
В следующих выпусках мы продолжим написание своего лексера.

QScintilla: создание редактора

Сейчас мы создадим экземпляр QScintilla и зададим ему некоторые свойства.
В качестве языка для подсветки будем использовать C++.

#include <Qsci/qsciscintilla.h>
#include <Qsci/QsciLexerCPP.h>

//Создаем редактор
QsciScintilla * textEdit = new QsciScintilla(this);

//Создаем и устанавливаем лексер для C++
QsciLexerCPP * lexCpp = new QsciLexerCPP(this);
textEdit->setLexer(lexCpp);

//Задаем формат ввода - без этого не будут вводиться русские буквы
textEdit->setUtf8(true);

//Текущая строка подсвечивается горизонтальной линией
textEdit->setCaretLineVisible(true);
//Цвет линии
textEdit->setCaretLineBackgroundColor(QColor("gainsboro"));

//Автоматический отступ
textEdit->setAutoIndent(true);
textEdit->setIndentationGuides(true);
//Заменять Tab на пробелы
textEdit->setIndentationsUseTabs(false);
//Ширина отступа - 4 пробела
textEdit->setIndentationWidth(4);

//Задаем символ конца строки
#if defined Q_WS_X11
textEdit->setEolMode(QsciScintilla::EolUnix);
#elif defined Q_WS_WIN
textEdit->setEolMode(QsciScintilla::EolWindows);
#elif defined Q_WS_MAC
textEdit->setEolMode(QsciScintilla::EolMac);
#endif

//Задаем цвет вертикальной полосы слева - там где ставятся breakpoints, закладки, номера строк
textEdit->setMarginsBackgroundColor(QColor("gainsboro"));
//Отображать номера строк
textEdit->setMarginLineNumbers(1, true);
//Ширина полосы - такая чтобы влезли символы до 1000
textEdit->setMarginWidth(1, QString("1000"));

//Автозавершение лексем
textEdit->setAutoCompletionSource(QsciScintilla::AcsAll);
textEdit->setAutoCompletionCaseSensitivity(true);
textEdit->setAutoCompletionReplaceWord(true);
textEdit->setAutoCompletionShowSingle(true);
textEdit->setAutoCompletionThreshold(2);

//Автоподсветка скобок
textEdit->setBraceMatching(QsciScintilla::SloppyBraceMatch);
//Цвет подсветки - желный с синим
textEdit->setMatchedBraceBackgroundColor(Qt::yellow);
textEdit->setUnmatchedBraceForegroundColor(Qt::blue);

//Слот на сигнал - "документ изменился"
connect(textEdit, SIGNAL(textChanged()),
 this, SLOT(documentWasModified()));
//Слот на сигнал - "курсор сместился"
connect(textEdit, SIGNAL(cursorPositionChanged(int, int)),
 this, SLOT(cursorMoved(int, int)));

* This source code was highlighted with Source Code Highlighter.
За дополнительной информацией по редактору можно обращаться к документации:
http://www.riverbankcomputing.co.uk/static/Docs/QScintilla2/classQsciScintilla.html

среда, 6 октября 2010 г.

QScintilla: собираем проект

Напишем pro файл для включения QScintilla в свой проект. Я не буду приводить весь файл, а укажу на что нужно обратить внимание.
  1. Конечно подключить библиотеку:
    unix:LIBS += -lqscintilla2
    win32:LIBS += qscintilla2.lib
  2. Определить переменные
    DEFINES += QSCINTILLA_DLL SCI_LEXER
    Здесь определены 2 переменные. Первая говорит, что мы используем экспорт из библиотеки qscintilla2. Вторая, что мы определяем свой лексер. Лексер - это объект, который отвечает за отрисовку текста. Соответственно, если в планах нет желания писать свой лексер (например, для какого-нибудь особо экзотического языка), то переменную SCI_LEXER определять не нужно.
Вот и все изменения в файле проекта.
В пределах видимости нужно расположить qscintilla2.dll и включить в INCLUDEPATH путь до заголовочных файлов QScintilla (например, QScintilla\Qt4\Qsci\).

После чего можно собирать проект.

QScintilla: установка

Живет QScintilla здесь:
http://www.riverbankcomputing.co.uk/software/qscintilla/intro
Периодически выходят обновления, на сегодняшний день последняя версия - 2.4.5.
QScintilla портирована как для Qt 3, так и для Qt 4. С третьей версией я не работаю и не знаю насколько там все хорошо, но для четверки все нормально, ничего допиливать не надо.

О лицензии.
RiverBank распространяет QScintilla под тремя лицензиями:
  • GNU General Public License v2
  • GNU General Public License v3
  • Riverbank Commercial License
К сожалению, GPL. GPL - несвободная лицензия с серьезным ограничением. Вы не сможете использовать QScintilla в коммерческих приложениях. Точнее вам придется тогда открыть весь исходный код вашего приложения. Вы также не сможете включать собранную библиотеку QScintilla в дистрибутив вашего приложения.
Но способ обойти ограничение есть.
Как обмануть GPL:
Например, можно на сайте сделать два линка: один на коммерческую программу , а второй — на GPL драйвер(библиотеку). Две независимые работы можно скачать по отдельности.
Вот такая неприятность.

Установка.
В сборке библиотеки нет ничего сложного - скачиваем, распаковываем, переходим в каталог QScintilla/Qt4 и запускаем qmake -tp vc. В итоге получаем проект qscintilla2.vcproj.
Собираем его.

Получаем в итоге qscintilla2.dll и qscintilla2.lib, которые будем использовать в программе.

В следующем выпуске начнем работу с Qscintilla.

QScintilla - продвинутый редактор для Qt

Открываю цикл статей о QScintilla. QScintilla это порт проекта Scintilla на Qt. Scintilla - это мощный кросплатформенный редактор текста.
В его возможности входит:
  • Подсветка исходного кода различных языков. Поддерживается 78 самых известных языков (Abaqus, Ada, APDL, Asm, Asn1, ASY, AU3, AVE, Baan, Bash, Basic, Bullant, Caml, CLW, Cmake, COBOL, Conf, CPP, Crontab, Csound, CSS, D, Eiffel, Erlang, EScript, Flagship, Forth, Fortran, GAP, Gen.py, Gui4Cli, Haskell, HTML, Inno, Kix, Lisp, Lout, Lua, Magik, Matlab, Metapost, MMIXAL, MPT, MSSQL, MySQL, Nimrod, Nsis, Opal, Others, Pascal, PB, Perl, PLM, POV, PowerPro, PowerShell, Progress, PS, Python, R, Rebol, Ruby, Scriptol, Smalltalk, SML, Sorcus, Specman, Spice, SQL, TACL, TADS3, TAL, TCL, TeX, VB, Verilog, VHDL, YAML)
  • Собственно редактирование кода и все, что с ним связано - отступы, cut/copy/paste, подсветка скобок и прочее. Возможностей - на полноценный текстовый редактор.
  • Есть возможность добавить собственный язык и задать для него собственную раскраску.
Среди русской части Интернета крайне мало информации о работе с QScintilla. В основном информацию приходилось собирать по форумам, вникать в документацию, которая, кстати без примеров.
В итоге я хочу в своем блоге выложить все, что мне известно о работе с QScintilla.