UpdateLayeredWindow

Uzun aradan sonra yine merhaba.
Bu yazıda sizlere Windows 2000 den sonra desteklenen
UpdateLayeredWindow apisinden bahsetmek istiyorum.

Biliyorsunuz Windows işletim sisteminde pençereler (…) dikdörtgen şeklindedir ve tüm programalar
bu yüzden birbirine benzer. Çoğu yazılımcı bundan çok sıkışmıştır (benim gibi)
ve bunu atlatmak için farklı bir çok tekniğe başvurmuşlardır. Bunu Bill Gates amacada
fark etmiş olmalıki Windows 2000 yazılırken bir çok yenilik gibi işletim sistemi
apisine UpdateLayeredWindow komutu koymuşlar.
Fakat bu komut kullanıldığında Windows (form) tipik davranışlarını sergilemez, yani
WM_PAINT gibi bazı kritik message ları tetiklemez. Herhalde işletim sisteminde cafcaflı
programlar olmasını istemediler.
Şimdi bazılarınız region komutları zaten fardı diyebilirler var ama bu komutlarla tam
istenen olmuyor ve regionlar çevresinde kırıklar meydana geliyor ve buda program
görüntülerinde pek hoş durmuyor. Bunun için belkide en iyi çare yine UpdateLayeredWindow
tekniği.
UpdateLayeredWindow tekniğinde arkaya windows çizimlerin yerine ilk önce bir resim gerekiyor.
Bu resmi desingtime veya runtime da oluşturabilirsiniz. Ben designtime ve png formatindaki
resimleri tercih ettim. Png formatı en önemki özelliklerinde biri ALPHA kanalına yani
saydamlık kanalına sahip olmasıdır. Diğer özellikleri için
http://tr.wikipedia.org/wiki/Portable_Network_Graphics buraya başvurabilirsiniz.
UpdateLayeredWindow en basit kullanılması splash ekranlardır. Bunun nedenleri arasında
windows işletim sisteminin WM_PAINT mesajını es geçmesi ve standat bileşenlerin bu yüzden
çizilememesi daha doğrusu layer altında kalan forma çizilmesidir. Bunu resmin üzerine
çizmek içinde kendimiz Delphide TCustomControl sınıfından türetme yaparak bir button
yaparak bunu layerın üzerine çizmeyi göstermeye çalışacağım. Bir sonraki yazımdada
Vista ile gelen bar üzerindeki gibi bu tekniği kullanarak küçük araçları
yapmaya çalışacağım.
Evet Delphi’ de png kullanımı 2007 versiyonunda geldi fakat Delphi’ nin eski sürümleri
için de http://www.torry.net/vcl/graphics/otherformats/pngimage.zip buradan indirebilirsiniz.
Png formatı 32 bit olmalı alpha kanalı ekleyebilmek için Photoshop veya opensource olan
Paint.Net (http://www.getpaint.net/) kullanabilirsiniz.

TSplashEkran ekranın en can alıcı yeri Execute fonksiyonudur. Burada
SetWindowLong(Fhandle, GWL_EXSTYLE, exStyle or WS_EX_LAYERED); satırı ile bileşenin sahibi formu
layered form yapıyoruz.
UpdateLayeredWindow fonksiyonu gördüğünüz gibi TBlendFunction tipi bir record (değişkenler
topluluğu veya yapı) gerektirir. Bu record tipi resmin arkaya nasıl çizim yapılacağı alpha(saydamlık) gibi
yöntemleri tutar.
UpdateLayeredWindow(Fhandle, 0, nil, @BitmapSize, FBitmap.Canvas.Handle, @BitmapPos, 0,@BlendFunction, ULW_ALPHA);

Şimdi bileşenimizi inceleyelim.

Aşağıda görüldüğü gibi png resmin alpha değerlerine göre çiziliyor.

layered

[code lang=”Delphi”]

unit splashekran;

interface

uses
SysUtils,
Classes,
Controls,
Messages,
Windows,
Forms,
pngimage,
Graphics;

type
TSplashEkran = class(TCustomControl)
private
FAlphaDegeri: integer;
FResim: TPngImage;
FBitmap: TBitmap; // png resmin tutamacı için gerekli.
Fhandle: THandle; // Sahip formun tutamacı.
procedure SetAlphaDegeri(const Value: integer);
procedure SetResim(const Value: TPngImage);
procedure ResizCiz;
procedure Setbuffer(const Value: TPngImage);

protected
procedure Paint; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override;
procedure CreateWnd; override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); override;

