Главная » C++, C++ Builder » Понятие о списках, прорисовываемых владельцем C++ Builder

0

Списки, прорисовываемые приложением, в котором они созданы, называются owner-draw (прорисовываемые владельцем) (это также относится к спискам внутри компонентов). Называются они так потому, что код для их прорисовки предоставляет их владелец (форма). Существует два вида owner-draw списков. Первый из них называется фиксированным  owner-draw  списком.  В таком списке все элементы фиксированной (одинаковой) высоты. Почти все списки, которые вы найдете в вашем приложении, будут именно фиксированными.

Второй вид owner-draw списков — переменные. Этот вид списка позволяет каждой строке, другими словами каждому элементу списка иметь переменную высоту. Пример, который мы реализуем, будет относится именно к такому, переменному виду. Как вы увидите в примере, иметь переменный размер не означает, что элементы не могут иметь одинаковую высоту, просто есть возможность делать элементы разными. В нашем случае мы собираемся сделать список переменным, чтобы продемонстрировать, как вы можете устанавливать  размер  строк  в  списке. Хотя мы и будем использовать одну и ту же высоту для всех элементов, зависящую от шрифта списка, пример будет очень легко приспособить  для  использования  многих  шрифтов  для различных элементов, у каждого из которых будет своя высота.

Для реализации owner-draw списка вам нужно понимать кое-что о сообщения Windows, которые посылаются за кулисами деятельности списка. При создании такого списка два сообщения Windows имеют первостепенную роль. К счастью, VCL обрабатывает эти сообщения в события, так что вы можете работать через стандартную обработку событий. Нет необходимости возиться с элементами карты сообщений при работе с owner-draw списками в CBuilder.

Первое  сообщение,  которое  следует  обработать  для  вашего  списка  —  WM_MEASUREITEM,

транслируемое событием MeasureItem, которое используется Windows для определения высоты каждого элемента списка. Когда Windows нужно прорисовать элемент в списке, вызывается событие MeasureItem при первой прорисовке. Высота — возвращаемый обработчиком события параметр, который список Windows использует для отведения достаточного места по вертикали для прорисовки элемента.

Второе сообщение, которое нужно обрабатывать — WM_DRAWITEM. Это сообщение, которое транслируется в событие DrawItem, нужно Windows для самой прорисовки каждого элемента в списке. Когда Windows определяет, что элемент должен быть перерисован на поверхности списка, то для этого элемента вызывается обработчик события DrawItem. Обработчик будет вызываться неоднократно, при каждой перерисовке элемента. В отличие от  других  систем,  VCL  большую часть owner-draw списка рисует сама,  так что вам достаточно реализовать части, уникальные в вашей форме приложения.

Эти два сообщения — единственные, о которых надо позаботиться при создании owner-draw списков. Задача в их грамотном использовании. Хотя это и не слишком трудная проблема, обычно проще, чтобы вам кто-то показал, как это делается, а потом вы бы копировали этот код в другие приложения. Такое отношение очень важно в CBuilder, и мы его будем использовать где только можно. Не изобретайте колесо, если кто-то уже сделал работу за вас. Вы увидите, что хотя вы и вольны творить что угодно, но все получается быстрее и проще, когда вы основываетесь на уже написанных, протестированных компонентах в системе, чем когда вы большую часть работы делаете сами.

Реализация примера

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

Замечание

Исходный  код  для  программы  «Ручная  прорисовка  списков»  находится  на  сопроводительном компакт-диске в каталоге Chapter4\OwnerDrawList.

Форма,  с  которой  мы  будем  работать  в  этом  приложении,  приведена  на  рис.  4.10.  Создайте

простую форму и положите на нее список (list box), более-менее отцентрировав его на форме. Кроме списка, мы будет работать с FontDialog (диалог установки шрифта) и ColorDialog (диалог установки цвета), а также с главным меню. Добавьте все эти компоненты на форму в любом месте. Не забудьте поставить стиль списка в Owner-Draw Variable (переменной высоты с ручной прорисовкой), иначе код, который мы напишем в этом примере, не будет  правильно  работать. Если вы напишите весь этот код и в списке ничего правильного не окажется (только текст), то проверьте значение этого свойства у списка.

Рис. 4.10. Форма примера ручной прорисовки списка Модификация заголовочного файла

В заголовочный файл (Unit1.h) нашего приложения нужно внести несколько изменений перед тем, как продолжить работу над примером. Эти изменения приведены в следующем листинге. Изменения, которые вам нужно сделать, выделены подсветкой:

//——————————————————–

#ifndef Unit1H

#define Unit1H

//——————————————————–

#include <vcl\Classes.hpp>

#include <vcl\Controls.hpp>

#include <vcl\StdCtrls.hpp>

#include <vcl\Forms.hpp>

#include <vcl\Dialogs.hpp>

#include <vcl\Menus.hpp>

//——————————————————–

class TForm1 : public TForm

