Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 23/07/2009, à 17:53

haile_selassie

[JAVA] Soucis avec JTable et focus

Salut,
J'essaie de faire une petite appli comme suit:
Dans une applet, je mets une jtable avec 4 colonnes:
-nom produit
-libelle produit
-quantité
-prix unitaire
ce que j'aimerais faire, c'est: l'applet se lance, le focus est directement donné sur la premier ligne de la première colonne. L'utilisateur tape alors le début d'un nom de produit, puis tape sur entrée. Une Frame apparait lui donnant tous les produits qui commencent par la chaine qu'il a tapée (ces produits sont présents dans une base de données). il en choisit un en se déplaçant avec les flèches, puis tape sur entrée.
Les colonnes "nom produit" et "libelle produit" se remplissent alors avec les valeurs du produit qu'il a sélectionné dans la frame, et le focus passe directement sur "quantité" (qui est à 1 par défaut) l'utilisateur peut alors changer la valeur ou laisser 1. Il appuie alors sur entrée, ce qui va créer une nouvelle ligne, et placer le focus sur la première colonne de cette nouvelle ligne.
Ce que j'ai fait jusqu'à présent : j'ai récupéré un AbstractTableModel qui permet d'ajouter des lignes. Je l'ai modifié à ma guise. J'ai ajouté un keylistener à mon applet de manière à lancer la JFrame lors de l'appui sur entrée. Tout le mécanisme de la JFrame fonctionne: connexion à la bdd pour récupérer les valeurs correspondantes, affichage, puis sélection (là encore grâce à un keylistener). Le problème se situe après avoir appuyé sur entrée pour ajouter une ligne. Cela ajoute bien une ligne, mais quand je tape sur entrée pour voir les résultats possibles, ça ne me montre pas les bons. Un exemple:
Imaginons que dans ma bdd j'ai les produits "chaussure de sport" et "chaussure de randonnée". Je lance mon applet, je tape chaussure, puis j'appuie sur entrée, le programme va donc me proposer dans la Frame les deux articles. Je choisis "chaussure de sport", puis j'appuie sur entrée. Le focus est maintenant sur la colonne "quantité", j'entre la quantité et j'appuie sur entrée. Ca me crée une ligne, et le focus se met sur la première colonne de cette ligne. Si je tape "chaussure" dans cette ligne, le programme ne me montre qu'une seule proposition : "chaussure de sport". Comme si le focus était sur la mauvaise cellule. Pourtant, je ne rêve pas, il est bien sur la bonne hmm

Pour info:
le listener de mon applet:

package listeners;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import presentation.GrilleMatchingChoices;
import presentation.GrilleSaisieApplet;

public class AppletKeyListener extends KeyAdapter {
    GrilleSaisieApplet applet;

    public AppletKeyListener(GrilleSaisieApplet applet) {
	this.applet = applet;
    }

    public void keyPressed(KeyEvent e) {
	int key = e.getKeyCode();

	if (key == KeyEvent.VK_ENTER) {
	    if (applet.getTable().getSelectedColumn() == 2) {
		applet.getTableModelPerso().addligne();
		applet.changerfocus(0, 0);

	    } else if (applet.getTable().getSelectedColumn() == 0) {
		applet.getTable();
		GrilleMatchingChoices tab = new GrilleMatchingChoices((String) applet.getTableModelPerso().getValueAt(
			applet.getTable().getSelectedRow(), 0), applet, applet.getTable().getSelectedRow());
	    }
	}

    }

}

la méthode d'ajout de lignes:

    public void addligne() {
	int i;
	donnees1 = new Object[donnees.length + 1][nomsColonnes.length];
	lignesup1 = new Object[lignesup.length + 1][nomsColonnes.length];
	for (i = 0; i < donnees.length; i++) {
	    donnees1[i] = donnees[i];
	}
	for (int j = 0; j < nomsColonnes.length; j++) { // d�pend de la
	    // fa�on dont vous
	    // g�rez les nombres
	    // (string ou non)
	    if (ctrlcol[j].equalsIgnoreCase("int"))
		donnees1[i][j] = new Integer(0);
	    if (ctrlcol[j].equalsIgnoreCase("long"))
		donnees1[i][j] = new Long(0);
	    if (ctrlcol[j].equalsIgnoreCase("float"))
		donnees1[i][j] = new Float(0);
	    if (ctrlcol[j].equalsIgnoreCase("double"))
		donnees1[i][j] = new Double(0);
	    if (ctrlcol[j].equalsIgnoreCase("string"))
		donnees1[i][j] = "";
	    if (ctrlcol[j].equalsIgnoreCase("char"))
		donnees1[i][j] = "";
	    if (ctrlcol[j].equalsIgnoreCase("date")) {
		Date datejour = new Date();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		donnees1[i][j] = formatter.format(datejour);
	    }
	    if (ctrlcol[j].equalsIgnoreCase("boolean"))
		donnees1[i][j] = vyes;

	}
	donnees = donnees1;
	fireTableDataChanged();
	lignes1 = new Ligne[this.getRowCount()];
	for (i = 0; i < lignes1.length; i++) {
	    lignes1[i] = new Ligne();
	    lignes1[i].index = i;
	}
	for (i = 0; i < lignesup.length; i++) {
	    lignesup1[i] = lignesup[i];
	}
	lignesup = lignesup1;
	lignes = lignes1;
	fireTableDataChanged();
    }

