Delphi XE2 и VCL Styles.

Vlad

Продолжаем пусть и медленно, но верно рассматривать новинки, которые нам преподнесла новая версия RAD Studio - XE2. И сегодня мы рассмотрим ещё одно нововведение - VCL Styles, с помощью которого можно организовать в своей программе поддержку скинов. До выхода Delphi XE2 мы модгли использовать стили оформления двумя способами: либо писать свой движок для поддержки скинов (долго, затратно), либо воспользоваться уже готовыми компонентами и библиотеками, например библиотекой AlphaControls и поддержку скинов без особых затрат времени. С выходом Delphi XE2 потребность в сторонних компонентах может отпасть сама собой. Сейчас я не буду говорить, что-то типа  "VCL Styles обанкротит разработчиков AlphaControls" и т.д. - тут время все расставит по своим местам и, думаю, что места под Солнцем хватит всем. Сегодня я просто рассмотрю максимально те возможности для работы со скинами в Delphi, которые мы можем использовать после начала работы с Delphi XE2.
Включаем поддержку стилей в проекте Delphi

Для включения поддержки стилей в вашем проекте Delphi необходимо зайти в настройки проекта:

Project -> Options -> Application -> Apperance

И выбрать те стили, которые вы хотите использовать для работы:

 
Для каждого выбранного стиля можно выполнить предварительный просмотр. Для этого необходимо выбрать стиль в списке и нажать "Preview...":
 
 
 

После того, как выбраны необходимые стили их можно будет использовать в программе, а также выбрать стиль, который будет использоваться в программе по умолчанию. Здесь сразу может возникнуть вопрос у читателей, которые дорожат размером своих программ: на сколько возрастет размер EXE-файла при включении стилей?

Давайте проверим. Создаем пустой проект Delphi, в Project Manager выбираем Build Configuration -> Release и собираем проект.

В итоге получаем размер EXE-файла равный 1 596 416 байт.

Теперь заходим настройки, включаем все стили и снова собираем проект.

Со всеми включенными стилями (13 штук) получаем размер EXE-файла равный 2 602 496 байт.

То есть получили прирост размера примерно на 40%. Много? Может быть, но можно пойти и другим путем и использовать стили без изменения размера EXE-файла. Для этого нам необходимо немного разобраться с тем как подгружаются стили в Delphi XE2 и изучить работу класса TStyleManager.
Класс TStyleManager

Класс TStyleManager располагается в модуле Vcl.Themes и является sealed-классом ("запечатанным"), т.е это означает,  что вы не сможете создать наследника от этого класса и код вида:

type
  TMyManager = class(TStyleManager)
  private
  public
  end;

При компиляции вызовет исключение: "[DCC Error] ...: E2353 Cannot extend sealed class 'TStyleManager'". Но, для работы со стилями и запечатанного класса будет вполне достаточно. Класс TStyleManager содержит ряд классовых свойств и методов, с помощью которых можно управлять стилями в вашем приложении. Рассмотрим основные возможности класса, которые пригодятся нам в будущем для работы.

Методы класса TStyleManager

class function IsValidStyle(const FileName: string): Boolean; overload;
class function IsValidStyle(const FileName: string; var StyleInfo: TStyleInfo): Boolean; overload;

Метод возвращает True в случае, если указанный в параметре FileName файл является файлом стилей. При этом перегруженный метод IsValidStyle может возвращать во втором параметре информацию по стилю, которая представляет собой запись вида:

TStyleInfo = record
    Name: string;//название стиля
    Author: string; //автор
    AuthorEMail: string; //email
    AuthorURL: string; //адрес сайта
    Version: string; //версия стиля
  end;

После того, как файл проверен его можно загрузить в менеджер. Для этого используется метод:
class function LoadFromFile(const FileName: string): TStyleServicesHandle;

Метод LoadFromFile стиль из файла и регистрирует его в менеджере.

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

