2009-05-11 8 views
1

Ich habe eine Komponente (Abstieg von TPanel), wo ich Transparenz und BrushStyle (mit TImage) Eigenschaften implementiert.Delphi-Komponente nicht gemalt

Alles ist in Ordnung, wenn ich eine Komponente dieses Typs auf dem Formular habe. Brötchen, wenn ich auf das Formular mehr Komponenten dieses Typs nur die erste sichtbare Komponente bemalen. Wenn das Formular verschoben und die erste Komponente unter einem anderen Fenster oder außerhalb des Desktops angezeigt wird, wird die nächste Komponente angezeigt.

unit TransparentPanel; 

interface 
uses 
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
    ExtCtrls, stdctrls; 

type 
    TTransparentPanel = class(TPanel) 
    private 
    FTransparent: Boolean; 
    FBrushStyle: TBrushStyle; 
    FImage: TImage; 

    procedure SetTransparent(const Value: Boolean); 
    procedure SetBrushStyle(const Value: TBrushStyle); 
    protected 
    procedure CreateParams(var Params: TCreateParams); override; 
    procedure Paint; override; 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    published 
    property Transparent: Boolean read FTransparent write SetTransparent default 
     True; 
    property BrushStyle: TBrushStyle read FBrushStyle write SetBrushStyle default 
     bsBDiagonal; 
    end; 

procedure Register; 

implementation 

procedure Register; 
begin 
    RegisterComponents('TransparentPanel', [TTransparentPanel]); 
end; 

constructor TTransparentPanel.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 

    FTransparent := True; 
    FBrushStyle := bsBDiagonal; 

    FImage := TImage.Create(Self); 
    FImage.Align := alClient; 
    FImage.Parent := Self; 
    FImage.Transparent := FTransparent; 
end; 

procedure TTransparentPanel.CreateParams(var Params: TCreateParams); 
begin 
    inherited CreateParams(Params); 
    if ((not (csDesigning in ComponentState)) and FTransparent) then 
    Params.ExStyle := Params.ExStyle or WS_EX_TRANSPARENT; 
end; 

destructor TTransparentPanel.Destroy; 
begin 
    if Assigned(FImage) then 
    FreeAndNil(FImage); 

    inherited Destroy; 
end; 

procedure TTransparentPanel.Paint; 
var 
    XBitMap, 
    BitmapBrush: TBitmap; 
    XOldDC: HDC; 
    XRect: TRect; 
    ParentCanvas: TCanvas; 
begin 
    {This panel will be transparent only in Run Time} 
    if (csDesigning in ComponentState) or (not FTransparent) or (FBrushStyle in [bsClear, bsSolid]) then 
    inherited Paint 
    else 
    begin 
    XRect := ClientRect; 
    XOldDC := Canvas.Handle; 
    XBitMap := TBitmap.Create; 
    BitmapBrush := TBitmap.Create; 
    try 
     XBitMap.Height := Height; 
     XBitMap.Width := Width; 
     Canvas.Handle := XBitMap.Canvas.Handle; 
     inherited Paint; 
     RedrawWindow(Parent.Handle, @XRect, 0, 
     RDW_ERASE or RDW_INVALIDATE or 
     RDW_NOCHILDREN or RDW_UPDATENOW); 

     BitmapBrush.Width := FImage.Width; 
     BitmapBrush.Height := FImage.Height; 

     BitmapBrush.Canvas.Brush.Color := clBlack; 
     BitmapBrush.Canvas.Brush.Style := FBrushStyle; 
     SetBkColor(BitmapBrush.Canvas.Handle, clWhite); 
     BitmapBrush.Canvas.FillRect(BitmapBrush.Canvas.ClipRect); 

     FImage.Canvas.Draw(0, 0, BitmapBrush); 
    finally 
     Canvas.Handle := XOldDC; 
     Canvas.BrushCopy(XRect, XBitMap, XRect, Color); 
     XBitMap.Free; 
     BitmapBrush.Free; 
    end; 
    end; 
end; 

procedure TTransparentPanel.SetBrushStyle(const Value: TBrushStyle); 
begin 
    if (FBrushStyle <> Value) then 
    begin 
    FBrushStyle := Value; 
    Invalidate; 
    end 
end; 

procedure TTransparentPanel.SetTransparent(const Value: Boolean); 
begin 
    if (FTransparent <> Value) then 
    begin 
    FTransparent := Value; 
    FImage.Transparent := Value; 
    Invalidate; 
    end; 
end; 

end. 

Was ist los?

+1

Ihr Code hat viele Probleme, aber es ist schwer, Ihnen zu helfen, ohne zu wissen, was die Steuerung tun soll. Könnten Sie bitte etwas mehr Details geben? – mghie

Antwort

5

