// Ich benötigte eine Möglichkeit, zur Laufzeit eine durchbrochene
//
(transparente) Bitmap mit der Maus innerhalb festgelegter Grenzen
// über ein Formular ziehen zu können, wobei sich die Bitmap über ein
//
TRichedit legen musste. Damit schloss ein TImage als Komponente
// aus. Also wurde die folgende Komponenete entwickelt. Ist
//
Transparent auf TRUE gesetzt, stößt erst die erste sichtbare Farbe
// an die Grenze
(effektive Breite), bei Transparent = FALSE bereits
// schon der Bitmaprand
(siehe Abbildung).
// Hinweis:
// Steht
SchiebenErlaubt auf FALSE oder ist die Komponente disabled,
// kann nicht geschoben werden.


// Getestet mit D4 unter XP

unit Schieber; 
 
interface 
 
uses 
  Windows, Messages, SysUtils, Classes, Graphics, Controls, StdCtrls; 
 
type 
  TSchieber = class(TWinControl) 
  private 
    FLeft, FTop, FRight, FBottom, FDo, FDl, FDr, FDu: Integer; 
    FTransparent, FErlaubt, FSchiebung, FAnders: boolean; 
    FRegion1, FRegion2: HRgn; 
    FBitmap: TBitmap; 
    FColor: TColor; 
    FPunkt: TPoint; 
    FDc: HDC; 
  protected 
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; 
    procedure MouseDown(Button: TMouseButton; 
      Shift: TShiftState; X, Y: Integer); override; 
    procedure MouseUp(Button: TMouseButton; 
      Shift: TShiftState; X, Y: Integer); override; 
    procedure paint(var M: TMessage); message wm_paint; 
    procedure setBottom(i: integer); 
    procedure setRight(i: integer); 
    procedure settrans(b: boolean); 
    procedure setLeft(i: integer); 
    procedure setcolor(c: TColor); 
    procedure setTop(i: integer); 
    procedure setbm(b: TBitmap); 
    procedure loaded; override; 
    procedure Resize; override; 
    procedure BuildRegion; 
    procedure setFarbe; 
    procedure region; 
    procedure gross; 
  public 
    constructor Create(Owner: TComponent); override; 
    destructor Destroy; override; 
  published 
    property SchiebenErlaubt: boolean read FErlaubt write FErlaubt; 
    property Transparent: boolean read FTransparent write settrans; 
    property TransparentColor: TColor read FColor write setcolor; 
    property GrenzeUnten: Integer read FBottom write setBottom; 
    property GrenzeRechts: Integer read FRight write setRight; 
    property GrenzeLinks: Integer read FLeft write setLeft; 
    property GrenzeOben: Integer read FTop write setTop; 
    property Bitmap: TBitmap read FBitmap write setbm; 
    property OnMouseDown; 
    property OnMouseMove; 
    property OnDblClick; 
    property PopupMenu; 
    property OnMouseUp; 
    property ShowHint; 
    property Visible; 
    property Enabled; 
    property OnClick; 
  end; 
 
procedure Register; 
 
implementation 
 
procedure Register; 
begin 
  RegisterComponents('DBR', [TSchieber]); 
end; 
 
procedure TSchieber.BuildRegion; 
var p: PBytearray; 
  x, y: integer; 
  ro, gr, bl: byte; 
  F: TColor; 
  function kombine(a: integer): integer; 
  var b, c: integer; 
  begin 
    b := -1; 
    while a < FBitmap.width * 3 do begin 
      if (p[a] <> bl) or (p[a + 1] <> gr) or (p[a + 2] <> ro) 
        then begin 
        b := a div 3; 
        if FDo < 0 then FDo := y; 
        if b < FDl then FDl := b; 
        FDu := height; 
        break; 
      end; 
      inc(a, 3); 
    end; 
    if b < 0 then begin 
      if FDu = height then FDu := y; 
      result := a; 
      exit; 
    end; 
    while a < FBitmap.width * 3 do begin 
      if (p[a] = bl) and (p[a + 1] = gr) and (p[a + 2] = ro) 
        then begin 
        break; 
      end; 
      inc(a, 3); 
    end; 
    c := a div 3; 
    if c > FDr then FDr := c; 
    result := a; 
    FRegion2 := CreateRectRgn(b, y, a div 3, succ(y)); 
    CombineRgn(FRegion1, FRegion1, FRegion2, RGN_OR); 
    DeleteObject(FRegion2); 
  end; 
begin 
  FBitmap.pixelformat := pf24bit; 
  F := ColorToRGB(FColor); 
  ro := getrvalue(F); 
  gr := getgvalue(F); 
  bl := getbvalue(F); 
  FRegion1 := CreateRectRgn(0, 0, 0, 0); 
  for y := 0 to pred(FBitmap.height) do begin 
    p := FBitmap.ScanLine[y]; 
    x := 0; 
    while x < FBitmap.width * 3 do x := kombine(x); 
  end; 
  FDr := width - FDr; 
  FDu := pred(height - FDu); 