class function LoadFromResource(Instance: HINST; const ResourceName: string): TStyleServicesHandle; overload;
class function LoadFromResource(Instance: HINST; const ResourceName: string; ResourceType: PChar): TStyleServicesHandle; overload;
class function TryLoadFromResource(Instance: HINST; const ResourceName: string; ResourceType: PChar; var Handle: TStyleServicesHandle): Boolean;

Последний метод вернет True, если стиль будет успешно загружен из ресурсов.

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

  class function TrySetStyle(const Name: string; ShowErrorDialog: Boolean = True): Boolean;
  class procedure SetStyle(Style: TCustomStyleServices); overload;
  class procedure SetStyle(Handle: TStyleServicesHandle); overload;

Метод TrySetStyle пробует установить в приложении стиль с именем Name и, если стиль успешно применен, то метод возвращает True. Второй параметр метода (ShowErrorDialog) указывает выводить ли сообщение об ошибке в том, случае, если применение стиля провалилось.
 Чтобы узнать какой стиль в настоящий момент используется, какие стили доступны и т.д. необходимо воспользоваться свойствами класса.

Свойства класса TStyleManager


class property ActiveStyle: TCustomStyleServices read GetActiveStyle;

Свойство возвращает используемый в настоящее время стиль оформления.
class property Enabled: Boolean read GetEnabled;

Возвращает True, если в приложении включена поддержка стилей оформления.
class property IsCustomStyleActive: Boolean read GetIsCustomStyleActive;

Возвращает True в случае, если используется стиль отличный от дефолтного (т.е. НЕ стиль Windows)
class property Style[const Name: string]: TCustomStyleServices read GetStyle;

Возвращает объект стиля по его имени.
class property StyleNames: TArray read GetStyleNames;

Возвращает массив названий зарегистрированных стилей.
class property SystemStyle: TCustomStyleServices read GetSystemStyle;

Возвращает системный стиль, т.е. стиль Windows.

Есть и другие методы и свойства класса TStyleManager, которые тоже могу оказаться полезными при работе со стилями VCL, но их мы сегодня рассматривать не будем, а перейдем к практической части статьи и напишем небольшое приложение по работе со стилями в ваших приложениях.
Использование стилей в своих приложениях

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

Создаем новый проект, заходим в опции и включаем все стили, как это было показано в начале статьи. Теперь перечислим все стили и выпишем их название, например, в ComboBox. Для этого нам пригодится свойство TStyleManager.StyleNames:

procedure TForm5.FormCreate(Sender: TObject);
var  i: integer;
begin
  for i := 0 to Length(TStyleManager.StyleNames)-1 do
    cbRegistredStyles.Items.Add(TStyleManager.StyleNames[i]);
  cbRegistredStyles.ItemIndex:=0;
end;

Так как для приложения в любом случае будет зарегистрирован минимум один стиль (Windows), то в конце метода я выбрал самый первый стиль из списка. Теперь сделаем следующее: при выборе очередного стиля попробуем применить этот стиль в приложении:

procedure TForm5.cbRegistredStylesChange(Sender: TObject);
begin
  TStyleManager.TrySetStyle(cbRegistredStyles.Items[cbRegistredStyles.ItemIndex],
                            false);
end;

Вот, собственно, самый простой способ использования стилей в своем приложении. Но, как я уже сказал ранее, такой подход увеличит размер Вашего проекта примерно на 40%. Теперь воспользуемся другим способом - загрузкой стиля из файла. Будем делать следующее: при выборе файла со стилем будем проверять его на валидность и выводить по нему всю имеющуюся информацию, после чего будем заносить имя стиля в наш ComboBox и применять его при выборе в списке.

Прежде всего заходим опять в настройки проекта и отключаем все выбранные ранее стили, чтобы при не нарваться на исключения типа "Такой стиль уже зарегистрирован". Можно было бы проверять уникальность имени, используя, всё то же свойство StyleNames, но не будем повторяться - для примера можно просто обезопасить себя выключением стилей в настройках проекта.