et le code de mon applet:

package presentation;



import java.applet.Applet;

import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.Dimension;

import java.awt.FlowLayout;

import java.awt.Point;

import java.util.ArrayList;

import java.util.List;



import javax.swing.DefaultCellEditor;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.JTextField;

import javax.swing.RowSorter;

import javax.swing.SortOrder;

import javax.swing.event.DocumentEvent;

import javax.swing.event.DocumentListener;

import javax.swing.event.TableModelEvent;

import javax.swing.event.TableModelListener;

import javax.swing.table.TableModel;

import javax.swing.table.TableRowSorter;

import javax.swing.text.BadLocationException;

import javax.swing.text.Document;



import listeners.AppletKeyListener;



public class GrilleSaisieApplet extends Applet implements TableModelListener {

    private static final long serialVersionUID = 1L;

    private String[] nomsColonnes;

    private JTable table;

    javax.swing.JLabel jLabel1;

    private TableModelPerso tableModelPerso;

    private int posilig;



    public void init() {

	tableModelPerso = TableModelPerso.initFirstTable();



	this.setLayout(new BorderLayout());

	table = new JTable(tableModelPerso);

	table.setCellEditor(new MyTableCellEditor());

	table.setColumnSelectionAllowed(true);

	table.setRowSelectionAllowed(true);

	table.setSelectionBackground(Color.BLUE);

	table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

	table.setCellEditor(new MyTableCellEditor());

	table.addKeyListener(new AppletKeyListener(this));

	javax.swing.InputMap inputMap = (javax.swing.InputMap) javax.swing.UIManager.get("Table.ancestorInputMap");

	inputMap.remove(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER, 0));

	JTextField textfield = new JTextField();

	textfield.getDocument().addDocumentListener(new DocumentListener() {

	    public void changedUpdate(DocumentEvent e) {

		printText(e);

	    }



	    public void insertUpdate(DocumentEvent e) {

		printText(e);

	    }



	    public void removeUpdate(DocumentEvent e) {

		printText(e);

	    }



	    private void printText(DocumentEvent e) {

		Document doc = e.getDocument();

		String text = null;

		try {

		    text = doc.getText(0, doc.getLength());

		} catch (BadLocationException e1) {

		    e1.printStackTrace();

		}

		int row = table.getSelectedRow();

		int col = table.getSelectedColumn();

		table.setValueAt(text, table.getSelectedRow(), table.getSelectedColumn());

		table.changeSelection(row, col, false, false);

	    }



	});

	DefaultCellEditor editor = new DefaultCellEditor(textfield);

	table.setDefaultEditor(Object.class, editor);

	//KeyStroke keyS = KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER, 0);



	/*final Action ActionEnter = new AbstractAction() {

	    public void actionPerformed(ActionEvent e) {

		table.getCellEditor().stopCellEditing(); // store user input

		int row = table.getSelectedRow();

		int col = table.getSelectedColumn();

		String val = String.valueOf(table.getValueAt(row, col)).toLowerCase();

		System.out.println(val);

	    }

	};



	table.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "ENTREE");

	table.getActionMap().put("ENTREE", ActionEnter);*/

	/*table.addKeyListener(new KeyAdapter() {

	    public void keyPressed(KeyEvent e) {

		int row = table.getSelectedRow();

		int col = table.getSelectedColumn();

		TableCellEditor editor = table.getColumnModel().getColumn(col).getCellEditor();

		if (editor != null) {

		    JTextField jtf = ((JTextField) (((MyTableCellEditor) editor).getComponent()));



		    KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyChar(), e.getModifiers());

		    char c = e.getKeyChar();

		    if (Character.isLetterOrDigit(c) || Character.isWhitespace(c)) {

			jtf.getCaret().setDot(0);

			jtf.getCaret().moveDot(jtf.getText().length());

			table.setValueAt("", row, col);

		    }

		}

	    }

	});*/



	// pour le tri

	TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(table.getModel());

	List<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>();

	sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING));

	sortKeys.add(new RowSorter.SortKey(0, SortOrder.ASCENDING));

	sorter.setSortKeys(sortKeys);



	table.setRowSorter(sorter);



	for (int i = 0; i < tableModelPerso.getColumnCount(); i++) {

	    table.getColumnModel().getColumn(i).setCellRenderer(new MyCellRenderer(table.getDefaultRenderer(Object.class)));

	}



	int[] vsize = tableModelPerso.getSizecol();

	int tailletot = 0;

	for (int i = 0; i < vsize.length; i++) {

	    table.getColumnModel().getColumn(i).setPreferredWidth(vsize[i]);

	    if (vsize[i] == 0) {

		table.getColumnModel().getColumn(i).setMinWidth(vsize[i]);

		table.getColumnModel().getColumn(i).setMaxWidth(vsize[i]);

	    }

	    tailletot = tailletot + vsize[i];

	}

	table.setPreferredScrollableViewportSize(new Dimension(tailletot + 100, 300));

	JScrollPane avecAsc = new JScrollPane(table);

	jLabel1 = new javax.swing.JLabel();

	jLabel1.setBackground(new java.awt.Color(255, 255, 51));

	jLabel1.setOpaque(true);

	jLabel1.setName("TITRE");

	jLabel1.setPreferredSize(new java.awt.Dimension(55, 20));



	add(jLabel1, BorderLayout.CENTER);

	add(avecAsc, BorderLayout.CENTER);

	table.addMouseListener(new java.awt.event.MouseAdapter() {

	    public void mouseClicked(java.awt.event.MouseEvent evt) {

		posilig = (table.rowAtPoint(evt.getPoint()));

	    }

	});



	JPanel pan = new JPanel();

	pan.setLayout(new FlowLayout());

	this.setSize(700, 700);

	this.add(pan, BorderLayout.SOUTH);

	table.changeSelection(0, 0, false, false);



	//table.editCellAt(0, 0);



    }



    public void tableChanged(TableModelEvent e) {

    }



    public Point getLocation() {

	Point retValue;

	retValue = super.getLocation();

	return retValue;

    }



    public void changerfocus(int row, int col) {

	table.changeSelection(row, col, false, false);

	// table.editCellAt(row, col);

    }



    public String[] getNomsColonnes() {

	return nomsColonnes;

    }



    public TableModelPerso getTableModelPerso() {

	return tableModelPerso;

    }



    public JTable getTable() {

	return table;

    }



    public GrilleSaisieApplet getThis() {

	return this;

    }



}

C'est peut-être un peu long, j'espère que vous aurez le courage de tout lire smile

Autre petit problème : je met une valeur par défaut à la quantité. Mais si l'utilisateur souhaite changer cette valeur, ça concatène la valeur par défaut et celle qu'il a entrée. En gros, si l'utilisateur entre une valeur => effacer la valeur par défaut. Mais je n'ai pas trouvé comment faire.
Voilà, merci à ceux qui pourraient m'aider.

Dernière modification par haile_selassie (Le 23/07/2009, à 17:54)

Hors ligne

#2 Le 24/07/2009, à 04:00

obiwankennedy

Re : [JAVA] Soucis avec JTable et focus

on pourrais voir le code de: GrilleMatchingChoices ?

Sinon pour ton autre problème pourquoi ne pas utilisé un delegate (je sais plus comment on appelle en java) CellRendering un truc comme ça ? pour mettre un Spinners
Voici un exemple pour mettre une comboxbox
http://java.sun.com/docs/books/tutorial … l#combobox


Dans mes logiciels, j'écris ton nom.
SGNGD: SvgGd is Not GD
Rolisteam

Hors ligne

#3 Le 24/07/2009, à 10:12

haile_selassie

Re : [JAVA] Soucis avec JTable et focus

obiwankennedy a écrit :

on pourrais voir le code de: GrilleMatchingChoices ?

Bien sûr:

package presentation;



import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.Dimension;

import java.awt.FlowLayout;

import java.awt.Point;

import java.awt.event.KeyEvent;

import java.sql.ResultSet;

import java.util.ArrayList;

import java.util.List;



import javax.swing.JFrame;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.KeyStroke;

import javax.swing.RowSorter;

import javax.swing.SortOrder;

import javax.swing.event.TableModelEvent;

import javax.swing.event.TableModelListener;

import javax.swing.table.TableModel;

import javax.swing.table.TableRowSorter;



import listeners.MatchingChoicesKeyListener;

import divers.Connexion;

import divers.Produit;



public class GrilleMatchingChoices extends JFrame implements TableModelListener {

    private static final long serialVersionUID = 1L;

    private String[] nomsColonnes;

    private JTable table;

    javax.swing.JLabel jLabel1;

    private TableModelPerso modelPerso;

    private int posilig;

    private GrilleSaisieApplet gridApplet;



    public GrilleSaisieApplet getGridApplet() {

	return gridApplet;

    }



    public GrilleMatchingChoices(String str, GrilleSaisieApplet gridApplet, int selectedRow) {

	this.requestFocus();

	this.gridApplet = gridApplet;

	this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);



	ResultSet rs = Connexion.RequeteResult("select * from produit where nom_produit like '" + str + "%'");

	ArrayList<Produit> match = new ArrayList<Produit>();

	try {

	    while (rs.next()) {

		match.add(new Produit(rs.getString(1), rs.getString(2), rs.getFloat(3)));

	    }

	} catch (Exception e) {

	    e.printStackTrace();



	}

	modelPerso = TableModelPerso.initSecondTable(match);



	this.setLayout(new BorderLayout());

	table = new JTable(modelPerso);

	table.setColumnSelectionAllowed(true);

	table.setRowSelectionAllowed(true);

	table.setSelectionBackground(Color.BLUE);

	table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

	table.addKeyListener(new MatchingChoicesKeyListener(this, gridApplet, selectedRow));

	table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "none");

	// pour le tri

	TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(table.getModel());

	List<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>();

	sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING));

	sortKeys.add(new RowSorter.SortKey(0, SortOrder.ASCENDING));

	sorter.setSortKeys(sortKeys);



	table.setRowSorter(sorter);



	for (int i = 0; i < modelPerso.getColumnCount(); i++) {

	    table.getColumnModel().getColumn(i).setCellRenderer(new MyCellRenderer(table.getDefaultRenderer(Object.class)));

	}



	int[] vsize = modelPerso.getSizecol();

	int tailletot = 0;

	for (int i = 0; i < vsize.length; i++) {

	    table.getColumnModel().getColumn(i).setPreferredWidth(vsize[i]);

	    if (vsize[i] == 0) {

		table.getColumnModel().getColumn(i).setMinWidth(vsize[i]);

		table.getColumnModel().getColumn(i).setMaxWidth(vsize[i]);

	    }

	    tailletot = tailletot + vsize[i];

	}

	table.setPreferredScrollableViewportSize(new Dimension(tailletot + 100, 300));

	JScrollPane avecAsc = new JScrollPane(table);

	jLabel1 = new javax.swing.JLabel();

	jLabel1.setBackground(new java.awt.Color(255, 255, 51));

	jLabel1.setOpaque(true);

	jLabel1.setName("TITRE");

	jLabel1.setPreferredSize(new java.awt.Dimension(55, 20));



	// add(jLabel1, BorderLayout.CENTER);

	add(avecAsc, BorderLayout.CENTER);

	table.addMouseListener(new java.awt.event.MouseAdapter() {

	    public void mouseClicked(java.awt.event.MouseEvent evt) {

		posilig = (table.rowAtPoint(evt.getPoint()));

	    }

	});



	JPanel pan = new JPanel();

	pan.setLayout(new FlowLayout());



	this.add(pan, BorderLayout.SOUTH);

	table.changeSelection(0, 0, false, false);

	this.pack();

	// table.editCellAt(0, 0);

	this.setLocationRelativeTo(null);

	this.setVisible(true);



    }



    public void tableChanged(TableModelEvent e) {

    }



    public Point getLocation() {

	Point retValue;

	retValue = super.getLocation();

	return retValue;

    }



    public String[] getNomsColonnes() {

	return nomsColonnes;

    }



    public TableModelPerso getModelPerso() {

	return modelPerso;

    }



    public JTable getTable() {

	return table;

    }



}

Et son écouteur:

package listeners;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import presentation.GrilleMatchingChoices;
import presentation.GrilleSaisieApplet;

public class MatchingChoicesKeyListener extends KeyAdapter {
    GrilleSaisieApplet applet;
    private GrilleMatchingChoices frame;
    int selectedRow;

    public MatchingChoicesKeyListener(GrilleMatchingChoices frame, GrilleSaisieApplet applet, int selectedRow) {
	this.applet = applet;
	this.frame = frame;
	this.selectedRow = selectedRow;

    }

    public void keyPressed(KeyEvent e) {
	int key = e.getKeyCode();
	System.out.println(key);
	if (key == KeyEvent.VK_ENTER) {
	    // nom du produit
	    applet.getTable().setValueAt(frame.getTable().getValueAt(frame.getTable().getSelectedRow(), 0), selectedRow, 0);
	    // libelle du produit
	    applet.getTable().setValueAt(frame.getTable().getValueAt(frame.getTable().getSelectedRow(), 1), selectedRow, 1);
	    // prix unitaire
	    String value = String.valueOf(frame.getTable().getValueAt(frame.getTable().getSelectedRow(), 2));
	    applet.getTable().setValueAt(value, selectedRow, 3);
	    frame.dispose();
	    applet.changerfocus(selectedRow, 2);
	}
    }
}

Quelques explication: Connexion est juste une connexion à une base de donnée postgresql, et qui marche.
    modelPerso = TableModelPerso.initSecondTable(match); permet d'initialiser mon modèle de table, la fonction est la suivante:

    public static TableModelPerso initSecondTable(ArrayList<Produit> produits) {
	TableModelPerso T;
	Object[][] donnees = new Object[produits.size()][4];

	for (int i = 0; i < produits.size(); i++) {
	    donnees[i][0] = produits.get(i).getNom();
	    donnees[i][1] = produits.get(i).getLibelle();
	    donnees[i][2] = produits.get(i).getPrix();
	}

	String[] titreColonnes = { "Nom", "Libelle", "Prix" };
	boolean[] vcoleditable = new boolean[] { true, true, true };

	String[] ctrlcolemploye = { "String", "String", "String" };
	int[] vsize = { 100, 100, 100 };
	return new TableModelPerso(donnees, // de type Object[][] contient les
		// données
		titreColonnes, // de type String[] contient les entetes de col
		false, // false si édition ,true si sélection uniquement
		vcoleditable, // de type Boolean[] les colonnes modifiables =
		// true
		ctrlcolemploye, // de type String[] classes des col
		// int,long,double,float,string,date,boolean
		vsize); // de type int[] taille des colonnes

    }
obiwankennedy a écrit :

Sinon pour ton autre problème pourquoi ne pas utilisé un delegate (je sais plus comment on appelle en java) CellRendering un truc comme ça ? pour mettre un Spinners
Voici un exemple pour mettre une comboxbox
http://java.sun.com/docs/books/tutorial … l#combobox

Tu penses qu'avec un JSpinner, ça règlerait le problème ?
Je vais tenter, mais je ne suis pas convaincu.
Parce qu'en fait, si tu conseilles d'utiliser un JSpinner pour pouvoir cliquer à la souris dessus, ce n'est pas ce que je veux. J'aurais dû le préciser : je voudrais que tout se fasse au clavier. Question de rapidité, et d'exigence du client ^^

Merci.

Hors ligne

#4 Le 24/07/2009, à 14:52

haile_selassie

Re : [JAVA] Soucis avec JTable et focus

Humpf j'ai quasiment résolu  le problème en faisant un CellEditor :

public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
    JTextField component;
    GrilleSaisieApplet applet;

    public MyTableCellEditor(final GrilleSaisieApplet applet) {
	this.applet = applet;
	System.out.println("selected" + applet.getTable().getSelectedRow());
	component = new JTextField();
	component.addActionListener(new ActionListener() {

	    public void actionPerformed(ActionEvent arg0) {
		if (applet.getTable().getSelectedColumn() == 0) {
		    applet.getTable().changeSelection(applet.getTable().getSelectedRow(), 2, false, false);
		    GrilleMatchingChoices tab = new GrilleMatchingChoices((String) applet.getTableModelPerso().getValueAt(
			    applet.getTable().getSelectedRow(), 0), applet, applet.getTable().getSelectedRow());
		} else if (applet.getTable().getSelectedColumn() == 2) {
		    applet.getTableModelPerso().addligne();
		}
		//table.editCellAt(table.getSelectedRow(), 2);

	    }

	});

    }
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int rowIndex, int vColIndex) {

	((JTextField) component).setText((String) value);
	return component;
    }
    public Object getCellEditorValue() {
	return ((JTextField) component).getText();
    }

}

Le problème est qu'en faisant un "editCellAt", le curseur n'est pas présent dans la cellule, et dans ce cas, l'ActionListener du TextField ne s'enclenche pas hmm
Donc si je comprends bien, il y au moins 3 focus différents sur une cellule :
-un focus où la cellule est juste surlignée, et si on commence à taper, on édite le contenu
-un focus d'édition sans curseur, dont je ne vois pas bien la différence avec le précedent
-un focus d'édition avec curseur, qui agit directement sur le composant "CellEditor" hmm

Dernière modification par haile_selassie (Le 24/07/2009, à 14:54)

Hors ligne