FASTGRADIENT (METTEZ DES DÉGRADÉS DE COULEURS DANS VOS APPLICATIONS)

cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 - 17 avril 2006 à 12:39
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012 - 28 avril 2006 à 16:08
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/37085-fastgradient-mettez-des-degrades-de-couleurs-dans-vos-applications

cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
28 avril 2006 à 16:08
Salut Cirec,
oui effectivement il manque le support Delphi2005 merci de me le rappeler ;)

maintenant dans la demo les gradients se trouvent dans la fiche ;) et pour avoir l'editeur de gradient il faut faire un double click sur le composant GradientManager ya ecrit "FGD" sur ce compo, ou sinon un click sur Items ça revient au même !!!.

Euh voui le Skinneur n'est pas tout à fait au point je sais !! mdr , concernant le choix des dégradés on peut toujours faire mumuse dans l'unité Skinner->SubClassing , Button ect.. car si tous les objets avait la même couleurs ça serait pas vraiment top point de vue "visuelle"

mais ce n'est qu'un test car il faut que le skinner puisse avoir sa propre structure basé sur le gradient manager avec peut être même des bitmaps pkoi pas !!! et il faudra que chaque éléments "button, groupbox" puissent avoir des info supplémentaires pour le look , le gradient utilisé ect.. qui seront dans stokées dans cette même structure donc rien de difficile !!, va falloir que je lance le projet Skinner à part !!, mais ça necessite encore des packages ect.. c'est pour ça que pour le moment FastGradient & Skinner cohabitent ensemble !!!
@+
Utilisateur anonyme
28 avril 2006 à 13:49
Bon j'ai réussi à installer le designer non sans mal (j'ai été obligé d'ajouter ma version de compilateur dans le fichier SFC.INC)
Bon je ne me suis pas fatigué à la faire j'ai juste mis ceci au début :

{$IFDEF VER170} // Version Delphi 2005
{$DEFINE DELPHI_COMPILER}
{$DEFINE DELPHI7}
{$ENDIF}

Donc le ca fonctionne mais j'ai pas réussi à changer de skin (j'ai pas tyrouvé comment faire)

J'ai remarqué aussi que le premier clique sur un bouton n'avait pas de réaction mais dès qu'il a le focus aucun problème ça fonctionne.

Les contours des TabSheet ne sont pas respecté non plus.

Bref que de la mise au point rien de bien difficile par rapport à ce qui a déjà été fait

Voilà si tu pouvais me dire comment on change de dégradé avec le designer (à moins que ce ne soit pas encore prévu)

Bon ben voilà je ne peut plus donner une note (c'est déjà fait)
donc bravo et j'attend avec impatience la mise à jour :-)

@+
Cirec
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
27 avril 2006 à 20:53
ah okay bah là ya toujours pas de protection contre les mauvaises versions lol c'est pour ça, maintenant les fichiers *.dof & *.cfg contiennent les repertoires de sortie donc si tu les vires et que l'exe et le gradient se trouve dans le même rep ya pas de problème !!, bon essaie d'installer le designer et dit moi si ça marche !!!
@+
Utilisateur anonyme
25 avril 2006 à 23:16
c'était les anciens fichiers qui posaient problème.
après suppression le prog démarre sans soucis.

Et effectivement la selection est inutile pour tester le skinneur :-)

En tous cas tu as fais un sacré boulot ... Bravo

10/10

ps : j'ai pas utilisé les fichiers *.dof et *.cfg et ça fonctionne quand même

@+
Cirec
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
25 avril 2006 à 18:54
Salut Cirec,
bah je viens de télécharger le zip et ça compile correctement et j'ai la même chose que dans le Screenshot donc no problemo !!!

Maintenant je ne sais pas si tu as schtroumpfé quelque chose avec soit les fichiers *.dof, *.cfg(il ne faut pas les effacés !!!), soit le fichier des dégradés en principe tu dois avoir un repertoire "Exe" qui contient Demo.exe puis un sous repertoire "Gradients" qui contient "Gradients.fgd" <== tous les dégradés se trouvent désormais dans ce même fichier, il ne faut surtout pas mettre les autres dégradés dans ce rep car il scan tout le rep et il risque d'y avoir des duplications de noms !!!

concernant le Skinneur il est inutile de chosir dans la liste le dégadé que tu veux car j'ai fait des tests en y mettant ma propre selection !!! il suffit donc de cliquer sur "TestSkin"
donc assure toi que tu as bien ces fichiers dans ton rep 'Exe', par ce que là

concernant le bot c'est rien, c'est juste quelques lignes de codes qui evite les trucs répétitifs !!!
@+
Utilisateur anonyme
25 avril 2006 à 18:03
Salut,
j'ai une belle erreur de lecture du flux
quand l'application démarre

les exemples ne sont pas disponible
je cliques donc sur nouveau et la il s'affiche dans List avec un en plus le sans nom 000
et si je sélectionne un des exemples et je clique sur TestSkin il me dit Index de liste Hors Limites et de la ça part en live ...

ps : et l'affichage ne se rafraîchis pas après le passage d'une autre fenêtre par dessus

Le SpinEdit semble bien fonctionner

