Imágenes.
En este apartado vamos a ver como tratar imágenes en nuestro componente.
En Delphi hay varios objetos que guardan (o hacen referencia a) imágenes
: TPicture, TBitmap,..., dependiendo de nosotros seleccionar aquel que
más se ajuste a nuestro interés, o bien podemos optar por
crear alguno nuevo. En nuestro componente vamos a utilizar dos de estos
objetos, un Picture y un Bitmap (este último lo veremos más
adelante, hacia el final de esta serie de artículos).
Picture nos permitirá cargar imágenes de varios tipos :
bmp, jpg,ico,..., de esta manera ofrecemos al programador que utilice
el componente una mayor libertad para seleccionar el tipo de gráfico
que quiere mostrar.
Como hemos dicho, las imágenes se guardarán en objetos
que nuestro componente debe gestionar (crear, manipular y destruir) por
lo que se deben definir variables que referencien dichos objetos. Como
siempre, estas variables se definirán en la parte privada y serán
las propiedades, las encargadas de interactuar con ellas.
Como se ha dicho, al ser objetos, se deben crear en algún lugar
del código de nuestro componente y deberán ser destruidos
antes de que se destruya nuestro control. Crear el objeto se hará,
normalmente, en el constructor (Create) del componente y para destruirlo
deberemos hacerlo justo antes de la destrucción de nuestro propio
objeto. Hay un procedimiento especial que se ejecuta siempre antes de
la liberación de memoria del objeto, este método es el 'destructor',
se llama Destroy y deberemos sobreescribirlo:
Destructor Destroy;
begin
//acciones anteriores a la liberación de memoria
inherited;
end;
Este procedimiento se debe definir en el apartado Public de nuestro componente.
Resumiendo, para guardar la imagen que queremos mostrar en nuestro componente
debemos : (a) Definir una variable que referencie al objeto que
contendrá la imagen, (b) crear el objeto imagen y hacer
que la variable definida contenga su referencia, (c) si queremos
tener una propiedad que refleje y maneje a la variable deberemos definir
esa propiedad, (d) tratar el objeto en cualquier sitio del código
del componente y (e) destruir/liberar el objeto antes de liberar
el control creado con nuestro componente.
private
FPicture:TPicture;
...
procedure SetPicture(Value:TPicture);
...
public
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
...
published
property Picture:TPicture read FPicture Write SetPicture;
...
implementation
constructor TPanelSel.Create(AOwner:TComponent);
begin
inherited;
...
...
FPicture:=TPicture.Create;
end;
destructor TPanelSel.Destroy;
begin
FPicture.Free;
inherited;
end;
...
procedure TPanelSel.SetPicture(Value:TPicture); begin FPicture.Assign(Value); repaint; end; ...
Hasta aquí tenemos la imagen guardada pero todavía no hemos
hecho que se dibuje en pantalla dentro del control, para ello iremos al
método Paint y allí dibujaremos la posible imagen.
procedure TPanelSel.Paint;
var
X, Y, W, H: Integer;
begin
with Canvas do
begin
setbkmode(Handle,TRANSPARENT);
Pen.Width:=BorderWidth;
Pen.Color:=BorderColor;
Brush.Style:=bsSolid;
Brush.Color:=Color;
X := Pen.Width div 2;
Y := X;
W := Width - Pen.Width + 1;
H := Height - Pen.Width + 1;
if Focused then
begin
Pen.Color:=FocusedBorderColor;
Brush.Color:=FocusedColor;
end;
if FOver then
begin
Pen.Color:=OverBorderColor;
Brush.Color:=OverColor;
end;
FillRect(ClientRect);
Brush.Style:=bsClear;
if Assigned(Picture.Graphic) then
Draw(BorderWidth,((Height-Picture.Graphic.Height) div 2),Picture.Graphic);
if Border then Rectangle(X, Y, X + W, Y + H);
end;
end;
El resultado en pantalla es :
Figura 5
A la hora de dibujar la imagen hemos hecho que ésta aparezca,
verticalmente, en el medio y horizontalmente justo después del
borde. Nótese que antes de dibujar, nos hemos asegurado de que
el objeto picture contiene algo (una imagen). La funciónAssigned(puntero)
sólo comprueba que este no sea Nil
Observamos en la figura anterior un relleno blanco sobre el dibujo que
a nosotros nos interesa, el círculo con la letra 'A'. La propiedad
Graphic del objeto Picture de nuestro componente, es a la vez un objeto
que tiene una propiedad denominada Transparent, esta propiedad cuando
tiene el valor True hace que sea transparente el color de la imagen que
coincida con el color del pixel (0,0) de la misma. Hay otras propiedades
dentro de objetos como Bitmap que hacen referencia a esto mismo y se puede
elegir el color que deseamos que sea el transparente, pero esto queda
fuera del objetivo de este artículo.
...
Brush.Style:=bsClear;
if Assigned(Picture.Graphic) then
begin
Picture.Graphic.Transparent:=true;
Draw(BorderWidth,((Height-Picture.Graphic.Height) div 2),Picture.Graphic);
end;
if Border then Rectangle(X, Y, X + W, Y + H);
...
Vamos a dar la posibilidad de que el programador elija la coordenada
X a partir de la cual dibujar la imagen, para ello añadimos una
variable nueva, una propiedad y hacemos que cualquier cambio en el valor
de esta propiedad se refleje inmediatamente en pantalla (como hemos hecho
en otras ocasiones) :
El código de nuestro componente hasta el momento es :
unit PanelSel;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Graphics;
type
TPanelSel = class(TCustomControl)
private
FPicture:TPicture;
FColors:array[0..5] of TColor;
FBorder:Boolean;
FBorderWidth:Integer;
FOver:Boolean;
FPosXPicture:Word;
procedure SetPicture(Value:TPicture);
procedure SetColors(Index:Integer;Value:TColor);
function GetColors(Index:integer):TColor;
procedure SetBorder(Value:Boolean);
procedure SetBorderWidth(Value:integer);
procedure SetPosXPicture(Value:Word);
{ Private declarations }
protected
procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
procedure WMKillFocus(var Message: TWMSetFocus); message WM_KILLFOCUS;
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure Paint; override;
procedure Click;override;
{ Protected declarations }
public
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
property Colors[Index:Integer]:TColor read GetColors Write SetColors;
{ Public declarations }
published
property Picture:TPicture read FPicture Write SetPicture;
property Border:Boolean read FBorder Write SetBorder default True;
property BorderWidth:integer read FBorderWidth Write SetBorderWidth default 1;
property Color:TColor Index 0 read GetColors Write SetColors default clBtnFace;
property BorderColor:TColor Index 1 read GetColors Write SetColors default clBlack;
property FocusedColor:TColor Index 2 read GetColors Write SetColors default clBtnHighlight;
property FocusedBorderColor:TColor Index 3 read GetColors Write SetColors default clBlack;
property OverColor:TColor Index 4 read GetColors Write SetColors default clBtnShadow;
property OverBorderColor:TColor Index 5 read GetColors Write SetColors default clBlack;
property PosXPicture:Word read FPosXPicture Write SetPosXPicture default 10;
property Font;
property Tabstop;
{ Published declarations }
end;
procedure Register;
implementation
constructor TPanelSel.Create(AOwner:TComponent);
begin
inherited;
FOver:=False;
Tabstop:=True;
FBorder:=True;
FBorderWidth:=1;
FColors[0]:= clBtnFace;
FColors[1]:=clBlack;
FColors[2]:=clBtnHighlight;
FColors[3]:=clBlack;
FColors[4]:= clBtnShadow;
FColors[5]:=clBlack;
FPicture:=TPicture.Create;
FPosXPicture:=10;
end;
destructor TPanelSel.Destroy;
begin
FPicture.Free;
inherited;
end;
procedure TPanelSel.WMSetFocus(var Message: TWMSetFocus);
begin
inherited;
Invalidate;
end;
procedure TPanelSel.WMKillFocus(var Message: TWMSetFocus);
begin
inherited;
Invalidate;
end;
procedure TPanelSel.CMMouseEnter(var Message: TMessage);
begin
inherited;
FOver:=True;
Invalidate;
end;
procedure TPanelSel.CMMouseLeave(var Message: TMessage);
begin
inherited;
FOver:=False;
Invalidate;
end;
procedure TPanelSel.SetPicture(Value:TPicture);
begin
FPicture.Assign(Value);
repaint;
end;
procedure TPanelSel.SetPosXPicture(Value:Word);
begin
if FPosXPicture<>Value then
// Sólo permitimos valores mayores que cero
if value>0 then
begin
FPosXPicture:=Value;
invalidate;
end;
end;
procedure TPanelSel.SetBorder(Value:Boolean);
begin
if FBorder<>Value then
begin
FBorder:=Value;
Invalidate;
end;
end;
procedure TPanelSel.SetBorderWidth(Value:integer);
begin
if FBorderWidth<>Value then
begin
if Value>0 then
FBorderWidth:=Value;
Invalidate;
end;
end;
procedure TPanelSel.SetColors(Index:Integer;Value:TColor);
begin
if FColors[Index]<>Value then
begin
FColors[Index]:=Value;
Invalidate;
end;
end;
Function TPanelSel.GetColors(Index:Integer):TColor;
begin
Result:=FColors[Index];
end;
procedure TPanelSel.Click;
begin
inherited;
SetFocus;
end;
procedure TPanelSel.Paint;
var
X, Y, W, H: Integer;
begin
with Canvas do
begin
setbkmode(Handle,TRANSPARENT);
Pen.Width:=BorderWidth;
Pen.Color:=BorderColor;
Brush.Style:=bsSolid;
Brush.Color:=Color;
X := Pen.Width div 2;
Y := X;
W := Width - Pen.Width + 1;
H := Height - Pen.Width + 1;
if Focused then
begin
Pen.Color:=FocusedBorderColor;
Brush.Color:=FocusedColor;
end;
if FOver then
begin
Pen.Color:=OverBorderColor;
Brush.Color:=OverColor;
end;
FillRect(ClientRect);
Brush.Style:=bsClear;
Picture.Graphic.Transparent:=true;
if Assigned(Picture.Graphic) then
Draw(BorderWidth+PosXPicture,((Height-Picture.Graphic.Height) div 2),Picture.Graphic);
if Border then Rectangle(X, Y, X + W, Y + H);
end;
end;
procedure Register;
begin
RegisterComponents('Ejemplo', [TPanelSel]);
end;
end.
|