(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Создание визуальных компонентов в Delphi (документация, исходники)

Источник: articles
Михаил Продан

При первом знакомстве с delphi несомненно удивляешься великому множеству разных визуальных компонентов. Кнопочки, панельки, надписи и многое другое. Но после нескольких месяцев пользования этой средой разработки появляется желание написать что-то свое. Именно эту задачу мы и попытаемся решить используя инвентарь delphi, который есть в у нас в наличии и, естественно, свое воображение.

Постановка задачи

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

Реализация

Наиболее правильным, с точки зрения иерархии vcl, методом решения первого пункта поставленной задачи, будет создание нового компонента, в качестве базового класса которого мы выберем tcustomcontrol. Этот класс является базовым для создания компонентов-надстроек над визуальными объектами windows, и предоставляет методы для отрисовки объектов разных форм. Если же у вас нет необходимости наследовать все особенности поведения объектов windows, то можете в качестве базового класса использовать tgraphiccontrol, наследники которого отрисовываются быстрее, поскольку не должны следить за уймой Виндовских служебных сообщений.

Сам компонент tcustomcontrol определен в модуле controls.pas следующим образом:

tcustomcontrol = class(twincontrol)
private
fcanvas: tcanvas;
procedure wmpaint(var message: twmpaint); message wm_paint;
protected
procedure paint; virtual;
procedure paintwindow(dc: hdc); override;
property canvas: tcanvas read fcanvas;
public
constructor create(aowner: tcomponent); override;
destructor destroy; override;
end;

Здесь самым интересным для нас является метод paint и свойство canvas. Посредством этих двух членов класса tcustomcontrol мы и будет рисовать нашу кнопку.

Кроме этого мы немножко расширим функциональность нашего компонента и придадим ему возможность устанавливать цвет темного и светлого участка своей границы, а также ее толщину, и наконец определим свойство flat, которое отвечает за функциональность аналогичного свойства стандартных компонентов delphi.

Исходя из вышесказанного прототип нашего компонента (tellipsebutton) будет выглядеть следующим образом:

tellipsebutton = class(tcustomcontrol)
private
fdarkcolor,flightcolor,fbackcolor:tcolor;
fsize:integer;
fpushed:boolean;
rgn:hrgn;
fflat:boolean;
fdrawflat:boolean;
fonmouseenter,fonmouseleave:tnotifyevent;
{ private declarations }
protected
procedure setdarkcolor(value:tcolor);
procedure setlightcolor(value:tcolor);
procedure setsize(size:integer);
procedure setbackcolor(value:tcolor);
procedure dblclick;override;
procedure drawflat;dynamic;
procedure drawnormal;dynamic;
procedure drawpushed;dynamic;
procedure wmlbuttondown(var message:twmmouse);message wm_lbuttondown;
procedure wmlbuttonup(var message:twmmouse);message wm_lbuttonup;
procedure wmmousemove(var message:twmmousemove);message wm_mousemove;
procedure cmmouseenter(var message:tmessage);message cm_mouseenter;
procedure cmmouseleave(var message:tmessage);message cm_mouseleave;
procedure cmtextchanged(var message:tmessage);message cm_textchanged;
procedure setflat(value:boolean);
procedure domouseenter;
procedure domouseleave;
{ protected declarations }
public
constructor create(aowner:tcomponent);override;
procedure afterconstruction;override;
destructor destory;virtual;
procedure repaint;override;
procedure paint;override;
{ public declarations }
property canvas;
published
property darkcolor:tcolor read fdarkcolor write setdarkcolor default clblack;
property lightcolor:tcolor read flightcolor write setlightcolor default clwhite;
property backcolor:tcolor read fbackcolor write setbackcolor default clbtnface;
property size:integer read fsize write setsize;
property flat:boolean read fflat write setflat;
property caption;
{events}
property onclick;
property ondblclick;
property onmousemove;
property onmousedown;
property onmouseup;
property onmouseenter:tnotifyevent read fonmouseenter write fonmouseenter;
property onmouseleave:tnotifyevent read fonmouseleave write fonmouseleave;
{ published declarations }
end;

Как видим, здесь помимо базовых конструктора create и метода afterconstruction переопределены и методы paint и repaint.

Вся функциональность этого компонента в основном заключена в динамических методах drawflat, drawnormal, drawpushed, которые отвечают за рисование компонента соответственно в режиме flat, в нормальном приподнятом режиме и в нажатом режиме.

Собственно рисование делается с помощью метода canvas.arc, который рисует часть эллипса заданным цветом. Таким образом мы рисуем одну половину темным цветом, а другую - светлым и получаем эффект выпуклости. Поменяв местами цвета мы достигаем эффекта «нажатия» для нашей кнопки. Ну а использовав в качестве цвета фона - средний между темным и светлым цветами границы - мы получаем ефект flat:

procedure tellipsebutton.drawflat;
var x,y:integer;
begin
canvas.lock;
try
inherited paint;
canvas.brush.color:=backcolor;
canvas.pen.color:=clgray;
canvas.arc(0,0,width,height,0,height,width,0);
canvas.brush.style:=bsclear;
canvas.ellipse(clientrect);
canvas.font.size:=5;
x:=self.clientwidth-canvas.textwidth(caption);
x:=x div 2;
y:=self.clientheight-canvas.textheight(caption);
y:=y div 2;
canvas.textrect(self.clientrect,x,y,caption);
finally
canvas.unlock;
end;
end;

procedure tellipsebutton.drawnormal;
var i:integer;x,y:integer;
begin
canvas.lock;
try
inherited paint;
canvas.brush.style:=bsclear;
canvas.brush.color:=backcolor;
canvas.pen.color:=darkcolor;
canvas.arc(0,0,width,height,0,height,width,0);
for i:=0 to fsize do
canvas.arc(i,i,width-i,height-i,i,height-i,width-i,i);
canvas.pen.color:=lightcolor;
canvas.arc(0,0,width,height,width,0,0,height);
for i:=0 to fsize do
canvas.arc(i,i,width-i,height-i,width-i,i,i,height-i);
canvas.brush.style:=bsclear;
canvas.font.size:=5;
x:=self.clientwidth-canvas.textwidth(caption);
x:=x div 2;
y:=self.clientheight-canvas.textheight(caption);
y:=y div 2;
canvas.textrect(self.clientrect,x,y,caption);
finally
canvas.unlock;
end;
end;

procedure tellipsebutton.drawpushed;
var i:integer;x,y:integer;
begin
canvas.lock;
try
inherited paint;
canvas.brush.style:=bsclear;
canvas.brush.color:=backcolor;
canvas.pen.color:=lightcolor;
canvas.arc(0,0,width,height,0,height,width,0);
for i:=0 to fsize do
canvas.arc(i,i,width-i,height-i,i,height-i,width-i,i);
canvas.pen.color:=darkcolor;
canvas.arc(0,0,width,height,width,0,0,height);
for i:=0 to fsize do
canvas.arc(i,i,width-i,height-i,width-i,i,i,height-i);
canvas.brush.style:=bsclear;
canvas.font.size:=5;
x:=self.clientwidth-canvas.textwidth(caption);
x:=x div 2;
y:=self.clientheight-canvas.textheight(caption);
y:=y div 2;
canvas.textrect(self.clientrect,x,y,caption);
finally
canvas.unlock;
end;
end;

Теперь, оснастив наш компонент необходимыми функциями, мы можем приступить к его «причесыванию», т.е. написанию рутинных методов по присвоению значений свойствам и отладке. Первым делом здесь надо реализовать реакцию компонента на события мыши. Это мы делаем посредством методов wmlbuttondown, wmlbuttonup, wmmousemove.

procedure tellipsebutton.wmlbuttondown;
begin
inherited;
paint;
end;

procedure tellipsebutton.wmlbuttonup;
begin
inherited;
paint;
end;
procedure tellipsebutton.wmmousemove;
begin
inherited;
if csclicked in controlstate then
begin
if ptinrect(clientrect,smallpointtopoint(message.pos)) then
begin
if not fpushed then drawpushed;
fpushed:=true;
end else
begin
if fpushed then drawnormal;
fpushed:=false;
end
end;
end;

Здесь также мы реализуем функциональность свойства flat. (в wmmousemove).

Кроме этого мы используем методы cmmouseenter, cmmouseleave для вызова соответствующих обработчиков событий.

А также реализовываем метод cmtextchanged для правильного отображения текста кнопки:

procedure tellipsebutton.cmtextchanged;
begin
invalidate;
end;

Теперь же дело только за методами paint и repaint, которые мы реализовываем следующим образом:

procedure tellipsebutton.paint;
begin
if not fflat then
begin
if not (csclicked in controlstate) then
drawnormal else drawpushed;
end else
if fdrawflat then drawflat else
if not (csclicked in controlstate) then drawnormal else drawpushed;
end;

procedure tellipsebutton.repaint;
begin
inherited;
paint;
end;

Все. Теперь наш компонент готов к испытаниям. И перед тем как его регистрировать и кидать на палитру компонентов настоятельно рекомендую Вам проверить его функциональность в runtime режиме. В противном же случае вы рискуете повесить всю ide delphi при добавлении компонента на форму.

Проверка компонента
Проверка компонента в runtime режиме не вызовет осложнений даже у новичка. Всего-то лишь надо:

-создать новое приложение
-в секции uses разместить ссылку на модуль с вашим компонентом (ellipsebutton.pas)
-объявить переменную типа tellipsebutton
-создать компонент, заполнить все его свойства и показать.

unit main;

interface

uses
windows, messages, sysutils, variants, classes, graphics, controls, forms,
dialogs, mycontrols;

type
tform1 = class(tform)
ellipsebutton1: tellipsebutton;
procedure formcreate(sender:tobject);
procedure formdestroy(sender:tobject);
private
{ private declarations }
public
{ public declarations }
end;

var
form1: tform1;

implementation

{$r *.dfm}
procedure tform1.formcreate(sender:tobject);
begin
ellipsebutton1:=tellipsebutton.create(self);
ellipsebutton1.parent:=self;
ellipsebutton1.setbounds(10,10,100,100);
ellipsebutton1.visible:=true;
end;

procedure tform1.formdestroy(sender:tobject);
begin
ellipsebutton1.free;
end;

end.

После такой, наглядной проверки и отладки вы можете спокойно регистрировать ваш компонент:

procedure register;
begin
registercomponents('usable', [tellipsebutton]);
end;

И использовать уже в ваших приложениях для быстрого создания эллипсоидных кнопок.

Итоги
Теперь, обладая мастерством рисования и зная методику написания визуальных компонентов для delphi, вы можете преспокойно написать любой замысловатый элемент интерфейса и даже продавать его как отдельный программный продукт за немаленькие деньги.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 11.01.2007 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
VMware Workstation 14 Pro for Linux and Windows, ESD
ABBYY Lingvo x6 Английская Домашняя версия, электронный ключ
Oracle Database Personal Edition Named User Plus Software Update License & Support
EMS SQL Management Studio for InterBase/Firebird (Business) + 1 Year Maintenance
Zend Guard 1 Year Subscription
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Программирование на Visual Basic/Visual Studio и ASP/ASP.NET
ЕRP-Форум. Творческие дискуссии о системах автоматизации
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100