euh ton petit robot (c'est au moins la deuxième fois que tu en parles) c'est un code de toi où c'est un soft ?

@+
Cirec
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
24 avril 2006 à 21:35
le SpinEdit à été mise à jour !! j'ai rectifié le problème des caractères "lettre" car avant on pouvait taper "Z" et on avait une belle exception !!!, j'ai aussi rajouter dans la demo une petite fenêtre qui montre la couleur d'origine ça peut toujours servir !!!
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
21 avril 2006 à 21:42
Bah si on met à chaque objet un dégradeur de couleur c'est pas top question resource !!! bon je vais voir, là j'ai pratiquement tout refait avec les TCollections ect.., et perdu FOxi j'ai transformer tous les gradients de l'ancienne version ->nouvelle version en seulement 5 minutes voir moins !!, juste un chti robot qui scan tout le rep et hop le tour est jouer , ya deux nouveaux gradients dans la liste now !!!
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
21 avril 2006 à 14:52
N'oubliez pas de jeter un oeil sur le TjvgBevel et Le
TjvGradient de JEDI.
C'est vrai il n'y pas les boutons ni les labels..

ça serait bien en effet un petit compo qui se loggerait direct sur ces objets et permettrait l'apparition de dégradés.
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
20 avril 2006 à 15:25
Ouep c'est un peu près ça que j'avais en tête à savoir

[gradient item]->gradient list]->GradientManager(c'est le
container)->GradientRenderer pour le rendu

comme ça on assign au Gradient Renderer un container de type GradientManager

comme ceci :

GradientRenderer->GradientManager=GradientManger1
GradientRenderer.DrawGradient(Name , DestCanvas) ect..

maintenant les TCollections c'est un peu lourd à mettre en oeuvre !!! mais pour celà aller chui sympa je mets à votre disposition CoBuilder

http://shining-world.chez.tiscali.fr/download/CoBuilder.rar

on peut créer une multitudes de Collections en quelques cliques !!! et en plus il se charge de la construction/destruction des Objets, ça n'arrive pas encore à la cheville de Delphi mais c'était pas le but mdr, petit à petit ça divient intérréssant enfin essaie et dis moi ce que t'en pense !!!
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
20 avril 2006 à 04:23
re shinning!

alors oui hein, ne prend jamais mal mes commentaires, la plupart du temps, si je m'interresse de si prés a un code c'est qu'il m'interresse donc ... c'est a prendre comme un bon point ...
meme si je critique, c'est toujours dans le but de resoudre les erreurs probables ... de maniere objective et constructive, trouver les meilleures solutions.

pour le INI , alors la, demande a florenth le plaisir que tu me fait a mettre un bench de comparaison, y'a pas photo, ta methode est la meilleure, mais ça je le savais deja.

mais je persiste a croire qu'il y a une bonne possibilitée d'ecrire un trés bon manager pour les dégradés, ma methode est peut etre un peu lourde pour cela.

en fait, ce dont a quoi je pense ce serait de pouvoir integré facilement l'objet dégradé dans des composants, comme des panels, des bouttons etc...

je vois une structure de ce type :

[[gradient item] gradient list] --- > [[gradient manager] composant,canvas]

Gradient Item contient les informations du dégradé
Gradient List contient plusieurs Gradient Item et s'occupe du chargement/sauvegarde des gradient item
Gradient Manager s'occupe du dessin du dégradé


pour le Gradient List, il faudrait modifier le Header et ajouter un parametre :

TGradientHeader = record
Header : array[0..3] of Char;
Version : array[0..5] of Char;
//--[remove to gradient struct) Name : array[0..55] of Char;
ItemCount : word; {0..65535}
end;

la lecture de ItemCount permettras de repeter l'operation de lecture des item et de faire par exemple :
GradientList.Add(GradientItem);

la structure de GradientItem deviendrais :

TGradientTemplate = record
Intensity : TGradientIntensity;
Color : TGradientColor;
LightAngle : single;
Name : array[0..55] of char;
end;

et pour l'item

TGradientItem = class(TCollectionItem)
private
fTemplate : TGradientTemplate;
fOnChange : TNotifyEvent;
function fGetFloat(index : integer) : single;
procedure fSetFloat(index : integer; val : single);
function fGetInteger(index : integer) : integer;
procedure fSetInteger(index : integer; val : integer);
function fGetByte(index : integer) : byte;
procedure fSetByte(index : integer; val : byte);
function fGetName : string;
procedure fSetName(val : string);
procedure Change; virtual;
protected
property OnChange : TNotifyEvent read fOnChange write fOnChange;
published
property GradientName : string read fGetName write fSetName;
property IntensityRGB : Integer index 0 read fGetInteger write fSetInteger;
property ColorRGB : Integer index 1 read fGetInteger write fSetInteger;
property ColorRange : Integer index 2 read fGetInteger write fSetInteger;
property IntensityFactor : Single index 0 read fGetFloat write fSetFloat;
property IntensityValue : Single index 1 read fGetFloat write fSetFloat;
property ColorFactor : Single index 2 read fGetFloat write fSetFloat;
property LightAngle : Single index 3 read fGetFloat write fSetFloat;
property ColorR : Byte index 0 read fGetByte write fSetByte;
property ColorG : Byte index 1 read fGetByte write fSetByte;
property ColorB : Byte index 2 read fGetByte write fSetByte;
public
constructor create(...); override;
end;

qu'en pense tu ?
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
19 avril 2006 à 15:50
bon alors chai pas par où commencer !! tiens salut d'abord ;)

euh okay GradientMat ça porte à confusion avec material mais c'est fait exprès car on se rapproche un peu plus de l'OpenGL qu'un simple GradientFill avec ColorBegin..ColorEnd, car ya la gestion de la lumière..contraste, certes ça n'égale pas l'OpenGL mais bon ça s'y rapproche un peu !!!

Oui pour les opérations Booléennes ça je connais très bien lol mais bon j'avou que dans la partie Demo de mes projets j'y consacre un peu moins d'intêret que dans le code

Case Bool of <=== oui façon de voir mais le Case of est légérement plus performant qu'un if..then

de plus le case of offre une meilleur lisibilité du code mais là c'est juste mon avis !!!

