Delphi

Создание градиентной заливки

Полностью расписанный и объяснённый исходник градиентной заливки формы. Оригинальный исходник написал Y0da

Вы, наверное, замечали, что в инсталляторах заливка формы не одноцветна, а плавно переходит от одного цвета к другому. Это выглядит довольно красиво. Почему бы не встроить в свою программу подобный переход? Но только переход от синего к чёрному устарел. Почему бы не залить свою форму другими цветами? Ниже приведён код, реализующий всё это. Его надо просто дописать в свой проект. Вызов процедуры GradientForm должен быть помещён в событие формы OnPaint.

procedure TForm1.GradientForm (frm: TForm; startcolor, endcolor: TColor); 
// Горизонтальная градиентная заливка формы 
var 
startr : integer; // Стартовое количество красного цвета 
startg : integer; // Стартовое количество зелёного цвета 
startb : integer; // Стартовое количество синего цвета 
endr : integer; // Конечное количество красного цвета 
endg : integer; // Конечное количество зелёного цвета 
endb : integer; // Конечное количество синего цвета 
curr : integer; // Текущее количество красного цвета 
curg : integer; // Текущее количество зелёного цвета 
curb : integer; // Текущее количество синего цвета 
i : integer; 
r : TRect; // Прямоугольник, который будет заполняться различными цветами 
nolines: byte; // количество прямоугольников 
curpct : integer; // Текущий процент изменения окраски 
bitspix: longint; // биты в пикселе 
begin 
// конвертирует TColor в RGB 
startr := GetRValue(startcolor); 
startg := GetGValue(startcolor); 
startb := GetBValue(startcolor); 
endr := GetRValue(endcolor); 
endg := GetGValue(endcolor); 
endb := GetBValue(endcolor); 

// Считает количество прямоугольников (линий) с различными цветами 
if frm.Height < 250 then 
nolines:=frm.Height 
else 
nolines:=250; // Максимум 250 прямоугольников (больше не нужно) 
// Получает количество битов в пикселе
bitspix:=GetDeviceCaps(frm.Canvas.Handle, BITSPIXEL);
if (bitspix = 8) and (nolines > 50) then // 256 цветов 
nolines:=50 
else if bitspix < 8 then // Меньше чем 256 цветов 
nolines:=4; // бедный парень! Это EGA монитор должен быть… 

r.Left:=0; // Left прямоугольника 
r.Right:=frm.Width; // Right прямоугольника 

for i:=0 to nolines do // Рисует градиент 
begin 

curpct:= (i * 100) div nolines; // % изменения (градиент) 

// Вычисляет количество красного для текущего прямоугольника 
if startr > endr then 
curr := startr - (curpct * (startr-endr) div 100) 
else 
curr := startr + (curpct * (endr-startr) div 100); 

// Вычисляет количество зелёного для текущего прямоугольника 
if startg > endg then 
curg := startg - (curpct * (startg-endg) div 100) 
else 
curg := startg + (curpct * (endg-startg) div 100); 

// Вычисляет количество синего для текущего прямоугольника 
if startb > endb then 
curb := startb - (curpct * (startb-endb) div 100) 
else 
curb := startb + (curpct * (endb-startb) div 100); 

// Устанавливает RGB цвет для текущего прямоугольника 
frm.Canvas.Brush.Color:=RGB(curr, curg, curb); 

// Высчитывает вершину и нижнюю точку прямоугольника (top и bottom) 
r.Top:=i + (i*(frm.Height div nolines)); 
r.Bottom:=r.Top + (frm.Height div nolines)+1; 

// Рисует прямоугольник на холсте (на canvas) 
frm.Canvas.FillRect(r); 
end; // Конец цикла for 
end; // Конец процедуры GradientForm 



procedure TForm1.FormPaint(Sender: TObject); 
begin 
// от светло-синего к чёрному - как в инсталляторах 
GradientForm(Form1,RGB(60,60,210), RGB(1,1,2)); 
// Вместо RGB(60,60,210) и RGB(1,1,2) можно использовать свои цвета,
// включая цветовые константы Delphi типа clWhite, clBlack и т.д. 
end; 

Теперь рассмотрим пошагово, что здесь происходило.

Начнём с самого начала:

procedure TForm1.GradientForm (frm: TForm; startcolor, endcolor: TColor);

Что передаётся в эту процедуру? Всё очень легко. Frm – та форма, которую нужно градиентно залить. StartColor и EndColor – цвета, которыми будет начинаться и кончаться заливка соответственно. Здесь ничего менять не надо – это просто заголовок.

Переменные откомментированы достаточно хорошо, так что переходим дальше.

Конвертация цветов.

Что такое цвет? На самом деле каждый цвет можно разложить на три составляющие: красную, зелёную, голубую. Это так называемый RGB: Red, Green, Blue. Для передачи RGB служат четырёх битные переменные. Почему? Да потому, что для каждого цвета выделено по одному байту. Почему тогда наша переменная не 3 байтная, ведь цветов всего три? - спросите вы. Дело в том, что в основе компьютера лежит двоичная система счисления. Т.е. всё должно быть кратным степеням двойки. Именно поэтому 4. Последний байт в обычных офисных приложениях чаще всего пустует. А в играх ему нашли применение – этот байт отвечает за прозрачность цвета.

