Salut à tous!

Pour des besoins perso, j'ai développé un TreeView permettant la gestion de l'alphablending (effet de transparence avec + ou - d'opacité)

Le compo est en plein développement, et j'aurais besoin d'aide pour l'optimiser. Il va sans dire que ce composant est full open-source!!!

Tout d'abord, voici le code du composant (D6 edition perso):
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
unit AlphaTreeView;
 
interface
 
uses
  Windows, Forms, Messages, SysUtils, Classes, Graphics, Controls, ExtCtrls, ComCtrls, StdCtrls;
 
type
  THoundred=0..100;
 
  TAlphaTreeView = class(TTreeView)
  private
    FParentForm:TForm;
    FAlphaBlend: Boolean;
    FAlphaBlendValue: THoundred;
    FDoubleBuffer: TBitmap;
    FOnCustomDraw:TNotifyEvent;
    FOnCustomDrawItem:TNotifyEvent;
    FOnCollapsed:TNotifyEvent;
    FOnExpanded:TNotifyEvent;
    function GetParentForm(Child:TComponent):TForm;
    function CopyControlsImage(Parent:TForm):TBitmap;
    function Alpha(pixcolor,tmpcolor:Byte):Byte;
    //function Test(i:integer):integer;
    procedure CreateDoubleBuffer;
    procedure CustomPaint;
  protected
    procedure Paint;
  public
    constructor Create(AOwner:TComponent); override;
    destructor Destroy; override;
    procedure RefreshData;
    procedure SetAlphaBlend(IsAlphaBlend: Boolean);
    procedure CustDrawButton(ARect: TRect; Node: TTreeNode);
    procedure CustDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
    procedure CustDraw(Sender: TCustomTreeView; const ARect: TRect; var DefaultDraw: Boolean);
    procedure CustRefresh(Sender: TObject; Node: TTreeNode);
  published
    property AlphaBlend:Boolean read FAlphaBlend write FAlphaBlend;
    property AlphaBlendValue:THoundred read FAlphaBlendValue write FAlphaBlendValue;
    property OnCustomDraw : TNotifyEvent read FOnCustomDraw write FOnCustomDraw;
    property OnCustomDrawItem : TNotifyEvent read FOnCustomDrawItem write FOnCustomDrawItem;
    property OnCollapsed : TNotifyEvent read FOnCollapsed write FOnCollapsed;
    property OnExpanded : TNotifyEvent read FOnExpanded write FOnExpanded;
  end;
 
procedure Register;
 
implementation
 
procedure Register;
begin
  RegisterComponents('AlphaComponents', [TAlphaTreeView]);
end;
 
{ TAlphaTreeView }
 
// Méthode invoquée à la création du composant
constructor TAlphaTreeView.Create(AOwner: TComponent);
begin
  inherited;
  FOnCustomDraw:=nil;
  FOnCustomDrawItem:=nil;
  FOnCollapsed:=nil;
  FOnExpanded:=nil;
 
  // Les 4 lignes suivantes permettent d'appeler des méthodes déclanchées par des événements
  Inherited OnCustomDraw:=CustDraw;
  Inherited OnCustomDrawItem:=CustDrawItem;
  Inherited OnCollapsed:=CustRefresh;
  Inherited OnExpanded:=CustRefresh;
 
  // Initialise les options du controle
  FAlphaBlend:=False;
  FAlphaBlendValue:=0;
 
  // Créer un buffer graphique
  FDoubleBuffer:=TBitmap.Create;
  RefreshData;
  Repaint;
end;
 
// Méthode invoquée à la destruction du composant
destructor TAlphaTreeView.Destroy;
begin
  FreeAndNil(FDoubleBuffer);
  inherited;
end;
 
// Procédure qui charge le buffer graphique
procedure TAlphaTreeView.CreateDoubleBuffer;
begin
  FDoubleBuffer.Width:=FParentForm.Width;
  FDoubleBuffer.Height:=FParentForm.Height;
  FDoubleBuffer:=CopyControlsImage(FParentForm);
end;
 
// Procédure qui permet de mettre à jour certaines donnée (buffer...)
procedure TAlphaTreeView.RefreshData;
begin
  FParentForm:=GetParentForm(Self);
  CreateDoubleBuffer;
end;
 
// Fonction qui calcule la valeur RGB 'alphablendée' à appliquer à un pixel
function TAlphaTreeView.Alpha(pixcolor,tmpcolor : Byte) : Byte;
begin
  result := (pixcolor * AlphaBlendValue + (100 - AlphaBlendValue) * tmpcolor) div 100;
end;
 
// Fonction qui récupère dans un canvas (TBitmap) tous les controles de type TImage de la form
function TAlphaTreeView.CopyControlsImage(Parent: TForm): TBitmap;
var I:Word;
    ChildImage:TImage;
begin
  Result:=TBitmap.Create;
  Result.Height:=Parent.ClientHeight;
  Result.Width:=Parent.ClientWidth;
  Result.Canvas.Brush.Color:=Parent.Color;
  Result.Canvas.FillRect(Parent.ClientRect);
 
 // recherche tous les contrôles de type TImage qui sont dans la form
  for I:=0 to Parent.ComponentCount-1 do
  begin
    if (Parent.Components[I] is TImage) then
    begin
      // Copie le canva du TImage dans le canvas du bitmap retourné par la fontion
      ChildImage:=(Parent.Components[I] as TImage);
      Result.Canvas.Draw(ChildImage.Left,ChildImage.Top,ChildImage.Picture.Graphic);
    end;
  end;
end;
 
// Fonction qui permet de récupérer la form du control AlphaTreeview
function TAlphaTreeView.GetParentForm(Child: TComponent): TForm;
begin
  if Child.Owner is TForm then Result:=Child.Owner as TForm
  else Result:=GetParentForm(Child.Owner) as TForm;
end;
 
// Procédure perso pour désinner AlphaTreeView
procedure TAlphaTreeView.CustomPaint;
var  img:TBitmap;
     X,Y: integer;
     pixcol : tcolor;
begin
  // Si la propriété AlphaBlend du controle est vraie
  if (FAlphaBlend) then
  begin
    // Récupère le canvas de la form (juste avec les TImages)
    img:=CopyControlsImage(FParentForm);
 
    if (BorderStyle=bsSingle) then
      BitBlt(Canvas.Handle, 0, 0, Width, Height,img.Canvas.Handle, left+2, top+2, SrcCopy)
    else
      BitBlt(Canvas.Handle, 0, 0, Width, Height,img.Canvas.Handle, left, top, SrcCopy);
 
    img.free;
 
    // Effectue un parcours complet des pixels du canvas d'AlphaTreeView pour appliquer
    // un effet d'AlphaBlending
    for Y := 0 to Height - 1 do
    begin
      for X := 0 to Width - 1 do
      begin
        pixcol := Canvas.Pixels[X,Y];
        Canvas.Pixels[X,Y] := RGB(
          alpha(byte(pixcol),byte(color)),
          alpha(byte(pixcol shr 8),byte(color shr 8)),
          alpha(byte(pixcol shr 16),byte(color shr 16)));
      end;
    end;
  end;
end;
 
// Procédure pour utiliser le double buffer (non utilisé pour le moment)
procedure TAlphaTreeView.Paint;
begin
if (not FAlphaBlend) or (csDesigning in ComponentState) then
  inherited
else
  begin
    CreateDoubleBuffer;
    CustomPaint;
  end;
end;
 
// Procédure utilisée pour dessiner le contrôle
procedure TAlphaTreeView.CustDraw(Sender: TCustomTreeView; const ARect: TRect; var DefaultDraw: Boolean);
begin
  CustomPaint;
end;
 
 
procedure TAlphaTreeView.SetAlphaBlend(IsAlphaBlend: Boolean);
begin
if FAlphaBlend<>IsAlphaBlend then
  begin
    FAlphaBlend:=IsAlphaBlend;
    Invalidate;
  end;
end;
 
 
// Procédure pour dessiner les lignes/boutons de AlphaTreeView
procedure TAlphaTreeView.CustDrawButton(ARect: TRect; Node: TTreeNode);
var
  cx, cy, cx2, cy2 : Integer;
begin
//  cx := ARect.Left + Indent div 2;
//  cy := ARect.Top + (ARect.Bottom - ARect.Top) div 2;
  // cx,cy représente le coin supérieur gauche
  cx := ARect.Left;
  cy := ARect.Top;
 
  with Canvas do
  begin
    Pen.Color := clGray;
 
    // Tout d'abord, si le noeud à des enfants, on dessine un bouton pour étendre/réduire
    if Node.HasChildren then
    begin
      // Dessine le cadre du bouton d'extension/réduction
      cx2:=cx+5;
      cy2:=cy+2;
      PenPos := Point(cx2, cy2);
      LineTo(cx2,cy2+8);
      LineTo(cx2+8,cy2+8);
      LineTo(cx2+8,cy2);
      LineTo(cx2,cy2);
 
      Pen.Color := clBlack;
      // Dessine la barre horizontale ('-')
      PenPos := Point(cx2+2, cy2+4);
      LineTo(cx2+7, cy2+4);
 
      // Dessine la barre verticale si le noeud est réduit ('+')
      if not Node.Expanded then
      begin
        PenPos := Point(cx2+4, cy2+2);
        LineTo(cx2+4, cy2+7);
      end;
      Pen.Color := clGray;
 
      if Node.Parent <> nil then
      begin
        cx2 := cx + 9;
        cy2 := cy - 2;
 
        while (cy2 < cy + 2) do
        begin
          PenPos := Point(cx2,cy2);
          LineTo(cx2,cy2+1);
          cy2 := cy2 + 2;
        end;
      end;
    end
    // Sinon (pas d'enfant), trace une barre verticale en pointillés
    else
    begin
      cx2 := cx + 9;
      if (Node.AbsoluteIndex = 0) then cy2 := cy + 6
      else cy2 := cy - 2;
 
      if (Node.getNextSibling <> nil) then
      begin
        while (cy2 < ARect.Bottom + 3) do
        begin
          PenPos := Point(cx2,cy2);
          LineTo(cx2,cy2+1);
          cy2 := cy2 + 2;
        end;
      end
      else begin
        while (cy2 < cy + 5) do
        begin
          PenPos := Point(cx2,cy2);
          LineTo(cx2,cy2+1);
          cy2 := cy2 + 2;
        end;
      end;
    end;
 
    // Pour tous les noeuds, trace une ligne horizontale en pointillés (entre le bouton et le label du noeud)
    if Node.HasChildren then cx2 := cx + 15
    else cx2 := cx + 9;
    cy2 := cy + 6;
 
    while (cx2 < cx + 18) do
    begin
      PenPos := Point(cx2,cy2);
      LineTo(cx2+1,cy2);
      cx2 := cx2 + 2;
    end;
 
    if ((Node.GetNextVisible <> nil) and (Node.GetNextVisible.Level = Node.Level))
    or (Node.GetNextSibling <> nil) then
    begin
      cx2 := cx + 9;
      cy2 := cy + 12;
      while cy2 < cy + 18 do
      begin
 
        PenPos := Point(cx2, cy2);
        LineTo(cx2,cy2+1);
        cy2 := cy2 + 2;
      end;
    end;
 
    // Connecte les sous-noeuds au noeud parent
    Node := Node.Parent;
    if Node <> nil then
    begin
      cx2 := 9;
      cy2 := ARect.Top - 2;
      while (cy2 < ARect.Bottom - 1) do
      begin
        PenPos := Point(cx2, cy2);
        LineTo(cx2, cy2 + 1);
        cy2 := cy2 + 2;
      end;
    end;
  end;
  inherited
end;
 
// Procédure pour dessiner les noeuds de AlphaTreeView
procedure TAlphaTreeView.CustDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
var
  NodeRect: TRect;
begin
  DefaultDraw := false; // nécessaire pour forcer le dessin manuel des items
  with Canvas do
  begin
    if cdsSelected in State then
    begin
      NodeRect := Node.DisplayRect(True);
      FillRect(NodeRect);
    end;
    NodeRect := Node.DisplayRect(False);
 
    Brush.Style := bsClear;
 
    NodeRect.Top := NodeRect.Top+1;
    NodeRect.Left := NodeRect.Left + (Node.Level * Indent);
    // Appel à la procédure de dessin des lignes
    CustDrawButton(NodeRect, Node);
 
    NodeRect.Left := NodeRect.Left + Indent;
 
    TextOut(NodeRect.Left, NodeRect.Top, Node.Text);
  end;
  inherited
end;
 
procedure TAlphaTreeView.CustRefresh(Sender: TObject; Node: TTreeNode);
begin
  Repaint;
end;
 
end.
J'aurais besoin d'aide pour plusieurs trucs:
- Le premier, c'est qu'en cours d'exécution, ça fonctionne bien sauf que c'est lent: effet de clipping quand on étend/réduit l'arbre et autre trucs de ce genre
- Ensuite, pour le moment, je ne suis capable que d'afficher par transaprence les composants de type TImage (pas de boutons ni rien...) J'ai bien tenté de faire une copie du canvas de la form, mais sur la zone d'AlphaTreeView, ça le fait pas, et si je masque le treeview le temps de capturer la form, le fait de l'afficher après appelle la procédure de rafraichissement de la form, qui appelle le redessin du treeview etc, donc clipping pourri!

Merci pour vos commentaires et votre aide, je reste à votre disposition si vous avez besoin d'infos complémentaires!