"pourquoi ne debuge tu pas le code des BiduleSpinEdit et que tu soumettrais le debogage a l'auteur" <=== ouep c'est une bonne idée car ce composant est plutôt sympa !! je vais voir si c'est possible de contacter l'auteur

"sinon Good Job et bon courage pour le reste." <== ah quand même un point positif lol okay merci pour le compliment

"Remoi, toujours pour le bug FindClose" <=== eh ouep j'allais te le dire si deux unités possèdent deux fonctions identiques, c'est bel & bien la deuxième unité qui sera prioritaire !!!
donc un point important qu'à relevé Foxi c'est de bien faire Attention à la déclaration des unités dans la clause USES sinon ça peut vous jouer des tours, pensez à mettre toujours windows en 1er lieu !! et plus loin l'unité SysUtils(de même pour toutes les unités ayant des fonctions identiques !!)

maintenant je retiens l'idée de mettre des TCollection ça peut toujours servir pour rajouter facilement de nouveaux gradients et dans ce cas on pourrat dessinée un gradient de part son nom
DrawGradient('MyGradient' ..), bien entendu ces gradients seront dans un TGradientContainer

maintenant concernant l'usage du Tini, mon objectif de départ était que si on charge un gradient depus le resource ou dans un fichier du disque !!, qu'il y est un interval le moins lent que possible sinon j'aurais tout simplement appeler mon composant TSfcTurtleNinjaGradient lol ;)
j'explique imaginons que un compo utilisant celui-ci puisse par exemple coloré les boutons, Forms ect.. et que l'on utilise plusieurs dégradés !!!
il va falloir faire très vite car si la fiche bouge c'est des centaines de fois qu'on va faire appel au dessin !!! capich ? d'où un chargement extrement rapide, d'ailleurs j'ai voulu en avoir le coeur nette !!!

j'ai fait un test comparatif entre
- le chargement d'un gradient avec ma méthode
- le chargement d'un gradient avec ta méthode

voici le resultat
http://shining-world.chez.tiscali.fr/Report/DelphiReport.htm

t'en penses quoi ?!?
@+
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
19 avril 2006 à 00:45
Remoi, toujours pour le bug FindClose que j'ai chez moi ...
je crois savoir precisement de ou il vient mais d'abord tu vas comparer ces deux declarations de clause uses :

chez moi (la plupart du temps) :

uses SysUtils, Windows , ... ;

chez toi :

uses Windows, ..., SysUtils, ... ;

ne remarque tu rien de particulier ?

et oui tu as bien deviné, je declare toujours SysUtils en premier et toi tu declare Windows en premier.
donc je pense et suis fortement sur que quand le compilateur cherche "FindClose" il cherche de la premiere a la dernier unités dans les uses et ne prend en compte que la derniere fonction trouvée (portée plus forte).

chez toi il tombe sur SysUtils aprés windows donc il prend bien en compte la bonne methode FindClose.
chez moi, totalement l'inverse, il tombe sur windows aprés sysutils donc prend la methode FindClose de l'unité windows ce qui provoque mon erreur.

c'est con hein ?!

au moins, ça m'aurat permis de decouvrir enfin pourquoi j'avais eu cette erreur auparavant, des fois oui, des fois non ...
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
19 avril 2006 à 00:31
Oui pour le fichier INI, en effet, d'ailleur je me disait que je trouver pas mal ta methode de lecture/ecriture de fichier et c'est un peu a contre coeur que j'avais opter pour une solution plus "simple". Mais on peu egalement stocker un fichier INI en ressource et l'ouvrir dans un TMemIniFile ... ça reviens un peu au meme... la c'est une question de choix ...

Pour ce qui est du code en plus, oui c'est bien certain, mon exemple genere plus de code au final.
au depart, quand je l'ai ecris, j'avais laisser en externe la methode de dessin ... ce qui n'etait pas plus mal, mais je l'ai mis a l'interieur pour ne pas a avoir a créer un Manager pour le dessin.

Pour "MAT" desolé mais c'est le fait qu'en 3D l'abrégé Mat = Material ... si j'ai confondus c'est tout simplement parce que tu a provoquer la confusion en mettant ce "Mat" ... ^^ hehe (retour a l'envoyeur)

Sinon oui bien sur on pourrais ecrire un editeur de propriété mais bon ... ça ne facilite pas l'utilisation. Vus que les classes separées et les propriété permettent justement de faciliter l'utilisation et la verification des données.

Et puis meme en execution, a l'instar des buffers etc... il n'est pas necessaire de garder tout le temps l'instance de l'objet ... au final ... ça reviens a Creer Utiliser Liberer ... avantage du dynamique c'est que peu importe l'objet au final ça prend toujours pas vraiment plus de place.

Pour justifier quand meme mon choix des fichiers ini plutot qu'un type fichier bien precis et surtout trés contraint, c'est qu'admettons nous ajoutons 2 parametres dans la nouvelle version.
Avec le type record, tout les degradés seront a refaire et on passeras beaucoup de temps dessus.
alors qu'avec un fichier de type texte (ini) il suffirat de les ouvrir tous dans delphi ou dans NotePad++ par exemple, de definir l'emplacement des nouveaux parametres dans le fichier (avant la section color par exemple) > menu > remplacer texte > "[Color]" par "nouveaux parametres{retour ligne}[Color]" > remplacer dans tout les fichiers > ok.
hop ... 100 degradé mis a jours en a peine 5 minutes.

Et pour justifier le code en plus, c'est tout bonnement pour reduire le code que le developpeur aurat a ecrire pour utiliser le composant.

