2009-05-11 17 views
1

J'ai un composant (descendant de TPanel) dans lequel j'ai implémenté les propriétés Transparency et BrushStyle (en utilisant TImage).Composant Delphi non peint

Tout est ok quand j'ai un composant de ce type sur le formulaire. Bun quand je punis sur la forme plus de composants de ce type seulement le premier composant visible est peint. Lorsque le formulaire est déplacé et que le premier composant se trouve sous une autre fenêtre ou à l'extérieur du bureau, le composant suivant est peint.

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. 

Qu'est-ce qui ne va pas?

+1

Votre code a beaucoup de problèmes, mais il est difficile de vous aider sans savoir ce que le contrôle devrait faire. Pourriez-vous s'il vous plaît fournir plus de détails? – mghie

Répondre

5

OK, quelques conseils:

  • Un seul élément est tiré, car au cours de la peinture de la zone client du contrôle est invalidée à nouveau, si vous créez un flux infini de WM _ PEINTURE messages, et le deuxième composant ne se dessine jamais. Jusqu'à ce que le premier soit rendu invisible, comme vous le décrivez. Vous pouvez le voir à partir de la charge du processeur, en ayant un de vos composants sur un formulaire utilise 100% d'un noyau sur mon système (Delphi 2007, composant créé à l'exécution).

  • Vous devez essayer de supprimer le bitmap dans lequel vous dessinez et utiliser à la place la propriété DoubleBuffered.

  • À quoi FImage est-il réellement utilisé? Si vous modifiez les paramètres de création en fonction de la valeur de la propriété Transparent, vous devez recréer le handle de fenêtre lors de la modification de la propriété. Peut-être que vous pouvez vous débarrasser complètement du composant et utiliser un TPaintBox à la place? Il est transparent tant que vous ne peignez pas l'arrière-plan vous-même. Mais je ne peux pas dire à partir de votre code ce que vous voulez vraiment réaliser, donc c'est difficile à dire.

4

Je pense que vous voulez un contrôle qui peut contenir d'autres contrôles - comme TPanel peut faire - et un contrôle qui permet d'afficher le contenu de la fenêtre en dessous - comme TImage peut faire lorsque sa Transparent propriété est définie. Il semble que vous ayez l'impression erronée que si vous mettez un contrôle au-dessus d'un autre, vous obtiendrez le comportement des deux combinés. C'est qu'est-ce qui ne va pas?

La première chose à faire est de se débarrasser du contrôle TImage. Cela rend les choses plus compliquées qu'elles ne devraient l'être. Lorsque vous devez dessiner un motif de brosse sur le panneau, dessinez-le directement sur le panneau.

Ensuite, réalisez que le style de fenêtre ws_ex_Transparent détermine si les frères et sœurs de la fenêtre sont peints en premier. Cela ne dit rien à savoir si le parent de la fenêtre est repeint. Si le parent de votre panneau a le jeu de style ws_ClipChildren, il ne se dessinera pas en dessous de l'emplacement supposé de votre panneau. Il semblerait que cela vous aiderait si le parent de votre contrôle de panneau avait le jeu de style ws_ex_Composited, mais en tant que rédacteur de composant, vous n'avez pas le contrôle sur les parents de vos contrôles.

TImage est transparent, car il ne s'agit pas d'un contrôle fenêtré. Il n'a pas de poignée de fenêtre, donc les règles du système d'exploitation concernant la peinture et le découpage ne s'appliquent pas.Du point de vue de Windows, TImage n'existe pas du tout. Ce que nous percevons dans le monde Delphi comme la peinture TImage est en fait la fenêtre parente se reportant à un sous-programme séparé pour peindre une certaine région de la fenêtre parente. À cause de cela, le code de peinture TImage ne peut simplement pas peindre sur une partie de la zone des parents. Si je faisais ceci, je me demanderais si le contrôle avec le modèle de brosse devait vraiment être un contrôle de récipient. Pourrais-je simplement utiliser un TImage ordinaire avec un motif de pinceau répétitif dessiné dessus? Les autres contrôles peuvent toujours être placés dessus, mais ils ne seront pas considérés comme des enfants du contrôle de pattern.

0

Essayez de regarder le Graphics32 library: il est très bon dans les choses de dessin et travaille grande avec bitmaps et transparence

0

Si vous voulez que le panneau soit transparent, tout ce que vous devez faire est prioritaire Peinture et ne rien faire (ou peindre une image transparente, par exemple), et aussi attraper le message WM_ERASEBKGND et ne rien faire ici aussi. Cela garantit que le panneau ne se peint pas du tout.

Assurez-vous également d'exclure l'indicateur csOpaque de ControlStyle, afin que le parent sache qu'il doit se placer sous le panneau. Le truc que vous avez dans Paint est absolument horrible, d'ailleurs (je veux dire la chose RedrawWindow). Débarrassez-vous de cela. Et WS_EX_TRANSPARENT est destiné uniquement aux fenêtres de niveau supérieur, pas aux contrôles.