Erreur de thread sur JTable triée
Bonjour,
J'ai un problème de fonctionnement sur une JTable qui à la fonction de trie activée
classe MainFrame (fenêtre principale) :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class MainFrame extends JFrame {
private static Thread t;
private Discovery objDiscovery;
// ****************************************************
private final JPanel sJPanel1 = new JPanel();
private final JPanel ssJPanel1 = new JPanel();
private final JPanel ssJPanel2 = new JPanel();
private JTable jTable1;
private MyTableModel2 jTableModel1;
private final JButton jButton1 = new JButton("Test");
MainFrame myFrame = this;
// constructeur
public MainFrame(){
super();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(true);
initComposant(); // construction de la fenetre
this.setVisible(true);
this.setSize(600, 400);
run_app(); // lancement des Threads
}
// efface le tableau
private void clearTable(){
while (jTableModel1.getRowCount() != 0){
jTableModel1.removeRow(jTableModel1.getRowCount() - 1);
}
}
// construction de la fenetre
private void run_app(){
// **********************************************************************
objDiscovery = new Discovery();
objDiscovery.addStatusListener(new StatusListener(){
@Override
public void infoMessageDetected(String[] messages, short type){
System.out.print("Discovery.listener");
System.out.print("Discovery.listener.add");
for (String message : messages) {
System.out.print(" " + message);
}
//jTable1.setAutoCreateRowSorter(false);
jTableModel1.addRow(messages); // ajout de la ligne
//jTable1.setAutoCreateRowSorter(true);
}
});
// bouton clear console
jButton1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
clearTable();
objDiscovery.sendDiscoveryMsg();
}
});
t = new Thread(objDiscovery);
t.start();
objDiscovery.sendDiscoveryMsg(); // lance une requete au demarrage
}
// construction de la fenetre
private void initComposant(){
String[] columnNames = {"column 1", "column 2", "column 3", "column 4", "column 5", "column 6"};
Object[][] data = null;
jTable1 = new JTable(new MyTableModel2(data, columnNames));
jTableModel1 = (MyTableModel2)jTable1.getModel(); // pour pouvoir utiliser l'ajout/suppression de lignes
JScrollPane jScrollPane1 = new JScrollPane(jTable1);
jTable1.setFillsViewportHeight(true);
jTable1.setAutoCreateRowSorter(true); // pour activer la gestion de trie
this.setLayout(new BorderLayout());
this.getContentPane().add(sJPanel1, BorderLayout.NORTH);
this.getContentPane().add(jScrollPane1, BorderLayout.CENTER);
sJPanel1.setLayout(new BorderLayout());
sJPanel1.add(ssJPanel1, BorderLayout.WEST);
sJPanel1.add(ssJPanel2, BorderLayout.EAST);
ssJPanel1.add(jButton1);
}
// initialise la Table suivant le modele
private class MyTableModel2 extends DefaultTableModel {
public MyTableModel2(Object[][] data, String[] columnNames) {
super(data, columnNames);
}
@Override
public boolean isCellEditable(int row, int col) {
return false;
}
}
} |
classe Discovery qui envoie des infos vers la JTable pour la remplir
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
import javax.swing.event.EventListenerList;
public final class Discovery implements Runnable {
private boolean stopThread = false; // mettre volatile pour le multi-threading
Integer counter = 9;
boolean sendMessage = false;
// constructeur
public Discovery(){
super();
}
// envoie le message
public void sendDiscoveryMsg(){
sendMessage = true;
}
// reception des data
// lance le thread
@Override
public void run(){
boolean threadOff = false;
while(!threadOff){
if(sendMessage == true){
System.out.println("run.start");
String[] myStr = {"a", "b", "c", "d", "e", "f"};
myStr[0] = counter.toString();
switch(counter){
case 9:
counter = 5;
break;
case 5:
counter = 2;
break;
case 2:
counter = 7;
break;
default:
counter = 9;
sendMessage = false;
break;
}
sendMessage(myStr);
}
synchronized(this) {
threadOff = this.stopThread;
}
}
}
// ferme le thread
public void close(){
this.stopThread = true;
System.out.println("Discovery : close");
}
// ***********************************************************************
// Gestion des messages console (implementation de l'interface StatusListener que j'ai créée)
private final static EventListenerList listeners = new EventListenerList();
// gestion de l'ajout d'un ecouteur a liste listeners
// => on peut ajouter plusieurs type de listener dans la liste (on repere leur type grace a StatusListener.class)
public void addStatusListener(StatusListener listener){
listeners.add(StatusListener.class, listener);
}
// suppression d'un listener dans la liste
public void removeStatusListener(StatusListener listener){
listeners.remove(StatusListener.class, listener);
}
// recupere la liste de tous les abonnés
public StatusListener[] getStatusListener(){
return listeners.getListeners(StatusListener.class);
}
// envoie de l'evenement
//protected void sendMessage(String message, short type){
protected void sendMessage(String[] messages){
System.out.print("DiscoveryMsg : send => " );
for(int i = 0; i<messages.length; i++){
if (i !=0){
System.out.print(" / ");
}
System.out.print(messages[i]);
}
System.out.println(); // fin de la ligne
for(StatusListener listener : getStatusListener()) {
listener.infoMessageDetected(messages, (short) 0);
}
}
} |
interface StatusListener pour la gestion d’événements
Code:
1 2 3 4 5 6
|
import java.util.EventListener;
public interface StatusListener extends EventListener{
public void infoMessageDetected(String[] messages, short type);
} |
Lorsqu'on spam le bouton "test", tout fonctionne bien.
Mais si on appuie sur l’entête de la première colonne pour activer le tri et qu'ensuite on spam le bouton "test", on peut voir dans la console qu'il y a l'erreur suivante qui est générée :
Citation:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.DefaultRowSorter.convertRowIndexToModel(DefaultRowSorter.java:518)
at javax.swing.JTable.convertRowIndexToModel(JTable.java:2642)
at javax.swing.JTable.getValueAt(JTable.java:2717)
at javax.swing.JTable.prepareRenderer(JTable.java:5719)
at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2114)
at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2016)
at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1812)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
at javax.swing.JComponent.paintComponent(JComponent.java:778)
at javax.swing.JComponent.paint(JComponent.java:1054)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5219)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1529)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1452)
at javax.swing.RepaintManager.paint(RepaintManager.java:1249)
at javax.swing.JComponent._paintImmediately(JComponent.java:5167)
at javax.swing.JComponent.paintImmediately(JComponent.java:4978)
at javax.swing.RepaintManager$3.run(RepaintManager.java:808)
at javax.swing.RepaintManager$3.run(RepaintManager.java:796)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:796)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:769)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:718)
at javax.swing.RepaintManager.access$1100(RepaintManager.java:62)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1677)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Remarque : dans la classe MainFrame, si j'active les deux lignes qui sont en commentaire (voir ci-dessous), il n'y a plus d'erreur généré mais le tri ne fonctionne plus.
Code:
1 2 3
| //jTable1.setAutoCreateRowSorter(false);
jTableModel1.addRow(messages); // ajout de la ligne
//jTable1.setAutoCreateRowSorter(true); |
Comment résoudre le problème, je ne trouve vraiment pas la solution ?
Merci d'avance