notes quand meme que ça fait 3 points plutot benefique :
utilisation pour le developpeur facilitée
mises a jours des nouvelles versions facilitée
edition dans un simple bloc note des fichiers parametres de dégradés

aprés, ce n'etait qu'une suggestion, a toi de voir si tu peu en tirer quelque chose, des idées etc...
par exemple tu pourrais deja remplacer tes 3 methodes de dessin dans le compo TSfcFastGradient
qui peuvent se resumé a une seule methode, ne trouve tu pas.

mais sinon, j'ai oublier quand meme de te feliciter pour ce sources que j'avous assé bluffant sur les rendus des degradés... un peu de mal quand meme a comprendre comment les paremetres agissent sur le dégradé, tu devrais peut etre les commentés en details pour qu'on puisse bien comprendre le fonctionnement.
Car la on change completement par rapport aux dégradés CouleurDebut > CouleurFin.

pour Les find, j'ai rechercher et je te mets la solution :

en fait SysUtils.FindClose() se retrouve en conflit avec la fonction Windows.FindClose()
>> function FindClose; external kernel32 name 'FindClose'; (unité windows)

et si l'erreur n'apparait pas chez toi ... la je comprend pas pourquoi... en tout cas sur la v7 de Delphi ... y'a ce probleme ...
donc si un jours tu vois l'erreur "erreur findclose incompatibilité TSearchRec et Cardinal" ne cherche pas plus loin ... il faut ecrire SysUtils.FindClose()

et sinon pour :
>> if not FBeginUpdate then <=== ça fait débutant ?? quoi de plus normal pour un débutant ;)

c'est pas "if not [bool] then" qui fait code de debutant c'est "if [bool] = false then" qui fait debutant.
l'expression d'une condition est un booléen donc il ne devrait jamais y avoir de valeur booléene dans les conditions tel :
if [bool] = true then
ou
if [bool] = false then

mais seulement
if [bool] then (expression vrai)
if not [bool] then (expression fausse)

ça c'est ceux qui font des switchs sur les valeurs booléenes ... on ne fait pas de switch la dessus.
case [bool] of
true :
false :
end;

c'est caca faut pas faire. il faut faire :

if [bool] then ... else ...

et aussi pour les affectation booléene sur comparaison de valeur tel :

if X < 0 then Negative := true
else
if X >= 0 then Negative := false;

beaucoup de code pour que dalle ... il faut faire :
Negative := (X < 0);

mais ça tu le sais c'est juste pour le rappeler a ceux qui ne le savent pas.

enfin bref ... tout cela pour dire que, je ne dis pas que mon exemple est le meilleur, mais je pense qu'il peu te donner des idées... a toi de voir lequels.

sinon Good Job et bon courage pour le reste.

ps : au fait, pourquoi ne debuge tu pas le code des BiduleSpinEdit et que tu soumettrais le debogage a l'auteur avec le package que tu as créé ? c'est un codes sources en opensource aprés tout non ? ça m'a etonné de voir que tu disais : "je n'ai pas le droit de modifier le fichier sans l'accord de l'auteur j'ai donc tout simplement mis le zip tel quel !!!"

moi je te conseil : Modifie et soumet le a l'auteur, aprés tout peut etre accepterat t'il ou au moins il verrat que des bugs persistent. Surtout que ça a l'air d'etre un petit composant sympa ... alors pourquoi pas...
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
18 avril 2006 à 16:08
c'est bien beau un TIni mais hélas ce dernier ne permet pas un chargement depuis le resource !!!, il fraudrait enregistrer le fichier dans le DD puis l'ouvrir !! contrairement à la Structure de type "Record" !!!

TSfcFastGradient <=== ce composant ce charge du rendu d'un gradient il ne doit pas avoir des propriétés telles ceux qui tu as mis dans TGradientMat <== et en plus ya une grosse confusion ce n'est pas un matériel !!! tu nous fait un mixage de tout mdr, et en plus si chaque gradient devait avoir son propre renderer quel gaspillage de code !!!
car à chaque nouvelle instance de TGradientMat Delphi va copier tout le code de ce dernier !!!

et Sfc c'est pour Shining Freeman Component ça evite tout conflit avec des composants existant !!!

Concernant le problème de division par zero il faudrait retirer la fonction qui affiche en temps réel mais là on perd quant à la recherche d'un dégradé precis en jouant avec les valeurs !!!

if not FBeginUpdate then <=== ça fait débutant ?? quoi de plus normal pour un débutant ;)

concernant le problème de conflit avec FindNext ect.. j'ai Delphi6 et jamais eu de problème avec ça !!!

maintenant concernant la modification des gradients plutôt que d'emcombrer le composant avec des propriétés publiées(TPersistent) il vaudrait mieux laisser cette tâche à l'inspecteur d'objet via un Package dédier au design !!! là au moins le code ne sera pas compiler dans l'exe !!!
le but c'est quand même de ne pas créer d'instance d'un Gradient et de permettre un Rendu avec un Simple Record même si c'est un peu galère lors d'une eventuelle mise à jour c'est pour cette raison qu'il faudra une structure flexible un peu comme celle de PaintShopPro !!
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
18 avril 2006 à 15:06
>>if not FBeginUpdate then <=== ça change quoi dans le code généré par delphi ?

ça change que la c'est ecrit proprement et non pas a la debutant.

>>Windows.FindNextFile
>>Windows.FindFirstFile
>>à la limite veux bien pour FindClose !!!

non non, je ne sais pas pourquoi mais dans la version 6 et 7 de delphi y'a une incompatibilitée si on ne force pas SysUtils avec ces fonctions ... je sais ... c'est bizarre mais ça m'est arrivé deja plein de fois malgrés et meme sur plusieurs installation du systeme.