OK, ein paar Tipps:

  • nur eine Komponente gezogen wird, weil während des Client-Bereichs des Steuer Malerei wieder für ungültig erklärt, so dass man einen unendlichen Strom von WM _ Nachrichten PAINT erstellen, und die zweite Komponente wird nie gezeichnet. Bis der erste unsichtbar wird, wie du es beschreibst. Sie können dies anhand der CPU-Last sehen, wenn eine Ihrer Komponenten in einem Formular 100% eines Kerns auf meinem System verwendet (Delphi 2007, Komponente, die zur Laufzeit erstellt wurde).

  • Sie sollten versuchen, die Bitmap, in die Sie zeichnen, zu entfernen und stattdessen die DoubleBuffered-Eigenschaft zu verwenden.

  • Wofür wird FImage tatsächlich verwendet?

  • Wenn Sie die Erstellungs-Parameter abhängig vom Wert der Eigenschaft Transparent ändern, müssen Sie das Fenster-Handle neu erstellen, wenn sich die Eigenschaft ändert.

  • Vielleicht können Sie die Komponente komplett loswerden und stattdessen eine TPaintBox verwenden? Es ist transparent, solange Sie den Hintergrund nicht selbst malen. Aber ich kann nicht aus deinem Code ersehen, was du eigentlich erreichen willst, also ist es schwer zu sagen.

4

Ich denke, Sie ein Steuerelement mögen, die anderen Steuerelemente enthalten kann - wie TPanel tun kann - und eine Steuerung, die den Inhalt des Fensters darunter angezeigt werden kann - wie TImage tun können, wenn seine Transparent Eigenschaft festgelegt ist. Es scheint, dass Sie unter dem falschen Eindruck geraten, dass Sie das Verhalten beider kombiniert erhalten, wenn Sie ein Steuerelement übereinander legen. Das ist was ist falsch.

Zuerst sollten Sie die TImage Kontrolle loswerden. Das macht die Dinge nur komplizierter, als sie sein müssen. Wenn Sie ein Malwerkzeugmuster auf dem Panel zeichnen müssen, zeichnen Sie es direkt auf das Panel.

Als nächstes erkennen, dass die ws_ex_Transparent Fenster Stil steuert, ob Geschwister des Fensters zuerst gemalt werden. Das sagt nichts darüber aus, ob die übergeordnete des Fensters neu lackiert wird. Wenn das übergeordnete Element Ihres Bedienfelds die ws_ClipChildren-Formatvorlage festgelegt hat, wird es sich nicht unter der Stelle, an der sich Ihr Bedienfeld befindet, aufmalen. Es sieht so aus, als ob es Ihnen helfen würde, wenn das übergeordnete Element des Panel-Steuerelements den ws_ex_Composited-Stil festgelegt hätte, aber als Komponentenschreiber erhalten Sie nicht die Kontrolle über die übergeordneten Elemente Ihrer Steuerelemente.

TImage kann transparent angezeigt werden, da es kein Fenstersteuerelement ist. Es hat kein Fenster-Handle, daher gelten die OS-Regeln zum Malen und Clippen nicht für dieses Element.Aus Sicht von Windows existiert TImage überhaupt nicht. Was wir in der Delphi-Welt als die TImage Malerei selbst wahrnehmen, ist wirklich das Elternfenster, das auf eine separate Subroutine verweist, um eine bestimmte Region des Elternfensters zu zeichnen. Aus diesem Grund kann der Malcode TImage einfach nicht über den Bereich der Eltern übermalen.

Wenn ich das täte, würde ich mich fragen, ob die Steuerung mit dem Pinselmuster wirklich eine Behälterkontrolle sein musste. Kann ich stattdessen einfach eine gewöhnliche TImage mit einem wiederholten Pinselmuster darauf gezeichnet? Andere Steuerelemente können noch darüber hinausgehen, aber sie werden nicht als untergeordnete Elemente der Mustersteuerung betrachtet.

0

Versuchen am Graphics32 library aussehen: es Zeichnung Dinge sehr gut ist und arbeitet große mit Bitmaps und Transparenz

0

Wenn Sie die Platte transparent sein wollen, alles, was Sie tun müssen, außer Kraft zu setzen Paint ist und nichts tun (Oder zeichne ein transparentes Bild zum Beispiel), und fange auch die WM_ERASEBKGND-Nachricht und mache auch hier nichts. Dies stellt sicher, dass sich das Panel überhaupt nicht malt.

Stellen Sie sicher, dass auch das csOpaque-Flag von ControlStyle ausgeschlossen wird, damit das übergeordnete Element weiß, dass es sich unterhalb des Bedienfelds malt.

Das Zeug, das Sie in Paint haben, ist übrigens absolut schrecklich (ich meine das RedrawWindow-Ding). Werde es los. Und WS_EX_TRANSPARENT ist nur für Toplevel-Fenster gedacht, nicht für Steuerelemente.