informatixo
Messages postés129Date d'inscriptionmercredi 4 février 2004StatutMembreDernière intervention25 juillet 2012
-
16 juin 2009 à 17:31
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 2013
-
18 juin 2009 à 13:10
Bonsoir le forum,
J'ai un problème avec le composant ComboBoxEx et plus particulièrement avec sa propriété Images.
J'ai créé une procédure qui permet de mettre à jour une ComboBoxEx de façon dynamique (texte + image) dont voici le code simplifié :
begin
try
// Permet de créer la liste des images et de la remplir.
ListeImages := TImageList.Create(nil);
ListeImages.Height := 20;
ListeImages.Width := 20;
Bitmap:= TBitmap.Create;
Bitmap.LoadFromFile('C:\Images\Image1.bmp');
ListeImages.Add(Bitmap, nil);
Bitmap.LoadFromFile('C:\Images\Image2.bmp');
ListeImages.Add(Bitmap, nil);
Bitmap.LoadFromFile('C:\Images\Image3.bmp');
ListeImages.Add(Bitmap, nil);
Bitmap.LoadFromFile('C:\Images\Image4.bmp');
ListeImages.Add(Bitmap, nil);
Bitmap.LoadFromFile('C:\Images\Image5.bmp');
ListeImages.Add(Bitmap, nil);
// Permet d'associer la liste d'images à la liste déroulante.
cmbListeDeroulante.Images.Assign(ListeImages);
// Permet de nettoyer la liste déroulante dans le cas où il y a déjà des données.
cmbListeDeroulante.Clear;
// Permet d'ajouter les éléments dans la liste déroulante.
for i := 0 to 4 do
cmbListeDeroulante.ItemsEx.AddItem('Image' + IntToStr(i + 1), i, i, -1, -1, nil);
finally
ListeImages.Free;
imgBitmap.Free;
end;
end;
Dans l'exemple ci-dessus j'obtiens un Access violation. J'ai donc essayé cette variante en remplaçant le "Assign" (ligne en vert) :
cmbListeDeroulante.Images.AddImages(ListeImages);
Mais là, même résultat c'est-à-dire Access violation. J'ai donc pensé que Images n'était pas créé et j'ai donc ajouté cette ligne de code avant le "Assign" (ligne en vert) :
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202234 16 juin 2009 à 18:20
Explications :
cela est du au fait que, comme les Evenements, les propriétés du style Images, PopupMenu, Action, ActiveControl, Menu, etc, ne sont la que pour stocker une instance existante d'un objet.
voici comme elle sont déclarée :
TMaClasse = class
private
fCompo: TComponent;
// Ceci est en fait un pointeur sur l'instance existante d'un composant, il est nil par defaut
procedure SetCompo(Value: TComponent);
// permet d'effectuer les operations necessaire pour l'assignation a fCompo
public
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
// permet de gerer la notification de liberation externe de fCompo, sans cela, un appel a fCompo alors
// que ce dernier serait libéré provoquerai une erreur dans la classe.
property Component : TComponent read fCompo write SetCompo;
// ceci est la propriété visible permettant de "linker" un composant a notre classe.
end;
procedure TMaClasse.Notification(AComponent: TComponent; Operation: TOperation);
begin
// si le composant linké se libère on remet fCompo a nil. if (AComponent fCompo) and (Operation opRemove) then
fCompo := nil;
inherited;
end;
procedure MaClasse.SetCompo(Value: TComponent);
begin
if fCompo <> Value then
begin
// Si fCompo etait assigné on lui indique de ne plus prevenir la classe de sa libération
if Assigned(fCompo) then
fCompo.RemoveFreeNotification;
// on assigne notre nouveau composant ou nil
fCompo := Value;
// si fCompo est de nouveau assigné, il doit nous prevenir de son eventuelle libération
if Assigned(fCompo) then
fCompo.FreeNotification(Self);
end;
end;
Voila, ce genre de propriété permet de linké un composant avec un autre, le Owner ne doit pas, en regles generales, effectuer la creation ou la libération d'une telle propriété. Elles ne servent qu'a pouvoir interragir avec un composant.
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202234 17 juin 2009 à 04:17
procedure UpdateImageList(ComboBox: TComboBoxEx; ImageList: TImageList; const ImagesName : array of string);
var
I : Integer;
BMP: TBitmap;
begin if (Length(ImagesName) 0) or (ComboBox nil) or (ImageList = nil) then
Exit;
for I := Low(ImagesName) to high(ImagesName) do
begin
if FileExists(
ImagesName[I]
) then
begin
BMP.LoadFromFile(
ImagesName[I]
);
ImageList.Add(BMP, nil);
ComboBox.ItemsEx.AddItem(
ImagesName[I]
, I, I, -1, -1, nil);
end;
end;
finally
ComboBox.ItemsEx.EndUpdate;
end;
finally
BMP.Free;
end;
end;
procedure Tform1.UpdateImageList(ComboBox: TComboBoxEx);
var
I : Integer;
BMP: TBitmap;
FLN, PTH : String;
begin
BMP := TBitmap.Create;
try
ComboBox.ItemsEx.BeginUpdate;
try
ComboBox.Clear;
ComboBox.Images := fImageList;
PTH := 'c:\images\';
for I := 0 to 4 do
begin
FLN := 'image'+IntToStr(I+1)+'.bmp';
if FileExists(PTH+FLN) then
begin
BMP.LoadFromFile(PTH+FLN);
fImageList.Add(BMP, nil);
ComboBox.ItemsEx.AddItem(FLN, I, I, -1, -1, nil);
end;
end;
finally
ComboBox.ItemsEx.EndUpdate;
end;
finally
BMP.Free;
end;
end;
informatixo
Messages postés129Date d'inscriptionmercredi 4 février 2004StatutMembreDernière intervention25 juillet 20121 16 juin 2009 à 23:40
Merci beaucoup foxi pour ta réponse si rapide et si complète, désolé de ne pas avoir pu être aussi réactif !
Donc si j'ai bien compris, la propriété Images du composant ComboBoxEx n'est qu'un pointeur vers un TImageList existant et à la conception ça marche bien puisque les deux sont créés sur la form et que l'on a que besoin de les lier.
Hors dans l'hypothèse d'une création dynamique, je suppose qu'il n'y a pas moyen d'assigner un TImageList mais juste de pointer dessus.
Je ne mets pas réponse accepté pour ton code car dans mon cas il ne s'applique pas cependant je vais m'en servir pour arriver à mes fins ! En revanche tes explications sont claires et m'ont permis de trouver une solution donc je mets réponses accepté pour ta deuxième réponse.
Mon problème est que ma procédure est stockée dans une unité toute simple sans form que j'appelle depuis plusieurs autres form via le uses. Donc si j'ai compris les deux solutions qu'ils me restent sont :
<li>De déclarer dans mon unité un TImageList global que je pourrais lier à la propriété Images par une simple affectation (qui initialisera le pointeur en question) depuis ma procédure</li><li>De créer mon propre composant ComboBoxEx en dérivant de TCustomComboBox pour arriver au résultat souhaité</li>Pourrais-tu avoir la gentillesse de me dire si je suis sur la bonne voie ?
Merci d'avance pour ton aide et encore merci pour l'aide que tu m'as déjà apporté.
Que la force soit avec vous !
Vous n’avez pas trouvé la réponse que vous recherchez ?
informatixo
Messages postés129Date d'inscriptionmercredi 4 février 2004StatutMembreDernière intervention25 juillet 20121 17 juin 2009 à 12:20
Merci encore foxi pour ton aide.
Donc mes hypothèses précédentes se vérifie à propos du TImageList.
Je te remercie pour ton dernier code, je vais m'en inspiré pour compléter ma procédure car je veux l'appeler avec uniquement le ComboBoxEx comme paramètre par référence.
Ton aide m'a été vraiment précieuse et tu m'a mis sur la bonne voie alors je t'en remercie.
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 17 juin 2009 à 16:17
@f0xi : tu écris dans ton premier commentaire que tu crées dynamiquement ton TImageList de la façon suivante :
fImageList := TImageList.Create(self);
Mais tu le libères dans le OnDestroy, alors que tu définis la fiche comme propriétaire de l'objet. N'est-ce pas superflu de libérer cet enfant alors que la fiche, à sa fermeture, devrait s'en occuper ? J'aimerais être fixé sur ce point car j'ai toujours des doutes sur la libération des objets enfants/parents.
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202234 17 juin 2009 à 22:40
non, on libere toutes les ressources créées manuellement de façon manuelle.
si je crée un objet, je libere ce dernier. je ne laisse pas un autre composant s'occuper de sa liberation, SAUF si ce composant saitle faire, peux le faire et le fait car il est prevus pour ça.
en aucuns cas je ne laisse le ramasse miette le faire, en aucuns cas je laisse les composant se drebrouiller entre eux
Guillemouze
Messages postés991Date d'inscriptionsamedi 25 octobre 2003StatutMembreDernière intervention29 août 20136 18 juin 2009 à 13:10
Petite précision sur la source de la violation d'accès :
// Permet d'associer la liste d'images à la liste déroulante.
cmbListeDeroulante.Images.Assign(ListeImages);
Comme l'a dit foxi, "cela est du au fait que les propriétés du style
Images [...] ne sont la que
pour stocker une instance existante d'un objet.", la propriété Images n'est qu'un lien vers ton instance. Il est donc nil à l'origine.
Le code qui tente donc d'être exécuté est :
nil.Assign(ListeImages); d'où l'access violation.