Добавляем на форму следующие компоненты:

  • TButtonedEdit
  • TOpenDialog
  • и несколько меток TLabel для вывода информации по стилю.

У меня получилась следующая форма:

 

Где взять файлы со стилями VCL? Все имеющиеся в Delphi XE2 стили располагаются в директории:

c:\Program Files\Embarcadero\RAD Studio\9.0\Redist\styles\vcl\...

и имеют расширение *.vsf. Так что для примера можно воспользоваться этими файлами. Пишем обработчик на открытие файла со стилем:

procedure TForm5.ButtonedEdit1RightButtonClick(Sender: TObject);
var si: TStyleInfo;
begin
  if OpenDialog1.Execute then
    if TStyleManager.IsValidStyle(OpenDialog1.FileName,si) then
      begin
        ButtonedEdit1.Text:=OpenDialog1.FileName;
        {выводим информацию}
        label8.Caption:=si.Name;
        label9.Caption:=si.Author;
        label10.Caption:=si.AuthorEMail;
        label11.Caption:=si.AuthorURL;
        label12.Caption:=si.Version;
        {грузим стиль}
        if TStyleManager.Style[si.Name]=nil then
          begin
            TStyleManager.LoadFromFile(OpenDialog1.FileName);
          {заносим имя стиля в список}
            cbRegistredStyles.Items.Add(si.Name);
          end;
      end
    else
      ShowMessage('Этот файл не содержит стилей оформления');
end;

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

 В принципе, используя модуль IOUtils.pas, о котором я рассказывал в нескольких статьях блога webdelphi.ru, можно без каких-либо проблем организовать сканирование определенной директории с целью поиска файлов со стилями. Например, поиск необходимых файлов можно осуществить так:

uses ..., IOUtils;
[...]
var FileArray:TStringDynArray;
begin
  {ищем все файлы с расширением vsf}
  FileArray:=TDirectory.GetFiles(Dir,'*.vsf');
  {проверяем, является ли файл файлом стиля и заносим его в список}
  for I := 0 to Length(FileArray)-1 do
     if TStyleManager.IsValidStyle(FileArray[i])then
        FFiles.Add(FileArray[i]);
end;

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

 Перейдем к следующим двум вопросам: Где взять файлы с готовыми стилями? и Как создать свой уникальный стиль?

Редактирование стилей. Создание собственных стилей для приложений, использующих VCL.

В отличие от стилей для Ribbon Controls, VCL Styles имеют свой достаточно удобный редактор, позволяющий как редактировать существующий, так и создавать собственный уникальный стиль.  Редактор стилей находится в главном меню:

Tools -> VCL Style Designer

 
Посмотрим, что представляем из себя редактор стиля. После открытия редакторы вы увидите такое окно:
 
 

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

Рассмотрим небольшой пример того как можно быстро изменить существующий VCL-стиль. Для этого нам потребуется минимум средств, а именно - любая программа для редактирования изображений, например, Paint.NET. Распишу весь процесс по шагам. Итак:

1. Заходим в главное меню редактора "Image - Export".  С помощью этого действия мы можем экспортировать изображение, использующееся для отрисовки стиля в отдельный png-файл. Задаем в открывшемся окне расположение файла и жмем "Export":

 
Файл с изображение будет иметь название style.png и выглядеть следующим образом:
 
 

Как и при работе со стилями в Ribbon Controls в этом изображении содержатся все необходимые элементы для прорисовки форм и компонентов в приложении с VCL. Например, два элемента в верхнем левом углу изображения отвечают за отрисовку активной и неактивной формы.

2. Загружаем файл style.png в Paint.NET и проводим цветовую коррекцию:

 
Ещё одну коррекцию:
 
3. Сохраняем полученный файл. И импортируем его обратно в редактор. Для этого в редакторе выбираем "Image -> Update"
 
 

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

Теперь жмем "Ok" и обновляем изображение стиля.

4. Теперь в редакторе нажимаем F9 и смотрим, что получилось.

 

