[Java] Actualisation d'une JList

Résolu/Fermé
SAKDOSS - 8 déc. 2011 à 20:15
 SAKDOSS - 9 déc. 2011 à 18:21
Bonjour,

J'essai de créer une classe ADList dérivée de la classe JList. La classe ADList contient un argument de type ArrayList<AnnotatedDialog>. Chaque AnnotatedDialog possède un nom de fichier (en String) et le but de l'ADList est de donner la liste des noms de fichiers des AnnotatedDialog figurant dans l'ArrayList.

J'ai créé la classe ADList qui semble fonctionner. Malheureusement, la liste ne s'actualise pas automatiquement. Si j'ajoute un élément dans l'ArrayList, il faut que je click sur mon ADList dans l'interface graphique pour que l'actualisation soit effectuée.

Voici le code de la classe ADList :
----------------
... imports ...
 
public class ADList extends JList{
 
	private ArrayList<AnnotatedDialog> ad;
 
	public ADList(ArrayList<AnnotatedDialog> ad_arg){
 
		ad = ad_arg;
 
		setModel(new ADListModel());
		this.setCellRenderer(new ADListCellRenderer());
	}
 
	/* Methode utilisee pour mettre a jour la liste */
	public void setADL(ArrayList<AnnotatedDialog> ad_arg){	
		ad = ad_arg;
	}
 
	public ArrayList<AnnotatedDialog> getAD(){
		return ad;
	}
 
	public class ADListModel extends AbstractListModel {
 
		public int getSize(){
			return ad.size();
		}
 
		public Object getElementAt(int index){	
			return ad.get(index).getFileName();	
		}
 
	}
 
	private class ADListCellRenderer extends DefaultListCellRenderer{
 
	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean iss, boolean chf){
 
	    	super.getListCellRendererComponent(list, value, index, iss, chf);
	    	return this;
	    }
 
	}
}

----------------

Pour afficher mon ADList, je met l'ADList dans un JPanel puis je met le JPanel dans un JScrollPane puis je met le JScrollPane dans un autre JPanel :
----------------
 
JPanel jp_adl = new JPanel(new GridLayout());
jp_adl.add(monADList);
 
JScrollPane jsp_adl = new JScrollPane();
jsp_adl = new JScrollPane(jp_adl);
 