c'est avec windows ou une autre unité ? tiens zut j'ai un doute ... en tout cas je sais que dans plusieurs cas y'a une incompatibilitée avec une unité ... il faudrait que je verifie pour en dire plus ...

>> dans LoadGradients; pour mettre un Try puisque si aucun fichier n'existe on ne fait rien ??? !!!!

pareil que pour "if not..." c'est pour faire du code propre et non du code de debutant.


pour l'histoire du range, la par contre en effet, toute mes excuses, je ne savais pas qu'il pouvais etre negatif.
en effet ... ça pose un probleme et releve encore une fois une question que je me suis souvent posé en math :
si X * 0 = 0
alors pourquoi X / 0 ne serait pas non plus egal a 0

donc oui a ce moment la il faut laisser la condition
if Range = 0 then Range := 1;
on ne peu pas faire autrement de toute façon.
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
18 avril 2006 à 14:51
tiens je me permet de faire une grosse correction pour TGradientMat.

tu remarqueras que les fichiers sont fait avec TIniFile, ce qui permet d'aller les modifier dans le bloc note par exemple (ce qui peut etre utile quand on change la version du composant), mais ca simplifie grandement le format du fichier ce qui faciliteras l'ajout de choses et d'autre et l'utilisation concrete dans les programmes.

Le fait d'avoir mis TGradientIntensity et TGradientColor en classe TPersistent permet d'avoir une hierarchie lisible dans l'inspecteur d'objet et permet egalement un meilleur control sur les données, comme l'ajout d'evenement, de control d'interval, de calcul avancé ect... ect...

TGradientMat Remplace directement TSfcFastGradient qui s'est trouver inutile aprés reflexion.
ce composant gere seul le chargement et la sauvegarde des fichiers de dégradés et egalement le dessin dans le canvas.
Ce qui fait que TGradientMat s'utilise un peu comme les TStringLists, il permettras egalement de faire des presets plus facilement pour un composant visuel plus costaud.
Il faudrat juste que tu regarde a regler les valeurs par defaut a la creation dans les constructeurs, ne les sachants pas, je les est mises un peu au plus logique.

Sinon tout a été corrigé et ce qui été inutile (comme la couleur de fond ?! qui servait a rien du tout) ont été enlevés.

bien entendus, tout cela genere plus de code, mais au final, a l'utilisation il y'en a beaucoup moins ... c'est ça la puissance des classes.


unit GradientMat;

interface

uses Windows, Types, Classes, SysUtils, Math, Controls, Graphics, IniFiles, Dialogs;

const
{byte 1 : major
byte 2 : minor
byte 3 : release
byte 4 : build }
GRADIENT_VERSION = $01010000; {v1.1.0.0}

type
TGradientOrientation = (goHorz , goVert);

TGradientIntensity = Class(TPersistent)
private
fControl : TControl;
fRGB : integer;
fFactor : single;
fValue : single;
fOnChange: TNotifyEvent;
procedure fSetInt(Val : integer);
procedure fSetFloat(index : integer; Val : single);
protected
procedure Change; virtual;
procedure AssignTo(Dest : TPersistent); override;
property Control : TControl read FControl;
property OnChange : TNotifyEvent read fOnChange write fOnChange;
published
property RGB :{0..255} integer read fRGB write fSetInt;
property Factor:{?..?} single index 0 read fFactor write fSetFloat;
property Value :{?..?} single index 1 read fValue write fSetFloat;
public
constructor Create(Control: TControl); virtual;
destructor Destroy; override;
end;

TGradientColor = Class(TPersistent)
private
fControl : TControl;
fRGB : integer;
fRange : integer;
fFactor : single;
fR : byte;
fG : byte;
fB : byte;
fOnChange: TNotifyEvent;
procedure fSetInt(index : integer; Val : integer);
procedure fSetFloat(Val : single);
procedure fSetByte(index : integer; Val : byte);
protected
procedure Change; virtual;
procedure AssignTo(Dest : TPersistent); override;
property Control : TControl read FControl;
property OnChange : TNotifyEvent read fOnChange write fOnChange;
published
property RGB : {0..255} integer index 0 read fRGB write fSetInt;
property Range : {?..?} integer index 1 read fRange write fSetInt;
property Factor: {?..?} single read fFactor write fSetFloat;
property R : {0..255} byte index 0 read fR write fSetByte;
property G : {0..255} byte index 1 read fG write fSetByte;
property B : {0..255} byte index 2 read fB write fSetByte;
public
constructor Create(Control: TControl); virtual;
destructor Destroy; override;
end;

TGradientMat = class(TComponent)
private
fIntensity : TGradientIntensity;
fColor : TGradientColor;
fLightAngle : single;
fGradientName : string;
fGradientVersion : integer;
fOnChange : TNotifyEvent;
procedure fSetIntensity(Val : TGradientIntensity);
procedure fSetColor(Val : TGradientColor);
procedure fSetFloat(Val : single);
procedure fSetGDName(Val : String);
function fGetVersion : string;
procedure DoIntensityChange(Sender : TObject);
procedure DoColorChange(Sender : TObject);
protected
procedure Change; virtual;
published
property Intensity : TGradientIntensity read fIntensity write fSetIntensity;
property Color : TGradientColor read fColor write fSetColor;
property LightAngle : single read fLightAngle write fSetFloat;
property GradientName : string read fGradientName write fSetGDName;
property GradientVersion : string read fGetVersion;
property OnChange : TNotifyEvent read fOnChange write fOnChange;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DrawGradient(ACanvas : TCanvas; ARect : TRect; AOrientation : TGradientOrientation);
procedure LoadFromFile(FileName : string);
procedure SaveToFile(FileName : string);
end;

