madcap
Messages postés77Date d'inscriptionmercredi 15 mars 2006StatutMembreDernière intervention22 février 2011
-
29 mai 2009 à 14:40
madcap
Messages postés77Date d'inscriptionmercredi 15 mars 2006StatutMembreDernière intervention22 février 2011
-
2 juin 2009 à 16:47
Bonjour à tous,
Depuis ce matin, je cherche une solution pour dessiner un rond sur une image. J'ai réussi à le faire, par contre ce que j'aimerais c'est qu'il se fasse au clic de la souris et se place à l'endroit où a cliquer l'utilisateur.
L'idéal après serait que l'on puisse également déplacer ce rond pour ajuster le positionnement sur l'image. Et là, je suis vraiment perdu...
Voici déjà le code que j'ai pour dessiner le rond dans mon image :
procedure TFormGestion.JvImageCorpsHumainMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
JvImageCorpsHumain.Canvas.Brush.Color := clBlue;
JvImageCorpsHumain.Canvas.Font.Size := 15;
JvImageCorpsHumain.Canvas.Ellipse(0,0,15,15); //Ici je décide où je veux mettre mon ellipse
Donc logiquement, pour que mon ellipse se place à l'endroit du clic de la souris, au lieu des valeurs 0,0,15,15 de la fonction Ellipse, je mets :
JvImageCorpsHumain.Canvas.Ellipse(Mouse.CursorPos.X - JvImageCorpsHumain.Left, Mouse.CursorPos.Y - JvImageCorpsHumain.Top,
Mouse.CursorPos.X - JvImageCorpsHumain.Left + 15, Mouse.CursorPos.Y - JvImageCorpsHumain.Top + 15);
Ainsi je récupère les coordonnées de ma souris et je les soustraits aux coordonnées de mon objet Image pour que j'aie les coordonnées à l'intérieur de l'image, mais apparemment ça fonctionne pas, pask j'ai rien qui se dessine
Y'a un truc que je dois faire de faux, est-ce que qqun à une idée ?
JulioDelphi
Messages postés2226Date d'inscriptiondimanche 5 octobre 2003StatutMembreDernière intervention18 novembre 201014 29 mai 2009 à 15:38
Salut
Tu as presque tout bon ! Tu dois aussi prendre en compte la place de la fenetre ! donc "- Form1.Left" et idem avec top.
Imagine tu es en résolution 800*600, ta souris se trouve en 400*300 (pile au milieu). Ta fenetre se trouve en 200*200 (haut gauche), ton image (quit fait 150*150, mais cela est pas important ici) en 10*10 (dans la fenetre, donc en 200+10*200+10 sur l'écran) et le clic de souris se fait en 20*20 dans l'image (donc en 20+10*20+10 selon le coin de la fenetre, soit en 200+20+10*200+20+10 selon le coin de la fenetre).
Petit screen (j'ai dessiné un curseur sous paint ^^) :
la souris se trouve en 20*20 sur le TImage
la souris se trouve en 40*40 sur la form
la souris se trouve en 200*200 sur mon écran.
si je clic ma souris aura comme coordonnées 260*260 sur mon écran
ça donne donc :
delphi > mouse.x - form.left - image.left = position exacte !
math > 260 - 200 - 40 = 20 !
f0xi
Messages postés4204Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202234 30 mai 2009 à 13:17
fMsPos de type TPoint permet de recuperer la position de la souris sur la paintbox. cette variable est mise a jour dans l'evenement OnMouseMove de TPaintBox.
fMsSize de type integer est la taille (rayon) de l'ellipse dessinée pour remplacer le curseur de la souris. cela te permet de voir comment remplacer le curseur et d'en dessiner un autre.
fMsDown de type boolean (defaut = false) est la variable qui control le dessin de l'ellipse de selection, dessin si true.
fMsDPos de type TPoint est la position sauvegardée du click souris afin de savoir ou dessiner l'ellipse de selection.
fMsDown et fMsDPos sont initialisé dans la procedure OnClick de la paintbox.
fMsDSize de type integer est la taille (rayon) de l'ellipse de selection.
fMsPos, fMsSize, fMsDown, fMsDPos, fMsDSize sont privée et ne sont utilisée qu'en interne dans la classe TFormX.
fACTB type boolean (defaut = true) (fAutomaticConvertToBitmap) control la convertion automatique du Graphic contenu dans fPicture dans le Bitmap de fPicture. qu'on charge une image JPG, PNG, GIF ou BMP cela fonctionne a tout coups. par contre, si l'on desire avoir la transparence du PNG il faut invalider fACTB (=false) et activé fUGFX (=true) afin d'utiliser fPicture.Graphic plutot que fPicture.Bitmap.
fUGFX type boolean (defaut = false) indique si il faut utilise le Graphic de fPicture (=true) ou le Bitmap de fPicture (=false), pour fUGFX = false il est conseillé de mettre fACTB=true, elle se modifie via la propriété UseGraphic.
fPicture type TPicture, permet de charger une image dans n'importe quel format enregistré auprés de Delphi. fPicture nous permet d'avoir directement un composant fonctionnel non visible pour traiter les images. mieux que d'utiliser un TImage invisible ou une instance particuliere de TGraphic.
On placera donc notre image de fond dans fPicture via la methode LoadFromFile ou LoadFromResource.
fPicture s'utilise via la propriété Picture.
la procedure SetACTB permet de controler la modification de valeur de fACTB via la propriété AutomaticConvertToBitmap et de declencher automatiquement la convertion de Graphic vers Bitmap dans fPicture par la procedure ConvertPictureToBitmap si fACTB est passé a True.
la procedure SetPicture permet de controler la modification de fPicture via la propriété Picture, SetPicture declenche la ConvertToBitmap si fACTB=true.
les procedure contenue dans le gestionnaire d'evenement Paint de PaintBox, sont un exemple de possibilité, effectivement le code qu'elles contiennent pourrais etre placé directement dans la methode de dessin afin d'eviter plusieurs Call qui sont assé long a traiter.
On peut egalement, depuis Delphi 2005/2006 indiquer la directive Inline derriere les procedures, cette directive agit de la même façon que si nous copions le code directement dans la methode de dessin. Inline genere un code plus lourd mais egalement plus rapide. cela permet de controller correctement le rapport Poid/Performance de l'application.
on peu aisement remplacer SavePB et RestorePB par :
on peu egalement appliquer ce principe a la plupart des objets contenus dans les composant, tel que TFont ou tout autre classe decendant de TPersistent, on pourrait egalement créer une liste pour appliquer un principe Push/Pop sur TPen et TBrush, mais la ça devient plus compliqué.
pour le reglage du timer :
40ms = 25 FPS
45ms = 22.2223 FPS (~23FPS)
50ms = 20 FPS
il n'est pas utilise de descendre en dessous de 40ms. 50ms est un bon compromis fluidité/perf
Pour une fiche il y a deux façon d'indiquer des variables et methodes.
Qu'est ce qu'une fiche ? c'est tout simplement un composant dérivé de la classe TForm et il faut réellement la voir comme telle (une classe).
Si nous definissont des methodes et variables globale (partie implementation) cela crée des dependances qui ne sont pas forcement compatible avec les applications Threadées (voir l'aide delphi sur la directive ThreadVar).
On peu egalement donc considéré notre fiche comme une simple classe, un simple composant, auquel on vas ajouté des methodes, des variables et des propriétés. on utilisera donc les champs Private, Protected et Public de notre fiche, comme je l'ai fait dans ce cas.
a savoir que :
Private contiendra les variables (f) et methodes de propriété (Set et Get)
Protected contiendra les methodes de traitement interne de la classe et les propriétés "cachés" si besoin
Public contiendra les methodes de traitement et propriétés visibles.
procedure TForm1.FormDestroy(Sender: TObject);
begin
{ your code here! }
// ----------
fPicture.Free;
end;
procedure TForm1.SetACTB(const Value: Boolean);
{ do not modify }
begin
if Value <> fACTB then
begin
fACTB := Value;
if fACTB then
ConvertPictureToBitmap;
end;
end;
procedure TForm1.SetPicture(Value: TPicture);
{ do not modify }
begin
fPicture.Assign(Value);
if fACTB then
ConvertPictureToBitmap;
end;
procedure TForm1.ConvertPictureToBitmap;
{ do not modify }
begin
if fPicture.Bitmap.Empty then
begin
fPicture.Bitmap.Width := fPicture.Width;
fPicture.Bitmap.Height:= fPicture.Height;
fPicture.Bitmap.PixelFormat := pf32bit;
fPicture.Bitmap.Canvas.Draw(0,0,fPicture.Graphic);
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
{ code before draw, here! }
// ----------
PaintBox1.Refresh;
// ----------
{ code after draw, here! }
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
{ do not modify }
var GfxObj : TGraphic;
OldPen : TPen;
OldBrush : TBrush;
procedure SavePB(const SavePen: boolean=true; const SaveBrush: boolean=true);
begin { Save canvas Pen or Brush or both }
if SavePen then OldPen.Assign((Sender as TPaintBox).Canvas.Pen);
if SaveBrush then OldBrush.Assign((Sender as TPaintBox).Canvas.Brush);
end;
procedure RestorePB(const RestorePen: boolean=true; const RestoreBrush: boolean=true);
begin { Restore canvas Pen or Brush or both }
if RestorePen then (Sender as TPaintBox).Canvas.Pen.Assign(OldPen);
if RestoreBrush then (Sender as TPaintBox).Canvas.Brush.Assign(OldBrush);
end;
begin
OldPen := TPen.Create;
OldBrush := TBrush.Create;
try
with (Sender as TPaintBox).Canvas do
begin
// Draw picture
case fUGFX of
false: GfxObj := TGraphic(fPicture.Bitmap);
true : GfxObj := fPicture.Graphic
end;
if not GfxObj.Empty then
Draw(0,0,GfxObj);
// ------------
{ over picture and under selection ellipse, draw here! }
// Draw selection ellipse
if fMsDown then
begin
SavePB;
Pen.Width := 2;
Pen.Color := clBlue;
Brush.Style := bsClear;
Ellipse(fMsDPos.X-fMsDSize, fMsDPos.Y-fMsDSize,
fMsDPos.X+fMsDSize, fMsDPos.Y+fMsDSize);
RestorePB;
end;
// ------------
{ over picture and selection ellipse, draw here! }
madcap
Messages postés77Date d'inscriptionmercredi 15 mars 2006StatutMembreDernière intervention22 février 2011 29 mai 2009 à 15:51
Oui j'ai tout compris, merci JulioDelphi !
En fait j'avais complètement oublié de prendre en compte mon panel...
Merci pour ton explication, elle est vraiment claire !
Autrement, pour la réponse de foxi j'vais étudier ça, parce que je vois qu'il y explique comme déplacer l'ellipse, mais ça a l'air assez compliqué... J'reviens si j'ai des questions....
Merci encore !
Vous n’avez pas trouvé la réponse que vous recherchez ?
madcap
Messages postés77Date d'inscriptionmercredi 15 mars 2006StatutMembreDernière intervention22 février 2011 29 mai 2009 à 16:30
Encore une question pour le code à foxi
Dans l'évènement PaintBox1Paint, tu as mis dans les déclarations de variables des procedure !?
J'ai jamais vu ça, tu pourrais m'expliquer pourquoi tu fais cela ?
P.S. Je code depuis quelques mois en Delphi... je faisais du Java et un peu de C# avant...
JulioDelphi
Messages postés2226Date d'inscriptiondimanche 5 octobre 2003StatutMembreDernière intervention18 novembre 201014 29 mai 2009 à 16:38
Tu déclares toutes tes variables dans la form ? sous le "var Form1: TForm;" ??
Ça marche aussi mais en déclarant juste pour la procédure, la variable n'est déclarée en mémoire QUE quand la procédure est appelée et quand la procédure a fini, la variable est "supprimée" de la mémoire :]
Une métaphore : Pourquoi quand tu vas faire un contrôle de Math, tu ne révises que les maths et pas aussi la géo, le droit, la compta etc ... car tu sais que tu n'en auras pas besoin à ce moment, idem ici ^^
madcap
Messages postés77Date d'inscriptionmercredi 15 mars 2006StatutMembreDernière intervention22 février 2011 29 mai 2009 à 16:45
Non, bien sur que je déclare mes variables dans les procédures en général , mais là il a déclaré une procédure à l'endroit où on déclare les variables d'habitude.
Voici le code :
procedure TFormGestionPlaies.PaintBox1Paint(Sender: TObject);
{ do not modify }
var GfxObj : TGraphic;
OldPen : TPen;
OldBrush : TBrush;
procedure SavePB(const SavePen: boolean=true; const SaveBrush: boolean=true);
begin { Save canvas Pen or Brush or both }
if SavePen then OldPen.Assign((Sender as TPaintBox).Canvas.Pen);
if SaveBrush then OldBrush.Assign((Sender as TPaintBox).Canvas.Brush);
end;
procedure RestorePB(const RestorePen: boolean=true; const RestoreBrush: boolean=true);
begin { Restore canvas Pen or Brush or both }
if RestorePen then (Sender as TPaintBox).Canvas.Pen.Assign(OldPen);
if RestoreBrush then (Sender as TPaintBox).Canvas.Brush.Assign(OldBrush);
end;
begin
OldPen := TPen.Create;
OldBrush := TBrush.Create;
JulioDelphi
Messages postés2226Date d'inscriptiondimanche 5 octobre 2003StatutMembreDernière intervention18 novembre 201014 29 mai 2009 à 16:58
Meme explication, ces procédures (SavePB et RestorePB) ne sont utilisées QUE dans PaintBox1Paint, donc, pas besoin de les "sortir".
Métaphore : Tu as bien compris qu'il ne faut réviser QUE les maths pour le controle de math, mais vas-tu apprendre toutes tes leçons de maths ? non ! ^^
Mais pourquoi avoir fait des procédures et pas simplement mis ce code ? Car il fait plusieurs fois la même chose, donc au lieu de copier coller du code, il a créé des procédures.
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 29 mai 2009 à 17:41
Salut,
Pour compléter un peu les explications de Julio...
On appelle cela des fonctions/procedures imbriquées.
L'avantage est que toutes les variables déclarées localement dans le bloc de PaintBox1Paint sont visibles par SavePB et RestorePB.
Par exemple, tu peux constater que la variable locale OldPen est utilisée par les deux procedure imbriquées SavePB et RestorePB, bien que n'étant pas une variable globale.
On pourrait dire qu'elle est "localement globale".
En fait, une donnée déclarée localement dans un bloc est visible dans ce bloc et dans tous les blocs imbriqués dans celui-ci. Mais pas ailleurs!
Cela permet une meilleure optimisation des ressources ( et sur ce point, tu peux faire confiance à f0xi :).
Ces autorisations d'accès aux données situées dans des blocs imbriqués sont contenues dans la notion de règle de visibilité dans les langages à structure de bloc et ne concerne pas que le Pascal.
Cirec
Messages postés3833Date d'inscriptionvendredi 23 juillet 2004StatutModérateurDernière intervention18 septembre 202250 29 mai 2009 à 18:23
Précision complémentaire aux procédures et fonctions imbriquées
il faut savoir que le temps d'exécution est plus important avec les méthodes imbriquées qu'avec une répétitions de code dans la procédure principale !!!
on évitera donc d'utiliser cette méthode pour une procédure qui doit rafraichir souvent une image avec beaucoup de calculs où tout autre ou la vitesse est primordiale.
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 29 mai 2009 à 18:48
... Ce qui d'ailleurs, en ce qui concerne le temps d'exécution, est valable pour tous les appels de procedure ou de fonction, qui sont à éviter tant que le code reste maintenable. Fragile équilibre entre l'optimisation et la lisibilité...
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 30 mai 2009 à 15:06
Ouais...
Il faut reconnaître que le code de f0xi a une beauté troublante.
Il n'empêche que beaucoup de débutants ou même de développeurs confirmés se seraient tournés vers TImage plutôt que vers TPaintBox.
Souvent je me dis que TPaintBox a été inventée pour f0xi et d'ailleurs, perso, je l'appelle le « compo à f0xi »...
PS : [Hors sujet]
En parlant de beauté troublante, je me demande si c'est pareil chez vous...
Depuis quelques temps j'ai la pub " PhotothèqueNouveau ! " qui ne me montre que des asian sexy girls... et c'est pas fait pour augmenter les rendements, je trouve...
- Est-ce un truc à la Google qui cible la pub par rapport à l'internaute?
- Et dans ce cas, comment Nix connaît mon goût pour les cultures asiatiques?
Nicolas___
Messages postés992Date d'inscriptionjeudi 2 novembre 2000StatutMembreDernière intervention24 avril 20131 30 mai 2009 à 17:22
Et dans ce cas, comment Nix connaît mon goût pour les cultures asiatiques?
C'est pas dur ... les 3/4 des hommes aiment les asiatiques
et les 95% des informaticiens (ou des gars touchant à l'informatique ) aiment les asiatiques
donc place des asiatiques quelques part (pour peu qu'elles soient belles), et on cliquera dessus
Si en plus de ca , les catégories sont "Gorgeous asian girl in the water", c'est vraiment plus du jeu !!!