Краса - це страшна сила.
У цій статті я розглядаю кілька способів зробити форму красивою. Приклади, розглянуті тут, мають швидше естетичну, ніж практичну цінність, але, я думаю, ними можна скористатися при оформленні вікон вашої, шановні читачі, програми. Для оформлення я розгляну кілька способів залиття форми градієнтною заливкою (приклад такої заливки - інсталятори, в яких користувач милується красивим вікном, поки програма робить свою чорну справу). У різних Faq я зустрічав приклади, котрі заливають форму будь - яким градієнтом, і існують компоненти, які застосовують градієнтну заливку для оформлення (наприклад TRxGradientCaption з RxLib), але статті, систематизирующей інформацію з цього питання я не зустрічав. Тому я сподіваюся, що цей матеріал виявиться вам корисним.
Для заповнення полотна (Canvas) форми я використовую код, основа якого взята мною у високоповажного Nomadic'а з Озеровского FAQ. Його код я перетворив в одну подію OnPaint (у Nomadic'а в прикладі був розміщений Timer і обрабативлісь FormCreate, Timer.OnTimer, FormDestroy). Ось цей код:
procedure TForm1.FormPaint (sender: TObject);
type TRGB = record
b, g, r: byte;
end;
ARGB = array [0..1] of TRGB;
PARGB = ^ ARGB;
var
b: TBitMap;
p: PARGB;
x, y: integer;
begin
b: = TBitMap.Create;
b.pixelformat: = pf24bit;
b.width: = Clientwidth;
b.height: = Clientheight;
for y: = 0 to b.height-1 do
begin
p: = b.scanline [y];
for x: = 0 to b.width-1 do
begin
// цю частину коду будемо змінювати
p [x] .r: = random (256);
p [x] .g: = random (256);
p [x] .b: = random (256);
end;
end;
canvas.draw (0,0, b);
b.free;
end;
p [x] .r: = 255;
p [x] .g: = 255;
p [x] .b: = - 255 * x div b.width;
При застосуванні горизонтальної заливки слід врахувати, що порожній залитий об'єкт здається нестійким і його потрібно врівноважити, розмістивши щось на ньому (рис.3).
Вертикальну заливку отримати не набагато складніше. Для цього потрібно змінювати кольори не по х, а по у. Наприклад, наступний код дасть нам настільки улюблену інсталяторами синьо - білу заливку (рис. 4).
p [x] .r: = 255 * y div b.Height;
p [x] .g: = 255 * y div b.Height;
p [x] .b: = 255;
Зверніть увагу - щоб отримати синьо - білий градієнт я змінюю червоний і зелений кольори, а синій залишаю незмінним. Взагалі отримання потрібної колірної розтяжки я вважаю одним з найбільш хитрим питань даної теми, і я повернуся до нього в кінці цієї статті.
Ще більш красивого ефекту можна досягти накложів градієнти один на одного. Наприклад змінюючи червоний колір по вертикалі, а зелений по вертикалі ми отримаємо таку картину (рис. 5)
p [x] .r: = 255 * y div b.Height;
p [x] .g: = 255 * x div b.Width;
p [x] .b: = 255;
Отриманого градієнту можна надати зернисту структуру, змінюючи один або кілька основних кольорів випадковим чином. Що ви скажете про заливки на малюнках 6 і 7? p [x] .r: = random (250);
p [x] .g: = 255;
p [x] .b: = 255 * x div b.Width; (Рис. 6)
p [x] .r: = random (250);
p [x] .g: = 255 * y div b.Height;
p [x] .b: = 255 * x div b.Width; (Рис.7)
Для отримання більш складного розподілу градієнта за формою доведеться використовувати більш складні формули при присвоєнні значень кольорів. Розглянемо отримання заливки "до центру". Очевидно змінюваний колір повинен зменшуватися або збільшуватися від краю до центру форми, а потім змінюватися в зворотному порядку. Цього можна досягти за допомогою умовного оператора (більш наочний спосіб) (рис 8).
p [x] .r: = 0;
if y <= b.Height div 2
then p [x] .g: = 255 * y * 2 div b.Height
else p [x] .g: = - 255 * y * 2 div b.Height;
if abs (y - b.Height div 2)<3 then p[x].g:=255;
p [x] .b: = 200;
Більш складний спосіб - скласти функцію, яка змінює колір потрібним чином. Для такого прикладу нам знадобиться функція Sgn:
function Sgn (i: integer): integer;
begin
if i<>0 then Sgn: = round (i / abs (i))
else Sgn: = 1
end;
Функція Sign з модуля Math не підходить, тому що повертає 0 при значенні аргументу 0.
Наступний код дає такий варіант заливки (рис. 9):
p [x] .r: = 150;
p [x] .g: = Sgn (b.Width div 2-x) * (255 * x * 2 div b.Width);
p [x] .b: = 50;
На малюнку 9а показаний результат заміни функції Sgn, певною нами на функцію Sign з модуля Math. Повертається нуль призводить до появи смуги в середині форми.
Комбінуючи розглянуті способи заливок можна отримати форми, вид яких здивує всіх, включаючи творця (рис 10 - 12).
p [x] .r: = 50;
p [x] .g: = sgn (b.Width div 2-x) * (255 * x * 2 div b.Width);
p [x] .b: = sgn (b.Height div 2-y) * (255 * y * 2 div b.Height);
<Зелёная составляющая изменяется к центру по горизонтали, а синяя по вертикали> (Рис. 10)
p [x] .r: = 150 * x div b.Width;
p [x] .g: = sgn (b.Width div 2-x) * (255 * x * 2 div b.Width);
p [x] .b: = 155 * y div b.Height;
(Рис. 11)
p [x] .r: = 150 * x div b.Width;
p [x] .g: = sgn (b.Width div 2-x) * (255 * x * 2 div b.Width);
p [x] .b: = 155 + random (100);
(Рис. 12)
Вас не інтригує число 255, яке у формулах? Очевидно, зменшуючи його ми змінюємо колір, з якого починається заливка, а ось збільшення числа призводить до цікавого ефекту "жалюзі" - дублювання градієнтної заливки за формою (рис. 13)
p [x] .r: = 0;
p [x] .g: = 255 * 4 * y div b.Height;
p [x] .b: = 155;
Тут я не став писати 1020 замість 255 * 4, щоб було видно звідки взялися чотири "хвилі" градієнтної заливки.
Ще один ефект (рис. 14) - плавно переходять градієнтні хвилі виходять за допомогою наступного, правда досить незграбного коду:
p [x] .g: = 0;
if (x <= b.Width div 4) or ((x <= 3*b.Width div 4) and (x>= B.Width div 2))
then p [x] .r: = 255 * x * 4 div b.Width
else p [x] .r: = - 255 * x * 4 div b.Width;
if abs (x - b.Width div 2)<3 then p[x].r:=0;
if (abs (x -b.Width div 4)<3) or (abs(x - 3*b.Width div 4)<3) then p[x].r:=255;
p [x] .b: = 0;
Втім, цей ефект буде отриманий в кінці статті іншим, більш простим способом.
Отже, ви отримали красиво залиту форму і стали змінювати її розміри. І тут ви зіткнулися з негарним ефектом - на формі відображаються артефакти від заливки (рис 15).
Способів виправити цю ситуацію існує багато. Скористаємося найочевиднішим з них:
procedure TForm1.FormResize (Sender: TObject);
begin
form1.DoubleBuffered: = true;
form1.Repaint;
end;
Тепер при зміні розмірів форми зовнішній вигляд заливки не змінюється.
Наступне питання, яке не можна залишити без уваги в цій статті - це питання вибору квітів для створення градієнта. Для його дослідження в загальному випадку потрібно мати уявлення про RGB колірної моделі. Колірний перехід градієнта являє собою криву в цій моделі, рівняння якої потрібно задати в програмі. Вивчення колірної моделі і створення довільного колірного градієнта - завдання не для статті. Тут розглянемо, як отримати двоколірний перехід. Досить зрозуміло рішення для основних кольорів (червоний, синій, зелений) і їх сумішей. Так RG дає жовтий колір, RB - фіолетовий, GB - блакитний. Наприклад, для отримання синьо - жовтої раcтяжкі потрібно змінювати B від 255 до 0, R і G від 0 до 255 - ось так (рис. 16).
p [x] .g: = 255 * y div b.Height;
p [x] .b: = -255 * y div b.Height;
Для отримання довільної колірної розтяжки пропоную наступну процедуру.
Визначивши значення потрібних кольорів візуально (наприклад, за допомогою вікна вибору кольору), подставте їх на потрібне місце і визначте напрямок заливки.
Image1.Stretch: = true // де-небудь, можна на етапі проектування.