procedure Register;

implementation

procedure Register;
begin
RegisterComponents('Exemples', [TGradientMat]);
end;

type
TRGBRec = record
B,G,R : byte;
end;
TRGBRecArray = array[0..32767] of TRGBRec;
pRGBRecArray = ^TRGBRecArray;

{ functions -------------------------------------------------------------------------------------- }

function Clamp(const V,aMin,aMax : integer) : integer; overload;
begin
result := Max(Min(V,aMax),aMin);
end;

function Clamp(const V,aMin,aMax : byte) : byte; overload;
begin
result := Max(Min(V,aMax),aMin);
end;

function Clamp(const V,aMin,aMax : single) : single; overload;
begin
result := Max(Min(V,aMax),aMin);
end;

function ValidateRGB(Color: integer): integer;
begin
result := Max(Min(Color,255),0);
end;

{ TGradientIntensity ----------------------------------------------------------------------------- }
constructor TGradientIntensity.Create(Control : TControl);
begin
inherited Create;
fControl := Control;
fRGB := 0;
fFactor := 1.0;
fValue := 1.0;
end;

Destructor TGradientIntensity.Destroy;
begin
inherited Destroy;
end;

procedure TGradientIntensity.fSetInt(Val : integer);
var ClV : integer;
begin
ClV := Clamp(Val,0,255);
if fRGB <> ClV then begin
fRGB := ClV;
Change;
end;
end;

procedure TGRadientIntensity.fSetFloat(index : integer; Val : single);
begin
case index of
0: begin
if fFactor <> Val then begin
fFactor := Val;
Change;
end;
end;
1: begin
if fValue <> Val then begin
fValue := Val;
Change;
end;
end;
end;
end;

procedure TGRadientIntensity.Change;
begin
if Assigned(fOnChange) then fOnChange(Self);
end;

procedure TGRadientIntensity.AssignTo(Dest : TPersistent);
begin
if Dest is TGRadientIntensity then
with TGRadientIntensity(Dest) do begin
fRGB := Self.fRGB;
fFactor := Self.fFactor;
fValue := Self.fValue;
Change;
end
else
inherited AssignTo(Dest);
end;

{ TGradientColor --------------------------------------------------------------------------------- }
constructor TGradientColor.Create(Control : TControl);
begin
inherited Create;
fControl := Control;
fRGB := 0;
fRange := 1;
fFactor := 1.0;
fR := 0;
fG := 0;
fB := 0;
end;

destructor TGradientColor.Destroy;
begin
inherited Destroy;
end;

procedure TGradientColor.fSetInt(index : integer; val : integer);
var ClV : integer;
begin
case index of
0: begin
ClV := clamp(Val,0,255);
if fRGB <> ClV then begin
fRGB := ClV;
Change;
end;
end;
1: begin
ClV := clamp(Val,1,255);
if fRange <> ClV then begin
fRange := ClV;
Change;
end;
end;
end;
end;

procedure TGradientColor.fSetFloat(Val : single);
begin
if fFactor <> Val then begin
fFactor := Val;
Change;
end;
end;

procedure TGradientColor.fSetByte(index : integer; val : byte);
var ClV : byte;
begin
ClV := Clamp(Val,0,255);
Case Index of
0: if fR <> ClV then begin
fR := ClV;
Change;
end;
1: if fG <> ClV then begin
fG := ClV;
Change;
end;
2: if fB <> ClV then begin
fB := ClV;
Change;
end;
end;
end;

procedure TGradientColor.Change;
begin
if Assigned(fOnChange) then fOnChange(Self);
end;

procedure TGradientColor.AssignTo(Dest : TPersistent);
begin
if Dest is TGradientColor then
with TGradientColor(Dest) do begin
fRGB := Self.fRGB;
fFactor := Self.fFactor;
fRange := Self.fRange;
fR := Self.fR;
fG := Self.fG;
fB := Self.fB;
Change;
end
else
inherited AssignTo(Dest);
end;

{ TGradientMat --------------------------------------------------------------------------------- }
constructor TGradientMat.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
fIntensity := TGradientIntensity.Create(nil);
fIntensity.OnChange := DoIntensityChange;
fColor := TGradientColor.Create(nil);
fColor.OnChange := DoColorChange;
fLightAngle := 0;
fGradientName := '(UnNamed Gradient)';
end;

destructor TGradientMat.Destroy;
begin
fColor.Free;
fIntensity.Free;
inherited destroy;
end;

procedure TGradientMat.fSetIntensity(val : TGradientIntensity);
begin
Val.AssignTo(fIntensity);
fIntensity.OnChange(self);
end;

procedure TGradientMat.fSetColor(val : TGradientColor);
begin
Val.AssignTo(fColor);
fColor.OnChange(Self);
end;

procedure TGradientMat.fSetFloat(val : single);
var ClV : single;
begin
// ClV := Clamp(Val,{MinLightAngle},{MaxLightAngle});
if fLightAngle <> Val{ClV} then begin
fLightAngle := Val{ClV};
Change;
end;
end;

procedure TGradientMat.fSetGDName(Val : String);
begin
if fGradientName <> Val then begin
fGradientName := Val;
Change;
end;
end;

function TGradientMat.fGetVersion : string;
var VMajor,VMinor,VRelease,VBuild : byte;
begin
VMajor := byte(fGradientVersion shr 24);
VMinor := byte(fGradientVersion shr 16);
VRelease:= byte(fGradientVersion shr 8);
VBuild := byte(fGradientVersion);
result := format('%d.%d.%d.%d',[VMajor,VMinor,VRelease,VBuild]);
end;

procedure TgradientMat.DoIntensityChange(Sender : TObject);
begin
{ code of Intensity change here ...}
Change;
end;

