Problème de transparence d'un contrôle

ThWilliam Messages postés 418 Date d'inscription mardi 3 janvier 2006 Statut Membre Dernière intervention 26 novembre 2013 - 20 oct. 2009 à 11:37
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 - 22 oct. 2009 à 06:27
Bonjour à tous.

J'écris un composant transparent dérivé de TCustomControl.
Je ne peux pas le dériver de TGraphicControl, car j'ai besoin d'un contrôle fenêtré.

Cela marche bien, mais j'ai quelques questions :
* si je dessine sur le Canvas en mode Brush.Style = bsClear (par exemple, un texte), j'ai parfois besoin d'effacer le Canvas avant de redessiner. Pour cela, je n'ai trouvé que la méthode RecreateWnd. Est-ce la bonne solution ou qu'ajouter dans WMEraseBkng ?
* Si, à l'exécution, on change la taille du compo, pas de problèmes, il se redessine parfaitement en transparence. Par contre, changer sa position (left, top) exige de faire un RecreateWnd (?).
* le problème de RecreateWnd est qu'il appelle la procedure Paint. Donc impossible à placer dans, p.ex, un événement OnPaint. J'ai essayé en implémentant des procédures BeginUpdate, EndUpdate pour bloquer l'exécution du code dans Paint. Mais impossible de bloquer. Donc évidemment, l'événement OnPaint est rappelé sans arrêt. J'ai trouvé la solution avec un autre événement appelé avant OnPaint. Mais ne trouve pas cela très joli joli.

Ci-dessous la partie du code qui concerne la transparence.

Merci d'avance


Thierry

*************

interface

type

TMyControl = class(TCustomControl)
private
FCaption: string;
FTransparent: boolean;
procedure SetCaption(ACaption: string);
procedure SetTransparent(ATransparent: boolean);
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure Paint; override;
procedure WMEraseBkng(var msg :TWMEraseBkgnd); message WM_ERASEBKGND;
public
constructor Create(AOwner: TComponent); override;
property Canvas;
procedure ReDraw;
published
property Caption: string read FCaption write SetCaption;
property Transparent: boolean read FTransparent write SetTransparent;
end;

implementation

constructor TMyControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FTransparent:= true;
FCaption:= '';
//...
end;

procedure TMyControl.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
if FTransparent then
Params.ExStyle := params.ExStyle or WS_EX_TRANSPARENT;
// apparemment la ligne suivante n'est pas nécessaire
//ControlStyle := ControlStyle - [csOpaque];
end;

procedure TMyControl.CreateWnd;
begin
inherited CreateWnd;
if FTransparent then
begin
SetWindowLong(Parent.Handle, GWL_STYLE,
GetWindowLong(Parent.Handle, GWL_STYLE) and not WS_CLIPCHILDREN);
end;
end;

procedure TMyControl.WMEraseBkng(var msg :TWMEraseBkgnd);
begin
if FTransparent then Msg.Result:= 1 // pas d'effacement
else inherited;
end;

procedure TMyControl.SetTransparent(ATransparent: boolean);
begin
if FTransparent <> ATransparent then
begin
FTransparent:= ATransparent;
Redraw;
end;
end;

procedure TMyControl.SetCaption(ACaption: string);
begin
if FCaption <> ACaption then
begin
FCaption:= ACaption;
ReDraw;
end;
end;

procedure TMyControl.ReDraw;
begin
RecreateWnd;
end;

procedure TMyControl.paint;
begin
//......
end;

11 réponses

ThWilliam Messages postés 418 Date d'inscription mardi 3 janvier 2006 Statut Membre Dernière intervention 26 novembre 2013 4
20 oct. 2009 à 11:48
J'ai oublié de préciser que je travaille en Delphi7 sous XP pro.
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 oct. 2009 à 11:52
Salut,

et si tu fais tout simplement un Canvas.FillRect(aRect); toujours en bsClear avant de changer le texte ?

aRect contient la zone à effacer bien sur :d


[hr]@+Cirec
[hr]
0
ThWilliam Messages postés 418 Date d'inscription mardi 3 janvier 2006 Statut Membre Dernière intervention 26 novembre 2013 4
20 oct. 2009 à 12:09
Merci Cirec,
mais un FillRect en mode bsClear, ne fait malheureusement rien du tout.