{

__published:  // IDE-managed Components TListBox *ListBox1;

TFontDialog *FontDialog1;

TColorDialog  *ColorDialog1; TMainMenu *MainMenu1; TMenuItem *Display1; TMenuItem *ChangeFont1; TMenuItem *ChangeColor1;

private: // User declarations Tfont *FpFont;

TCOlor *FcColor; Graphics::TBitmap  *Fbmp1; Graphics::TBitmap  *Fbmp2; public:   // User declarations

virtual

fastcall TForm1(TComponent* Owner);

virtual     fastcall ~TForm1(void); void SetListBoxItems(void);

};

//———————————————————

extern TForm1 *Form1;

//———————————————————

#endif

В этом примере мы используем парочку вещей, которых раньше мы не использовали. Во-первых, указатель на объект TFont будет использован для сохранения шрифта, который мы будем применять к элементам списка. Этот объект является наследием HFONT  Windows  и  содержит много методов для работы с изображением текста. К счастью, нам не нужно много методов для работы со шрифтами, так как в системе CBuilder со шрифтами легко иметь дело. Объект font будет использован для получения текущего шрифта из окна диалога выбора шрифта и для установки текущего шрифта в отображаемой области списка.

Класс TFontDialog в CBuilder позволяет пользователю выбирать все атрибуты шрифта. Пользователь может выбирать имена шрифтов, размеры, атрибуты (жирный, курсив, …) для текста и даже посмотреть пример отображения текста выбранным шрифтом. Лучшая сторона шрифтового диалога в том, что вам ничего не нужно с ним делать. Только  отобразить  окно диалога, позволить пользователю выбрать в нем шрифт и его атрибуты, а потом получить новый объект TFont из диалога, когда тот закроется. Это огромное улучшение по сравнению с более ранними системами, в которых требовалось не только изобразить окно диалога, но  также  и собрать шрифт из частей, выбранных в окне диалога.

Объект TColor — очень  простой объект (на самом деле это просто число), который содержит определения цвета в Windows. Цвета в Windows делятся на две дискретные категории: реальные цвета и относительные цвета. Реальные цвета, представленные через значения RGB (Red, Green, Blue: красный, зеленый, синий), часто используются для прямого задания цвета для изображения. В системе CBuilder вам не обязательно напрямую связываться с RGB-значениями, так как CBuilder предоставляет для этого случая константы, как например clRed (красный) или clBlue (синий).

Относительные цвета устанавливаются как ссылка на объекты в системе. Например, вы можете захотеть установить фоновый цвет формы таким же, как и цвет кнопки, используемый в текущий момент в системе. В CBuilder много констант такого типа, например clBtnFace. Преимущество использования таких цветов в том, что ваша программа будет выглядеть также, как и все остальные программы в системе. Если у пользователя настроена какая-нибудь загадочная цветовая схема, так как он с трудом воспринимает красно-зеленую гамму, то  вы  окажете  ему плохую услугу, используя красный и зеленый цвета повсеместно  в вашей программе. Хотя такие проблемы редки, все же это серьезное замечание, когда вы пишите программы, используемые вне вашей компании. Программа никогда не должна делать предположений об используемой цветовой

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

Класс TColorDialog в CBuilder предоставляет средства для того, чтобы пользователь мог менять цвета. Построенный на стандартном диалоге Windows 95/NT Color Dialog, он позволяет или выбрать один из предопределенных цветов, или определить какой-либо новый. Вам не нужно волноваться на эту тему. Вы просто отображаете окно диалога, позволяя пользователю выбрать подходящий цвет, а затем используете значение цвета, выбранное пользователем.  Каждый  раз, когда вы решаете использовать нестандартный цвет в вашем приложении, подумайте, стоит ли разрешать его изменять. Это существенно для таких вещей, как прорисованный вручную список, который изображает текст элемента выбранным цветом.

Мы добавили все, что нужно; пора время начинать писать код для формы. Давайте начнем с конструктора формы. Вот код, который нужно добавить в конструктор:

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

FcColor = clBlack; FpFont = NULL;

// Создаем растровые изображения Fbmp1 = new Graphics::TBitmap; Fbmp1->LoadFromFile(

"d:\\Cbuilder\\Cbuilder\\images\\icons\\earth16.bmp"); Fbmp2 = new Graphics::TBitmap;

Fbmp2->LoadFromFile( "d:\\Cbuilder\\Cbuilder\\images\\icons\\ship16.bmp");

}

В первую очередь код присваивает свойствам списка шрифт и цвет некоторые значения по умолчанию. Мы будем использовать объект FcColor для хранения цвета для отображения текста, FpFont — для шрифта. По умолчанию мы берем черный цвет для текста. Шрифт будет установлен в NULL, что будет означать в нашей программе, что пользователь не выбрал никакого шрифта. Как и все нормальные компоненты, область прорисовки (canvas) списка имеет значение  для шрифта по умолчанию и будет его использовать, если мы не зададим шрифт во время работы программы.

Источник: Теллес М. – Borland C++ Builder. Библиотека программиста – 1998

По теме:

  • Комментарии