Если после обновления изображения стиль остался прежним, то необходимо в главном меню редактора выбрать "Style -> Assign Colors" и снова нажать F9.

Как видите, всего 4 шага нам потребовалось, чтобы сделать самое простейшее редактирование стиля. Конечно, таким образом можно насоздавать хоть миллион стилей различных оттенков цвета от чёрных до гламурно-розовых, но это мелочь - коррекция цвета в итоге не приводит к созданию какого-либо принципиально нового стиля. А создать уникальный стиль можно. Для этого необходимо разобраться с тем как работают различные свойства объектов, т.е. обратить свой взгляд на правый список в окне редактора.
Работа со свойствами объектов в редакторе стилей

 Чтобы рассмотреть все свойства объектов в редакторе стилей, думаю, придётся создать отдельный блог =) Да это, собственно и не нужно. Рассмотрим работу со свойствами на примере отрисовки формы (TForm). Сейчас у меня под рукой файл с изображением стиля содержащий вот такой элемент отрисовки формы:

 
Как видите, здесь уже используются какие-то собственные элементы изображения (огонь) и просто так взять и обновить картинку стиля у нас не получится. Покажу на примере как будет выглядеть форма, если просто обновить изображение:
 
 

Видите? Огонь растянулся по всему заголовку формы. А если изменять размер формы, то появятся пиксели размером с кулак, в общем получится что-то с чем-то, но не стиль. Вот здесь-то нам и пригодятся свойства объекта.

Находим в дереве объектов "Objects -> Form -> Image -> Title" :

 

Теперь первое, что нам необходимо сделать - это отменить растягивание изображения заголовка и вместо этого использовать эффект "замостить".

Для этого устанавливаем значения следующих свойств:
BorderTitleStyle = tsTile
TitleStyle = tsTile
Заголовок формы примет следующий вид:

 
 
Теперь сделаем так, чтобы между огнями были небольшие расстояния. Редактируем свойства
MarginLeft = 22
MarginRight = 5
 В итоге заголовок формы станет таким:
 
 
Вот заголовок формы уже приобретает более менее "товарный" вид. Осталось только назначить цвет шрифта, чтобы заголовок формы не сливался с основным цветом. Для этого в дереве объектов ищем раздел Fonts и меняем свойства у объектов CaptionTextNormal и CaptionTextInactive:
 
 
Теперь заголовок нашей формы стал полностью уникальным - свой рисунок. свой шрифт.
И в заключении рассмотрения этого вопроса остается только добавить, что для создания стилей "с нуля" Вы кроме уже готовой заготовки шаблона, можете также использовать и свое изображение и указать свои расположения каждого элемента приложения. Определить положение того или иного изображения для компонента Вы можете следующим образом (на примере всё того же заголовка формы):
1. Выбираем объект стиля
2. Ищем в инспекторе свойств свойство Bitmap и жмем кнопку редактирования
3. Откроется окно выбора битмапа для объекта:
 
 
4. Кликом левой кнопкой мыши по изображению указываем верхний левый угол битмапа для объекта.
6. Кликом правой кнопки мыши по изображению указываем нижний правый угол битмапа
7. Жмем "Apply"
После этого для объекта будет использоваться битмап с указанным расположением. Подобная функция редактора может потребоваться вам, чтобы создать стиль с уникальным расположением элементов на изображении.
Как видите, VCL Styles дает довольно большие возможности разработчикам в плане создания уникальных стилей для своих приложений. В этой статье я показал лишь несколько возможностей работы со стилями в Delphi XE2. На деле же, если вы задумаете создать свой уникальный стиль для приложения вы узнаете на порядок больше разного рода свойств, возможностей, вариантов работы.
Представленный в качестве примера стиль (с огонем) я не выкладываю (пока), т.к. ещё полностью его не протестировал на предмет артефактов, проблем отрисовки и т.д., но, думаю, что в скором времени Вы сможете скачать его со страницы с исходниками (которая, кстати, обновилась).

Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=27283