A +
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 oct. 2009 à 12:29
ah .. c'est peut être lié au style "WS_EX_TRANSPARENT"
parce que moi je l'utilise souvent pour effacer l'avant plan en mode bsClear !!!


[hr]@+Cirec
[hr]
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Guillemouze Messages postés 991 Date d'inscription samedi 25 octobre 2003 Statut Membre Dernière intervention 29 août 2013 6
20 oct. 2009 à 14:01
@cirec: hmmmmmm en es tu sûr ? il me semble que bsClear signifie que la brush est transparente, donc ne dessine rien (laisse ce qu'il y a derriere et ne redessine pas ce qui devrait theoriquement se trouver derriere). Par exemple, si tu dessine un rect bleu en bsSolid, et que tu redessine un rect bsClear par dessus, il ne va pas remplacer ton rect bleu par l'arriere plan!
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
20 oct. 2009 à 14:53
ha ha ha

vielles croyances qui ont la vie dure ...

j'étais persuadé d'effacer l'avant plan avec ça ...
mais après investigations ... vous avez raison ... ça ne fonctionne pas


bon de toute manière c'était pas ce qu'il demandait ... pour effacer/restituer l'arrière plan tu peux essayer ceci:
la PaintBox représente ton composant transparent
et Handle le composant parent (pour moi le Handle de la fiche).

var aRect: TRect;
begin
aRect := PaintBox1.BoundsRect;
InvalidateRect(Handle, @aRect, true);
end;


peut être que ceci fera l'affaire


[hr]@+Cirec
[hr]
0
ThWilliam Messages postés 418 Date d'inscription mardi 3 janvier 2006 Statut Membre Dernière intervention 26 novembre 2013 4
20 oct. 2009 à 19:20
Re-bonjour Cirec, et re-merci.

InvalidateRect ne marche pas non plus.
Tu me donnes un exemple avec un PaintBox qui est dérivé de TGraphicControl : dans ce cas, il n'y aucun problème pour la transparence. Mais avec un contrôle fenêtré (<- TWinControl), la transparence gérée par Windows me semble très nébuleuse !!!

Je place sur une Form un TImage avec bitmap.
Je place le composant transparent au-dessus de l'image.
Tout marche bien.
Si, en mode exécution, je déplace le composant (MyCompo.Left:= 500), le composant se déplace en gardant en background la portion du bitmap de l'emplacement d'origine ! Il faut donc recréer les paramètres : RecreateWnd fait appel à CreateParams et à CreateWnd. Sacrée façon de gérer la transparence !
D'où ma question: existe-t-il une autre manière de faire que RecreateWnd ?

A +
Thierry
0
ThWilliam Messages postés 418 Date d'inscription mardi 3 janvier 2006 Statut Membre Dernière intervention 26 novembre 2013 4
20 oct. 2009 à 19:25
@Guillemouze : j'adore le commentaire sur ta fiche :

"Si Microsoft inventait un truc qui plante pas, ce serait un clou ".
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
21 oct. 2009 à 10:30
Il existe un moyen, j'y suis parvenu sur un CustomControl sans appels d'API. Il faut que je retrouve ... 1 seconde ...

Dans le Paint (override) du contrôle :

try
  C.Control := self;
  if not FUpdating then // Dessin (le controlcanvas contient l'image qui se trouve "derrière" le contrôle avant dessin).
 finally
  C.Free;
 end;


Il me semble que ça marche comme ça (chez moi en tout cas sous Delphi 6 perso)

Cordialement, Bacterius !
0
ThWilliam Messages postés 418 Date d'inscription mardi 3 janvier 2006 Statut Membre Dernière intervention 26 novembre 2013 4
21 oct. 2009 à 12:51
Merci Bacterius.
Mais créer un nouveau TControlCanvas (nouveau pcq TCustomControl a le sien), n'arrange rien (ou alors j'ai mal compris ta façon de faire).

A +
Thierry
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
22 oct. 2009 à 06:27
Aaah désolé moi je dérivais un TButtonControl (pour un bouton), désolé ... mais je suis sûr qu'il existe un moyen, j'y suis déjà parvenu mais à chaque fois en tâtonnant ... faudrait que je retrouve la méthode.

Cordialement, Bacterius !
0
Rejoignez-nous