ana sayfa > Delphi > UpdateLayeredWindow

UpdateLayeredWindow

Çarşamba, 09 Eyl 2009 yorum ekle yorumlara git

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

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.

İlgili Dosyalar:
Layered

Categories: Delphi Tags:
  1. şimdilik yorum yok.
  1. şimdilik geri bağlantı yok