Translucent forms

Tags:    delphi
Skrevet af Bruger #132 @ 26.10.2001
Translucent forms


Indledende bemærkninger.

Flg. er lavet med D5 under Win2000. Det virker, så vidt jeg ved, ikke under win9x eller WinMe. Jeg ved ikke med XP, men det vil sandsynligvis fungere. Translucent, eller halvgennemsigtige, vinduer er, som navnet antyder, vinduer hvor man kan se det bagvedliggende igennem. Et eksempel på dette kan man se på muse-pointeren i Win2K. Hvis man kigger nøje på den, kan man se at der er en skygge til højre for. Det fænomen vil jeg prøve at lege lidt med i denne artikel.

Grader af gennemsigtighed.

Lad os først udforske gennemsigtigheden lidt. Start med en tom form med en TEdit og en TButton. Sæt TEdit.Text til 255. I TButton.OnClick skrives:
  SetWindowLong(self.Handle, gwl_ExStyle, GetWindowLong(Handle, gwl_ExStyle) or ws_EX_Layered);
  SetLayeredWindowAttributes(self.Handle, 0, strtoint(edit1.text), lwAlpha);
Nu er det sådan, at Delphi(I hvert fald ikke V5. Det kan være at det er med i V6, men så vil constanter/funktioner nok hedde noget andet) ikke kender noget til ws_EX_Layered, SetLayeredWindowAttributes eller lwAlpha. Vi må derfor definere dem selv med flg:
const
  lwa_ColorKey = 1;
  lwa_Alpha = 2;
  ws_Ex_Layered = $80000;

function SetLayeredWindowAttributes (Wnd: hWnd; crKey: ColorRef; bAlpha: Byte; dwFlags:DWord):
 Bool; stdcall; external 'user32.dll';
som placeres som globale konstanter (fx. lige efter Implementation). Vores program ser nu således ud:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

const
  //Constants for layered windows
  lwa_Alpha = 2;
  ws_Ex_Layered = $80000;

function SetLayeredWindowAttributes (Wnd: hWnd; crKey: ColorRef; bAlpha: Byte; dwFlags:DWord):
 Bool; stdcall; external 'user32.dll';

{$R *.DFM}


procedure TForm1.Button1Click(Sender: TObject);
begin
  SetWindowLong(self.Handle, gwl_ExStyle, GetWindowLong(Handle, gwl_ExStyle) or ws_EX_Layered);
  SetLayeredWindowAttributes(self.Handle, 0, strtoint(edit1.text), lwa_alpha);
end;

end.
Kør det. Prøv at ændre tallet i editboksen og tryk på knappen. Tallet skal være under <=255 og >=0. Bemærk at alle komponenter på formen også ændrer gennemsigtighed.

Skygger på forms

Det er jo meget sjovt. Det vi nu skal er at bruge denne teknik til at lave en skygge på en form. Det vil jeg gøre ved at lave to forms til skygger. En til højre og en nedenunder formen. Start på en ny form. Kald Den ShadowForm. Koden til ShadowForm ser sådan ud (forklaring kommer efter):
unit TransForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls;

type
  TShadowForm = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
    ShadowWidth: Integer;
    RightShadow: TForm;
    BotShadow: TForm;
    FShadowIntensity: byte;
    FShadowSize: integer;
    procedure WMWindowPosChanged(var Message: TWMWindowPosChanged); message wm_WindowPosChanged;
    procedure SetShadowIntensity(const Value: byte);
    procedure SetShadowSize(const Value: integer);
  public
    { Public declarations }
    property ShadowSize: integer read FShadowSize write SetShadowSize;
    property ShadowIntensity: byte read FShadowIntensity write SetShadowIntensity;
  end;

var
  ShadowForm: TShadowForm;

implementation

{$R *.DFM}

const
  //Constants for layered windows
  lwa_Alpha = 2;
  ws_Ex_Layered = $80000;

function SetLayeredWindowAttributes (Wnd: hWnd; crKey: ColorRef; bAlpha: Byte; dwFlags:DWord):
 Bool; stdcall; 