procedure TGradientMat.DoColorChange(sender : TObject);
begin
{ code of Color change here ...}
Change;
end;

procedure TGradientMat.Change;
begin
if Assigned(fOnChange) then fOnChange(Self);
end;

{ DrawGradient -------------------------------------------------------------------------------- }
procedure TGradientMat.DrawGradient(ACanvas: TCanvas; ARect: TRect; AOrientation: TGradientOrientation);
var Buffer : TBitmap;
X, Y,
iKB : Integer;
FR,FG,FB,
PL : Single ;
ScanLines : pRGBRecArray;
begin
Buffer := TBitmap.Create;
Buffer.PixelFormat := pf24bit;
Buffer.Width := ARect.Right - ARect.Left;
Buffer.Height := ARect.Bottom - ARect.Top;

Case AOrientation of
goHorz : begin
iKB := Trunc((Buffer.Height) / fLightAngle);
PL := 255 div (Buffer.Height);
end;
goVert : begin
if Buffer.Width > 255 then
PL := 0.5
else
PL := 255 div Buffer.Width;
end;
end;

FR := (((fIntensity.RGB+fColor.R*fIntensity.Factor)/fIntensity.Value)+fColor.R)/fColor.Range;
FG := (((fIntensity.RGB+fColor.G*fIntensity.Factor)/fIntensity.Value)+fColor.G)/fColor.Range;
FB := (((fIntensity.RGB+fColor.B*fIntensity.Factor)/fIntensity.Value)+fColor.B)/fColor.Range;

for Y := 0 to Buffer.Height -1 do begin
ScanLines := Buffer.Scanline[Y];
if AOrientation = goVert then
iKB := Trunc((Buffer.Width) / fLightAngle);
for X := 0 to Buffer.Width -1 do begin
with ScanLines[X] do begin
R := ValidateRGB(Trunc((fColor.RGB + (Abs(iKB) * PL) * fColor.Factor) * FR));
G := ValidateRGB(Trunc((fColor.RGB + (Abs(iKB) * PL) * fColor.Factor) * FG));
B := ValidateRGB(Trunc((fColor.RGB + (Abs(iKB) * PL) * fColor.Factor) * FB));
end;
if AOrientation = goVert then Inc(iKB);
end;
if AOrientation = goHorz then Inc(iKB);
end;
ACanvas.Draw(ARect.Left , ARect.Top , Buffer);
Buffer.Free;
end;

procedure TGradientMat.LoadFromFile(FileName : string);
var FGD : TIniFile;
begin
if FileExists(FileName) then begin
FGD := TIniFile.Create(FileName);
try
fGradientName := FGD.ReadString ('Header', 'Name', '(UnNamed gradient)');
fGradientVersion := FGD.ReadInteger('Header', 'Version', 0);
if fGradientVersion <> GRADIENT_VERSION then
MessageDlg('La version du fichier differe de la version en cours!'+#13+#10+
'Il se peut que le dégradé ne s''affiche pas correctement.',mtWarning,[mbOk],0);
fLightAngle := FGD.ReadFloat('Params','LightAngle',0.0);
fIntensity.RGB := FGD.ReadInteger('Intensity', 'RGB', 0);
fIntensity.Factor := FGD.ReadFloat ('Intensity', 'Factor', 1.0);
fIntensity.Value := FGD.ReadFloat ('Intensity', 'Value', 0);
fColor.RGB := FGD.ReadInteger('Color', 'RGB', 0);
fColor.Range := FGD.ReadInteger('Color', 'Range', 1);
fColor.Factor := FGD.ReadFloat ('Color', 'Factor', 1.0);
fColor.R := byte(FGD.ReadInteger('Color', 'Red', 0));
fColor.G := byte(FGD.ReadInteger('Color', 'Green', 0));
fColor.B := byte(FGD.ReadInteger('Color', 'Blue', 0));
finally
FGD.Free;
Change;
end;
end;
end;


Procedure TGradientMat.SaveToFile(FileName : string);
var FGD : TIniFile;
begin
FGD := TIniFile.Create(FileName);
try
FGD.WriteString ('Header', 'Name', fGradientName);
FGD.WriteInteger('Header', 'Version', GRADIENT_VERSION);
FGD.WriteFloat('Params','LightAngle',fLightAngle);
FGD.WriteInteger('Intensity', 'RGB', fIntensity.RGB);
FGD.WriteFloat ('Intensity', 'Factor', fIntensity.Factor);
FGD.WriteFloat ('Intensity', 'Value', fIntensity.Value);
FGD.WriteInteger('Color', 'RGB', fColor.RGB);
FGD.WriteInteger('Color', 'Range', fColor.Range);
FGD.WriteFloat ('Color', 'Factor', fColor.Factor);
FGD.WriteInteger('Color', 'Red', fColor.R);
FGD.WriteInteger('Color', 'Green', fColor.G);
FGD.WriteInteger('Color', 'Blue', fColor.B);
finally
FGD.Free;
end;
end;

end.
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
18 avril 2006 à 12:50
Q-"pourquoi ne pas remplacer les composants non standard par de simple trackbar ?"
R- bah je trouve SpinEdit plus esthétique que le trackbar de plus SpinEdit permet d'entrer des valeurs !!!


"with BmLightAngle do Value := Max(1,Value);" le problème est qu'on ne doit pas mettre de valeur "zero" sinon ya division par zero donc ton code où le mien ne résoud pas le problème car on peut mettre des valeurs négatives !!! et là ça bloque les valeurs négatives, la raison est qu'on dessine le gradient en temps réel !!!
pour le try ect.. encore une fois ce n'est que la démo et on est censé avoir les gradients dans le repertoire gradient !!!