public
Fbuffer: TBitmap; // İleride transparent bileşenler için zemin.
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Execute;

published
property Resim: TPngImage read FResim write SetResim;
//Saydamlık değer 0-255 arası değer. Eğer 255 olursa resmin orjinal alfa değeri kullanılı.
// 0 ise form hiç görünmez.
property AlphaDegeri: integer read FAlphaDegeri write SetAlphaDegeri default 255; //
end;

procedure register;

implementation

procedure register;
begin
RegisterComponents(‘NoktaComp’, [TSplashEkran]);
end;
{ TSplashEkran }

constructor TSplashEkran.Create(AOwner: TComponent);
begin
if not(AOwner is TForm) then
raise EInvalidCast.Create(‘Sadece Form’);
inherited Create(AOwner);
// Controlstyle özelliğine diğer bileşenleri kabul etmek için.
ControlStyle := ControlStyle + [csAcceptsControls];
// Sahip formun tutamacını alıyor.
Fhandle := TForm(AOwner).Handle;
FResim := TPngImage.Create;
TForm(AOwner).BorderStyle := bsNone;
FAlphaDegeri := 255;
FBitmap := TBitmap.Create;
Fbuffer := TBitmap.Create;
Align := alClient;
end;

procedure TSplashEkran.CreateWnd;
begin
// pençere oluşturulduktan sonra resmi buffera atıyor.
inherited CreateWnd;
if not(csDesigning in ComponentState) then
Fbuffer.Assign(FResim);
end;

destructor TSplashEkran.Destroy;
begin
FBitmap.Free;
FResim.Free;
Fbuffer.Free;
inherited;
end;

procedure TSplashEkran.Execute;
var
BlendFunction: TBlendFunction;
BitmapPos: TPoint;
BitmapSize: TSize;
exStyle: DWORD;
begin
if Fhandle = 0 then
exit;
if csDesigning in ComponentState then
exit;
if FResim = nil then
exit;
exStyle := GetWindowLongA(Fhandle, GWL_EXSTYLE);
if (exStyle and WS_EX_LAYERED = 0) then
SetWindowLong(Fhandle, GWL_EXSTYLE, exStyle or WS_EX_LAYERED);
FBitmap.Assign(FResim);
TForm(Owner).ClientWidth := FBitmap.Width;
TForm(Owner).ClientHeight := FBitmap.Height;
BitmapPos := Point(0, 0);
BitmapSize.cx := FBitmap.Width;
BitmapSize.cy := FBitmap.Height;
BlendFunction.BlendOp := AC_SRC_OVER;
BlendFunction.BlendFlags := 0;
BlendFunction.SourceConstantAlpha := FAlphaDegeri;
BlendFunction.AlphaFormat := AC_SRC_ALPHA;
UpdateLayeredWindow(Fhandle, 0, nil, @BitmapSize, FBitmap.Canvas.Handle, @BitmapPos, 0,
@BlendFunction, ULW_ALPHA);
end;

procedure TSplashEkran.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited;
Windows.SetFocus(Handle);
ReleaseCapture;
SendMessage(Fhandle, WM_SYSCOMMAND, SC_MOVE + 1, 0);
end;

procedure TSplashEkran.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited;
SetCapture(Handle);
end;

procedure TSplashEkran.Paint;
begin
inherited;
ResizCiz;
if not(csDesigning in ComponentState) then
Execute;
end;

procedure TSplashEkran.ResizCiz;
begin
// Tasarım zamanında atanan resmi göstermek için.
if (not FResim.Empty) then
begin
Canvas.Rectangle(0, 0, FResim.Width, FResim.Height);
Canvas.Draw(0, 0, FResim);
end;
end;

procedure TSplashEkran.SetAlphaDegeri(const Value: integer);
begin
if FAlphaDegeri <> Value then
begin
FAlphaDegeri := Value;
if FAlphaDegeri > 255 then
FAlphaDegeri := 255;
if FAlphaDegeri < 0 then FAlphaDegeri := 0; Invalidate; end; end; procedure TSplashEkran.Setbuffer(const Value: TPngImage); begin Fbuffer.Assign(Value); end; procedure TSplashEkran.SetResim(const Value: TPngImage); var r: TRect; begin FResim.Assign(Value); FBitmap.Assign(FResim); GetWindowRect(Fhandle, r); MoveWindow(Fhandle, r.Left, r.Top, FResim.Width, FResim.Height, true); Invalidate; end; end. [/code] İlgili Dosyalar: Layered

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir