[JAVA] Redéfinir le renderer d'une JList - en incluant un JTextArea dedans

Bonjour :hello:

BOn, le truc est tout bête. J’ai une JList, pour laquelle j’ai redéfinit le renderer pour ses éléments. Ce qui me donne :

http://img162.imageshack.us/img162/8764/extentions4lr.th.png

Chaque cellule de cette JList est donc un JPanel, dans lequel j’ai placé 2 JLabel et un JTextArea. Le soucis, c’est que je voudrais “wrapper” le JTextArea. Seulement voilà, lorsque je le fais, le texte sur les lignes suivantes est mangé, je ne vois que la première ligne dans tous les cas (j’ai joué sur les setPreferredSize à fond, mais rien…).

Je cherche donc une solution, pour éviter que le scroll horizontal apparaîsse.
Une idée ?

Tu as bien une solution barbare : redéfinir JList pour que tes renderers soient en fait les composants de ta list.

Pour le reste, le renderer c’est pour faire un composant sans focus/etc, et je pense que ça doit pas trop aimer?

Bah en fait, j’ai vu une solution barbare à l’adresse http://forum.java.sun.com/thread.jspa?thre…ssageID=4104647 (avec du code testable), mais c’est vraiment très lourd, et je ne sais pas si je peux l’adapter à mon cas (vu que moi c’est un renderer qui implémente un JPanel, dans lequel j’ai un JTextArea).

Et j’ai constaté, en faisant des petites recherches sur le net, que le même phénomène se produit avec une JTable, avec dans les cellules des JTextArea.

J’ai pensé à autre chose, est-ce faisable de faire la mise en forme de caractère dans un JTextArea (ou autre, comme JTextPane) ? Je n’ai jamais testé, car jamais trop compris comment on s’y prenait. Si c’est faisable, ca pourrait sûrement me permettre de faire que le JTextArea (ou JTextPane) soit directement mon renderer (au lieu du JPanel qui contient tout le reste). Je ne sais pas trop où ca peut me mener, mais ca peut me permettre de reprendre le code proposé dans le lien ci-dessus.

Et puis, pour finir, je dois pouvoir aussi sélectionné les éléments de la liste (voir, pouvoir double cliquer dessus).

Bref, si qqun trouve une solution, je suis vraiment très interessé !!!

EDIT : je dis une bêtise, avec une JTable ca semble faisable … après, si c’est faisable, c’est autre chose ^^

Pour ta question, oui c’est faisable :slight_smile: en manipulant le modèle Document.

Sinon essaye : <html><b>Foo</b> truc</html>

eh eh :slight_smile:

Alors, j’ai bidouillé à mort mon renderer. Et je me suis aperçu que le rafraîssement ne permet pas de redimensionner la cellule de la liste. Il y a cependant une méthode que je n’ai pas tester, supprimer puis rajouter à la même position la cellule dont la taille est à modifier (mais ca, ca serait plus dans le cas où je souhaite rajouter un élément, chose que je ne prévois pas de faire).

Donc, comme le rafraîssement ne permet pas de redimenssionner la cellule (pour pouvoir faire afficher tout mon JTextArea, rappelons le ^^), et bien j’ai calculé la taille au moment de la construction de la liste, avant le premier affichage. Normalement, tous les yeux s’ouvrent en grand : Comment ?

J’ai définit un constructeur dans mon renderer, qui initialise tous ce qui est affichage et emboitage d’éléments. Comme ma fenêtre est de taille fixe (et que je connais sa taille), et bien j’ai défini une taille fixe initialise pour mon JTextArea avant qu’il soit afficher. Au moment où la liste appelle la fameuse méthode getComponentBlabla…, et bien je calcule la hauteur du JTextArea en fonction du texte dedans, et je lui fixe sa hauteur (pour un JTextArea, la fonction setRows). Et ca passe !!!

La preuve en image :
http://img167.imageshack.us/img167/8631/extentions38xi.th.png

Le bout de code :

public class PluginManagerListCellRenderer extends JPanel
  implements ListCellRenderer {

	private JLabel name;
	private JLabel category;
	private JTextArea description;
	private JButton boutonExecuter;
	private JPanel container;

	public PluginManagerListCellRenderer( JList list ) {

  super( new BorderLayout() );
  setBorder( BorderFactory.createCompoundBorder(
    BorderFactory.createMatteBorder( 0, 0, 1, 0, Color.lightGray ),
    BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) ) );
  setOpaque( false );

  Font styleSimple = (new JLabel( "font" )).getFont();
  Font styleGras = new Font( styleSimple.getName(),
    Font.BOLD, styleSimple.getSize() );

  name = new JLabel();
  name.setFont( styleGras );
  name.setOpaque( false );

  category = new JLabel();
  category.setFont( styleSimple );
  category.setOpaque( false );

  description = new JTextArea();
  description.setBorder( BorderFactory.createEmptyBorder( 5, 0, 0, 0 ) );
  description.setEditable( false );
  description.setFont( (new JLabel()).getFont() );
  description.setOpaque( false );
  description.setLineWrap( true );
  description.setWrapStyleWord( true );

  boutonExecuter = new JButton( "Executer" );
  JPanel boutonPanel = new JPanel( new FlowLayout( FlowLayout.RIGHT ) );
  boutonPanel.add( boutonExecuter );
  boutonPanel.setOpaque( false );

  JPanel p1 = new JPanel( new BorderLayout() );
  p1.add( name, BorderLayout.NORTH );
  p1.add( category, BorderLayout.CENTER );
  p1.setOpaque( false );

  JPanel p2 = new JPanel( new BorderLayout() );
  p2.add( p1, BorderLayout.WEST );
  p2.add( boutonPanel, BorderLayout.EAST );
  p2.setOpaque( false );

  container = new JPanel( new BorderLayout() );
  container.add( p2, BorderLayout.NORTH );
  container.add( description, BorderLayout.SOUTH );
  container.setBorder( BorderFactory.createEmptyBorder( 5, 5, 5, 5 ) );

  Dimension d = description.getPreferredSize();
  d.setSize( 635, d.getHeight() );
  description.setPreferredSize( d );

  add( container, BorderLayout.CENTER );
	}

	public Component getListCellRendererComponent(
  	JList list,
  	Object value,
  	int index,
  	boolean isSelected,
  	boolean cellHasFocus ) {

  if( isSelected || list.getSelectedIndex()==index ) {
  	name.setForeground( list.getSelectionForeground() );
  	category.setForeground( list.getSelectionForeground() );
  	description.setForeground( list.getSelectionForeground() );
  	container.setBackground( list.getSelectionBackground() );
  	boutonExecuter.setEnabled( true );
  	boutonExecuter.setUI( (new JButton()).getUI() );
  } else {
  	name.setForeground( (new JLabel()).getForeground() );
  	category.setForeground( (new JLabel()).getForeground() );
  	description.setForeground( (new JLabel()).getForeground() );
  	container.setBackground( list.getBackground() );
  	boutonExecuter.setEnabled( false );
  	boutonExecuter.setUI( null );
  }

  if( value instanceof Plugin ) {
  	Plugin plugin = (Plugin) value;
  	name.setText( plugin.getName() );
  	category.setText( " [ " + plugin.getCategory() + " ]" );
  	description.setText( plugin.getDescription() );

  	int largeurTexte = (description.getFontMetrics( description.getFont() )).stringWidth( description.getText() );
  	int hauteurFont = description.getFontMetrics( description.getFont() ).getHeight();
  	int largeurContainer = (int) description.getPreferredSize().getWidth();
  	int hauteurTexte = (int) ( largeurTexte / largeurContainer ) + 1;
  	description.setRows( hauteurTexte );

  	//System.out.println( "largeurTexte=" + largeurTexte );
  	//System.out.println( "hauteurFont=" + hauteurFont );
  	//System.out.println( "largeurContainer=" + largeurContainer );
  	//System.out.println( "hauteurTexte=" + hauteurTexte );
  	//System.out.println();
  }

  return this;
	}

}

Bon alors, certe, ca me suffit. Mais ca n’est quand même pas ce que je voulais au départ. Je rappelle le pb, faire que tout soit automatique, sans avoir à spécifier de taille (donc sans avoir à faire une pseudo initialisation foireuse au départ). Voilà, le problème reste entier ^^ Je suis ouvert à toute proposition !

Le reste, j’ai constaté qu’un bouton dans un renderer de JList ne peut pas être actionner. J’ai penser à simuler l’action du bouton, mais ca fait là aussi un truc vraiment barbare ^^ Faudrait peut-être mieux que je passe par un JPanel tout bête au lieu de la JList (ou une JTable, mais j’ai tenté, et ca passe vraiment moins bien) …

éventuellement, essaye de mettre un CellEditor. C’est la seule façon pour avoir le focus. Sinon, tu dois pouvoir le faire avec un JPanel + FlowLayout.

erf … dans une JList j’ai pas vu comment faire pour mettre un CellEditor :grrr: (marrant ce smiley ^^)

Bref oué, je pense que je vais retenter l’histoire de la JTable, maintenant que j’ai trouvé comment régler la JList. Il ne doit pas y avoir de grosses différences.

Plutôt les ComboBox en fait :slight_smile: que tu peux faire afficher de la même façon qu’une JLIst.

Mais dans ton cas, je crains que le mieux soit de truquer ça avec un composant spécifique.

J’ai trouvé ton idée d’utiliser une JComboBox intéressante.
En effet, dedans on peut spécifier le renderer et l’editor.

Mais visiblement, ca ne semble pas fonctionner. J’ai spécifié mon renderer (it’s ok), et malheureusement je ne trouve pas où dire à la JComboBox d’afficher plusieurs lignes au lieu d’une seule, et enlever la popup.

Bon, ca semble bon. J’ai réécrit du code, j’ai refait une liste personnelle à base de JPanel, et de MouseListener pour les selections. L’affichage et l’action sont identiques aux screenshots plus haut.

La cellule est en fait un JPanel sur laquelle j’ai mis un MouseListener. Quand je clique, je change les couleurs, et je déselectionne l’ancienne cellule sélectionnée.

Mais j’ai tout de même un soucis, quand je clique dans mon JTextArea, la sélection de la cellule ne se fait pas. J’ai supprimer les MouseListener du JTextArea, mais ca ne fait rien, j’ai aussi mis à setFocusable( false ), et ca ne fait rien non plus. Quelqu’un aurait-il une idée pour faire qu’un JTextArea soit “transparent” au niveau du clic de souris ?