pour les with pareil me suis pas casser la tête vu que la structure risque de changer !!!

pour le reste je n'ai pas chercher à optimisé le code

if not FBeginUpdate then <=== ça change quoi dans le code généré par delphi ?
UpdateGradient;

dans LoadGradients; pour mettre un Try puisque si aucun fichier n'existe on ne fait rien ??? !!!!

Windows.FindNextFile tu ne confonds avec
Windows.FindNextFile
Windows.FindFirstFile
à la limite veux bien pour FindClose !!!
en tout cas ça marche c'est l'essentiel lol
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
18 avril 2006 à 09:47
pourquoi ne pas remplacer les composants non standard par de simple trackbar ?



sinon voila quelques resolutions de problemes :


procedure TFrmMain.DoSpinEditChange(Sender: TObject);
begin
if not FBeginUpdate then
UpdateGradient;
end;


procedure TFrmMain.UpdateGradient;
begin
// avec uses Math :
with BmLightAngle do Value := Max(1,Value);
with BmIntensisty do Value := Max(1,Value);
with BmRangeRGB do Value := Max(1,Value);

with Mat do begin
LightAngle := BmLightAngle.Value;
with Intensity do begin
Factor := BmIntensityFactor.Value;
Value := BmIntensity.Value;
RGB := Trunc(BMIntensityRGB.Value);
end;
with Color do begin
Factor := BmColorFactor.Value;
RGB := Trunc(BmColorRGB.Value);
Range := Trunc(BmRangeRGB.Value);
R := Trunc(BmR.Value);
G := Trunc(BmG.Value);
B := Trunc(BmB.Value);
end;
end;
DrawGradient;
end;


procedure TFrmMain.LoadGradients;
var
SearchRec : TSearchRec;
begin
lstbGradientExplorer.Clear;
// FindFirst, FindNext,FindCloses doit etre dans un bloc Try Finally
try
with lstbGradientExplorer.Items do begin
// il faut forcer SysUtils pour les fonctions Find* a cause de l'unité Windows.
if SysUtils.FindFirst(GetGradDir+'*.fgd' , faAnyFile, SearchRec) = 0 then begin
// ne pas oublier d'ajouter le premier elements trouvé.
Add(SearchRec.Name+'='+LoadGradient(SearchRec.Name));
while SysUtils.FindNext(SearchRec) = 0 do
// ne pas utiliser Format pour concatener les chaines.
Add(SearchRec.Name+'='+LoadGradient(SearchRec.Name));
end;
end;
finally
SysUtils.FindClose(SearchRec);
end;
end;


procedure TFrmMain.DrawGradient;
const
BoolToOrient : array[boolean] of TGradientOrientation = (goVert,goHorz);
begin
Grad.BackColor := PanGradient.Color;
Grad.DrawGradientMat( PaintBoxGradient.Canvas,
PanGradient.ClientRect,
Mat,
BoolToOrient[ChkOrientation.Checked]);
end;


procedure TFrmMain.chkOrientationClick(Sender: TObject);
const
BoolToOrientCap : array[boolean] of string = ('Verticale','Horizontale');
begin
ChkOrientation.Caption := BoolToOrientCap[ChkOrientation.Checked];
DrawGradient;
end;

// pas dans destroy mais dans Close
procedure TFrmMain.FormClose(Sender: TObject);
begin
Grad.Free;
end;
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
17 avril 2006 à 17:05
je peux maintenant tester le soft et les autres aussi..
faudrait p'tet dire quet chose..
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
17 avril 2006 à 16:40
Décidemment lol
non seulement l'auteur du composant SpinEdit diffuse un compo sans package et en plus il es bourré d'erreurs !!! mdr, je n'ai pas le droit de modifier le fichier sans l'accord de l'auteur j'ai donc tout simplement mis le zip tel quel !!! car entre temps visiblement l'auteur à changer le nom du fichier resource BmSpinEditInt.res par BmpSpinEdit.dcr

donc voilà la rectif à faire toi même !!!
Mon Package gère automatiquement le fichier resource donc en principe il n'est plus utile de re déclarer le fichier resource

donc dans BmSpinEdit.pas juste en dessous de implementation
l'auteur à mis
{$R BmSpinEditInt.res} <=== retire cette déclaration à la ligne 250

au pire des cas si ça ne marche toujours pas il suffit alors de changer BmpSpinEditInt.res par BmpSpinEdit.dcr

mais ya pas de raison que cette manip ne marche pas !!
@+
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
17 avril 2006 à 16:19
oui, c'est bien d'avoir penser à faire un package..
c'est plus pratique, mais cela dit le tien ne fonctionne toujours pas
car il a besoin d'un fichier BMSpinEditInt.res qui n'existe pas..

merci de corriger ton source..

@+
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
17 avril 2006 à 15:34
Autre chose aussi certaines valeurs on une précision double(avec virgule), il faut y aller molo généralement un chiffre après la virgule peut avoir une affluence sur tout le reste, c'est notamment le cas des "Facteurs", evitez de mettre des zero au facteur sinon ya risque de division par zero !!!, la demo integre petite protection.
cs_shining Messages postés 304 Date d'inscription lundi 30 décembre 2002 Statut Membre Dernière intervention 10 mars 2012
17 avril 2006 à 15:30
ce n'est pas une erreur de ta part c'est que l'auteur du composant SpinEdit ne distribue pas de Package d'installation avec son compo !!!
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
17 avril 2006 à 12:39
sauf erreur de ma part, il doit manquer un fichier dans ton ZIP..
essaie de tout installer à partir de ton fichier compressé.
Rejoignez-nous