Так вот, каждый бит – это 8 байт. Бит может принимать значение 0 , или 1. Следовательно байт может содержать два в восьмой степени различных комбинаций, т.е. 256 различных комбинаций. В шестнадцатеричной системе счисления ближайшее число FF. Из этого всего понятно, что цвет представляется в виде $00FFFFFF, где $ означает, что число представлено в шестнадцатеричной системе счисления остальные пары чисел обозначают цвета. Например $00FF0000 –синий цвет, $0000FF00 – зелёный цвет, $000000FF – красный.

Дальше мы разбиваем цвет на его составляющие. Для этого есть такие стандартные процедуры: GetRValue – получить красную составляющую, GetGValue – получить зелёную составляющую, GetBValue – получить синюю (голубую) составляющую.

С цветом вроде бы как разобрались. Поехали дальше!

Залить форму плавно изменяющимся цветом, конечно же не получиться. Но можно нарисовать много-много разноцветных маленьких прямоугольничков, которые создадут эффект плавного перехода цвета. Возникает проблема, сколько же нужно таких прямоугольничков? Больше 250 их не имеет смысла делать – заметно все равно не будет, а ресурсы будет «жрать» здорово. А если высота нашей формы меньше 250 пикселей, то тогда делать 250 прямоугольников бессмысленно. Тогда создадим количество прямоугольников, равное высоте нашей формы, т.е. у каждого горизонтального ряда пикселей будет свой уникальный цвет:

if frm.Height < 250 then 
nolines:=frm.Height 
else 
nolines:=250; // Максимум 250 прямоугольников (больше не нужно) 

Дальше идёт проверка количества цветов. Функция GetDeviceCaps возвращает количество цветов, поддерживаемых монитором. Например, цвет True Color соответствует 32 битам. На большинстве современных мониторов он поддерживается. Тогда имеет смысл рисовать до 250 прямоугольников – и у всех будет разный цвет. Если же у нас цвет только 8 битный, то больше 50 прямоугольников рисовать не имеет смысла. Если нарисовать больше, то рядом стоящие прямоугольники почти не будут отличаться:

bitspix:=GetDeviceCaps(frm.Canvas.Handle, BITSPIXEL); 
if (bitspix = 8) and (nolines > 50) then 
nolines:=50 
else if bitspix < 8 then 
nolines:=4; 

Естественно, что наши прямоугольнички должны тянуться на всю ширину формы. Для этого достаточно их левую границу поставить в 0, а правой присвоить ширину формы:

r.Left:=0; // Left прямоугольника 
r.Right:=frm.Width; // Right прямоугольника 

Теперь нам известно общее количество прямоугольников, их ширина. Теперь запустим цикл для рисования каждого из прямоугольников. Цвет прямоугольников будет отличаться. Причём на какой-то определённый процент. Этот процент можно рассчитать по формуле:

curpct:= (i * 100) div nolines; 

Выводится довольно просто: 100% - это у нас nolines (количество прямоугольников). Х – текущий процент, при линии i. Следовательно, Х будет равен i*100 и всё это разделить на общее количество линий. Известен процент изменения, как же посчитать текущий цвет? А вот так (на примере красной составляющей):

if startr > endr then 
curr := startr - (curpct * (startr-endr) div 100) 
else 
curr := startr + (curpct * (endr-startr) div 100); 

Т.е. изменение цвета будет равно текущий процент умножить на общую разницу цветов и всё это разделить на 100%. Смысл условия if таков: если начальный цвет светлее конечного, то текущий цвет должен темнеть (например, белый $00FFFFFF больше чёрного $00000000). Иначе, если начальный темнее конечного, то текущий должен светлеть. Таким образом определяем каждую из составляющих текущего цвета.

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

frm.Canvas.Brush.Color:=RGB(curr, curg, curb); 

Нам всё известно, кроме верхней нижней точки прямоугольника. Найдём их:

r.Top:=i + (i*(frm.Height div nolines)); 
r.Bottom:=r.Top + (frm.Height div nolines)+1; 

Доказывается это аналогично проценту изменения цвета. (Если Вы в школе учили математику, то доказать это не составит Вам проблем J). Всё готово! Теперь можем рисовать прямоугольник:

frm.Canvas.FillRect(r); 

Вот так работает данная программа. Как использовать это в своих целях? Да очень просто. Дописываете процедуру TForm1.GradientForm к своему проекту в нужный юнит, конечно, меняя TForm1 на название вашей формы. Не забудьте дописать эту процедуру в разделе описания типа формы. Потом создаёте для этой формы обработчик события OnPaint и в нём пишите:

GradientForm(Form1,RGB(60,60,210), RGB(1,1,2)); 

Вместо Form1 передавая название вашей формы. Можно передавать свои цвета. Немного поэкспериментировав можно найти вполне неплохие сочетания.

Other Delphi

RUSSIAN
russian delphi gui алгоритм

Dialogue & Discussion

DeXPeriX

Sunday, February 19th, 2006, 12.00am

Это моя самая первая статья, так что не судите строго! ;) Обновлять я её не буду - лучше напишу что-нибудь более полезное и новое, но и удалять не буду - пускай останется для истории :)

Leave a comment

(after comment you will be redirected back here)