external 'user32.dll';

procedure TShadowForm.FormCreate(Sender: TObject);
begin
  FShadowSize := 7;
  FShadowIntensity := 100;
  RightShadow := TForm.Create(Self);
  RightShadow.Parent := Application.MainForm;
  RightShadow.BorderStyle := bsNone;
  RightShadow.Width := ShadowSize;
  RightShadow.Color := clBlack;
  RightShadow.Visible := True;
  SetWindowLong(RightShadow.Handle, gwl_ExStyle, GetWindowLong(Handle, gwl_ExStyle)
   or ws_EX_Layered);
  SetLayeredWindowAttributes(RightShadow.Handle, 0, ShadowIntensity, lwa_Alpha);
  BotShadow := TForm.Create(Self);
  BotShadow.Parent := Application.MainForm;
  BotShadow.BorderStyle := bsNone;
  BotShadow.Height := ShadowSize;
  BotShadow.Color := clBlack;
  BotShadow.Visible := True;
  SetWindowLong(BotShadow.Handle, gwl_ExStyle, GetWindowLong(Handle, gwl_ExStyle)
   or ws_EX_Layered);
  SetLayeredWindowAttributes(BotShadow.Handle, 0, ShadowIntensity, lwa_Alpha);
  FormResize(Sender);
end;

procedure TShadowForm.WMWindowPosChanged(var Message: TWMWindowPosChanged);
begin
  Inherited;
  if Assigned(RightShadow) and RightShadow.Visible then
    FormResize(Nil);
end;

procedure TShadowForm.FormResize(Sender: TObject);
begin
  RightShadow.Height:= Height;
  RightShadow.Left := Left + Width;
  RightShadow.Top := Top + ShadowSize;
  RightShadow.Width := ShadowSize;
  BotShadow.Width := Width - ShadowSize;
  BotShadow.Left := Left + ShadowSize;
  BotShadow.Top := Top + Height;
  BotShadow.Height := ShadowSize;
end;

procedure TShadowForm.SetShadowIntensity(const Value: byte);
begin
  FShadowIntensity := Value;
  SetLayeredWindowAttributes(RightShadow.Handle, 0, ShadowIntensity, lwa_Alpha);
  SetLayeredWindowAttributes(BotShadow.Handle, 0, ShadowIntensity, lwa_Alpha);
end;

procedure TShadowForm.SetShadowSize(const Value: integer);
begin
  FShadowSize := Value;
  FormResize(Self);
end;

end.
I FormCreate sætter vi først nogle default-værdier for størrelse og intensitet af skyggen. Dernæst creater vi først den højre form, sætter dens parent til vores egen form, fjerner borderen, sætter bredden til størrelsen af vores skygge, gør den sort, synlig og translucent som i den første demo. Derefter laver vi den nederste skygge efter samme opskrift. Til sidst kalder vi FormResize for at placere skyggerne korrekt. I FormResize ligger udregningen af placering og størrelse af skygger. Grunden til dette er at disse udregninger skal foretages hver gang vi ændrer på størrelsen af vores vindue. Vi vil også gerne have vores skygger til at flytte rundt sammen med vinduet. Derfor fanger vi WMWindowPosChanged, som bliver sendt hver gang en form ændrer position. Når vi får den skal skyggerne gentegnes, hvilket sker med et kald til resize. Når vi ændrer på skyggens størrelse eller intensitet gennem de to properties, skal der ligeledes gentegnes, hvilket sker i de to set-rutiner.

Nu er vi klar til at bruge vores skygge-form. Start på et nyt program. Tilføj uniten med TShadowForm i uses-linien. Ret "TForm1 = class(TForm)" til "TForm1 = class(TShadowForm)" og kør programmet. Prøv at flytte rundt på vinduet og resize det. størrelse og intensitet kan ændres med ShadowSize := xxx og ShadowIntensity := yyy.

Jeg ved ikke om det her på nogen måde er brugbart, men det er da meget sjovt at lege med... :-) God Fornøjelse.



Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (0)

Du skal være logget ind for at skrive en kommentar.
t