JPanel jp_frame = new JPanel(new GridBagLayout);
jp_frame.add(jsp_adl, getConstraints(0, 4, 5, 1, 1.0, 0.48 , GridBagConstraints.WEST, GridBagConstraints.BOTH);
 
...
 
public GridBagConstraints getConstraints(int x, int y, int width, int height, double wX, double wY, int anchor, int fill){
 
	GridBagConstraints c = new GridBagConstraints();
 
	c.gridx = x;
	c.gridy = y;
	c.gridwidth = width;
	c.gridheight = height;
	c.weightx = wX;
	c.weighty = wY;
	c.anchor = anchor;
	c.fill = fill;
 
	return c;
}

----------------

Lorsque je modifie l'ArrayList en utilisant la méthode setAD la mise à jour est bien faite mais rien ne semble indiquer au composant graphique de s'acuatliser. Comment puis-je faire cela ? Je me suis trompé quelque part ?
A voir également:

3 réponses

KX Messages postés 16668 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 17 mars 2023 3 004
8 déc. 2011 à 20:48
J'ai du mal à voir où est concrètement utilisée ta liste ad.
Quand tu dis que tu ajoutes un élément à ta liste, il faudrait plutôt avoir une méthode dans ta classe ADList pour faire ça, et qui appellerait directement le model, non ?
0
J'ai essayé d'utiliser le pattern MVC. Le modèle contient et gère les données (notamment un ArrayList<AnnotatedDialog>).

La vue contient donc l'ADList. Elle contient aussi un bouton permettant d'ajouter un AnnotatedDialog. Quand j'appuie sur ce bouton cela ouvre envoie une instruction au modèle qui ajoute un AnnotatedDialog à sa liste. Puis le modèle notify la vue du changement.

Finalement, la vue, pour se mettre à jour, appel la méthode setADL qui change l'ensemble du contenu de la JList. Mais apparemment, changer le contenu de la JList ne fait pas actualiser automatiquement l'affichage.

J'espère que ce n'est pas trop confus. Si tu as d'autres questions n'hésite pas !
0
J'ai trouvé une "solution" qui ressemble plutôt à un contournement. Pour spécifier au ADListModel qu'il y a eu une modification, j'ai ajouté dans la fonction setADL un appel à DefaultListModel.fireContentsChanged. Ce qui me donne la chose suivante :

	public void setADL(ArrayList<AnnotatedDialog> ad_arg){	
		ad = ad_arg;
		((ADListModel)this.getModel()).update();
	}


La fonction update() est une fonction que j'ai ajoutée à ADListModel puisque la méthode fireContentsChanged n'était pas accessible depuis ADList :
		public void update(){
			this.fireContentsChanged(ad, 0, ad.size());
		}


Je trouve que ça fait un peu bidouillage alors que j'essayais de faire un truc propre... Vous en pensez quoi ?
0
KX Messages postés 16668 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 17 mars 2023 3 004
8 déc. 2011 à 23:11
Ce qui n'est pas propre c'est la manière dont tu utilises ad, je trouve ça vraiment bizarre...

Ensuite je ne vois pas l'intérêt de ADListCellRenderer, mais je ne vais pas trop m'avancer là dessus, il faudrait que je testes vraiment ce qu'il en est...

/** Le Model manipule les données */
class ADListModel extends AbstractListModel 
{
	private static final long serialVersionUID = 1;
	
	private ArrayList<AnnotatedDialog> ad;
	
	public ADListModel(ArrayList<AnnotatedDialog> ad_arg)
	{
		ad=ad_arg;
	}
	
	@Override
	public int getSize()
	{
		return ad.size();
	}
	
	@Override
	public Object getElementAt(int index)
	{
		return ad.get(index).getFileName();	
	}
	
	public ArrayList<AnnotatedDialog> getAD()
	{
		return ad;
	}
	
	public void setAD(ArrayList<AnnotatedDialog> ad_arg)
	{
		ad=ad_arg;
	}
}

/** La JList manipule le Model */
public class ADList extends JList
{ 
	private static final long serialVersionUID = 1;
	
	private final ADListModel model;
	
	public ADList(ArrayList<AnnotatedDialog> ad_arg)
	{	
		model = new ADListModel(ad_arg); 
		setModel(model);
	}
	
	public void setADL(ArrayList<AnnotatedDialog> ad_arg)
	{	
		model.setAD(ad_arg);
	}
 
	public ArrayList<AnnotatedDialog> getAD()
	{
		return model.getAD();
	}
}
0
Le ADListCellRenderer me permet de customiser l'affichage. Par exemple pour qu'une ligne sur d'eu soit d'une couleur différente je fais ça :
	public class ADListCellRenderer extends DefaultListCellRenderer{
	    public Component getListCellRendererComponent(
	            JList list,
	    	Object value,   // value to display
	    	int index,      // cell index
	    	boolean iss,    // is the cell selected
	    	boolean chf)    // the list and the cell have the focus
	        {
	        
	    	super.getListCellRendererComponent(list, value, index, iss, chf);
	    	
	        if( index %2 == 1 )
	            this.setBackground(new Color(231, 219, 249));
	    	
	    	return this;
	    }
		
	}


J'ai fais les modifications que tu préconise (ie. passer l'ArrayList<AnnotatedDialog> dans le model et y ajouter les @Override ainsi qu'une méthode setAD). Cependant pour que les changements soient pris en compte, il faut toujours que j'utilise la fonction "fireContentsChanged". La seule modification est que cette fonction est maintenant appellée dans setAD (du modèle) et plus setADL (de la JList).

C'est plus propre mais la mise à jour nécessite toujours fireContentsChanged. Je me dit que si tout était bien fait je n'aurais pas besoin de cet appel et tout devrait se faire tout seul.
0
KX Messages postés 16668 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 17 mars 2023 3 004
9 déc. 2011 à 14:32
Je pense que le problème vient que tu tiens absolument à passer tes données dans ad au lieu d'utiliser directement les données de la liste. Si tu prends DefaultListModel au lieu de AbstractListModel, c'est tout de suite plus simple car tu peux directement faire des get et des set sur tes données.

public class ADList extends JList
{ 
	private static final long serialVersionUID = 1;
	
	private final DefaultListModel model;
	
	public ADList(ArrayList<AnnotatedDialog> ad_arg)
	{	
		model = new DefaultListModel();
		setADL(ad_arg);
	}
	
	public void setADL(ArrayList<AnnotatedDialog> ad_arg)
	{	
		model.clear();
		for (AnnotatedDialog a : ad_arg)
			model.addElement(a);
	}
 
	public ArrayList<AnnotatedDialog> getAD()
	{
		int n=model.getSize();
		
		ArrayList<AnnotatedDialog> ad = new ArrayList<AnnotatedDialog>(n);
		
		for (int i=0; i<n; i++)
			ad.set(i, (AnnotatedDialog) model.get(i));
		
		return ad;
	}
}
0
Effectivement ça marche très bien avec les fonctions clear et addElement ! Je peux donc supprimer ma classe ADListModel.

J'ai juste modifié l'appel de addElement pour lui passer en argument a.getFileName() plutôt que a. Sinon il ne sait pas quoi m'afficher et ça donne des trucs comme ça : model.AnnotatedDialog@19f6a57.

Merci beaucoup de ton aide et du temps que tu as passé à comprendre mon cas tordu et à écrire le code des corrections !
0
KX Messages postés 16668 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 17 mars 2023 3 004
9 déc. 2011 à 17:54
model.AnnotatedDialog@19f6a57 c'est typiquement parce qu'il n'y a pas de toString redéfini pour AnnotatedDialog, là encore je pense que c'est parce qu'il affiche a au lieu de a.getFileName()
0