end; 
 
constructor TSchieber.Create(Owner: TComponent); 
begin 
  inherited Create(Owner); 
  Fanders := false; 
  Fleft := -1000000000; 
  Ftop := -1000000000; 
  Fright := 1000000000; 
  Fbottom := 1000000000; 
  FBitmap := TBitmap.create; 
  FErlaubt := true; 
  FColor := clBtnFace; 
  Color := clBlack; 
end; 
 
destructor TSchieber.Destroy; 
begin 
  FBitmap.Free; 
  deleteobject(FRegion1); 
  inherited Destroy; 
end; 
 
procedure TSchieber.MouseDown(Button: TMouseButton; 
  Shift: TShiftState; X, Y: Integer); 
begin 
  FPunkt.X := X; 
  FPunkt.Y := Y; 
  inherited; 
  FSchiebung := FErlaubt and Enabled; 
end; 
 
procedure TSchieber.MouseUp(Button: TMouseButton; 
  Shift: TShiftState; X, Y: Integer); 
begin 
  inherited; 
  FSchiebung := false; 
end; 
 
procedure TSchieber.MouseMove(Shift: TShiftState; X, Y: Integer); 
var T, L: integer; 
begin 
  if FSchiebung then begin 
    T := Top - FPunkt.y + y; 
    L := Left - FPunkt.x + x; 
    if T < Ftop - FDo then T := Ftop - FDo else 
      if T + height - FDu > Fbottom then 
        T := Fbottom - height + FDu; 
    if L < Fleft - FDl then L := Fleft - FDl else 
      if L + width - FDr > Fright then 
        L := Fright - width + Fdr; 
    SetBounds(L, T, Width, Height); 
  end; 
  inherited; 
end; 
 
procedure TSchieber.paint(var M: TMessage); 
begin 
  inherited; 
  FDc := GetDc(self.handle); 
  BitBlt(FDc, 0, 0, FBitmap.width, FBitmap.height, 
    FBitmap.canvas.handle, 0, 0, srccopy); 
  DeleteDc(FDc); 
end; 
 
procedure TSchieber.region; 
begin 
  if FTransparent and not FBitmap.empty then begin 
    FDo := -1; 
    FDl := width; 
    FDu := height; 
    FDr := FDo; 
    BuildRegion; 
    setwindowRgn(handle, FRegion1, true); 
  end else begin 
    FDo := 0; 
    FDu := FDo; 
    FDl := FDo; 
    FDr := FDo; 
    deleteobject(FRegion1); 
    setwindowRgn(handle, 0, true); 
  end; 
  invalidate; 
end; 
 
procedure TSchieber.gross; 
begin 
  if FBitmap.empty then begin 
    width := 30; 
    height := 20; 
  end else begin 
    width := FBitmap.width; 
    height := FBitmap.height; 
  end; 
end; 
 
procedure TSchieber.setFarbe; 
begin 
  FColor := FBitmap.TransparentColor; 
end; 
 
procedure TSchieber.setbm(b: TBitmap); 
begin 
  FBitmap.assign(b); 
  gross; 
  if FBitmap.empty then FColor := clBtnFace 
  else setfarbe; 
  region; 
end; 
 
procedure TSchieber.settrans(b: boolean); 
begin 
  if b = FTransparent then exit; 
  FTransparent := b; 
  if not FBitmap.empty and (FColor = clBtnFace) 
    and b then setfarbe; 
  region; 
  FAnders := true; 
  setRight(FRight); 
  setLeft(FLeft); 
  setBottom(FBottom); 
  setTop(FTop); 
  FAnders := false; 
end; 
 
procedure TSchieber.Loaded; 
begin 
  inherited Loaded; 
  region; 
end; 
 
procedure TSchieber.resize; 
begin 
  gross; 
end; 
 
procedure TSchieber.setcolor(c: TColor); 
begin 
  if c = FColor then exit; 
  FColor := c; 
  region; 
end; 
 
procedure TSchieber.setLeft(i: integer); 
begin 
  if (i = FLeft) and not FAnders then exit; 
  FLeft := i; 
  if left + FDl < FLeft then left := FLeft - FDl; 
end; 
 
procedure TSchieber.setTop(i: integer); 
begin 
  if (i = FTop) and not FAnders then exit; 
  FTop := i; 
  if top + FDo < FTop then top := FTop - Fdo; 
end; 
 
procedure TSchieber.setRight(i: integer); 
begin 
  if (i = FRight) and not FAnders then exit; 
  FRight := i; 
  if left + width - FDr > FRight then left := i - width + FDr; 
end; 
 
procedure TSchieber.setBottom(i: integer); 
begin 
  if (i = FBottom) and not FAnders then exit; 
  FBottom := i; 
  if top + height - FDu > FBottom then top := i - height + FDu; 
end; 
 
end.



 

Zugriffe seit 6.9.2001 auf Delphi-Ecke