0

2015.5.5 22:11 updated. I found that, when I create a sorter and call setRowSorter() method in the MyTable's construction, afterwards, it will keep the original line number(in which the data still refresh correctly but not easy to discover)even though the dataModel inside is already changed many times which can be proven as printf(getModel().getRowCount()). What's more, MyTable.getAutoCreateRowSorter() always return true. I must explicitly call setAutoCreateRowSorter(true) to fix the issue it if I called setRowSorter(). I am happy but this is still wierd.


[2015.5.5 6:19 updated] I have found a way to access: make a "setRow" with the combination of insertRow() and removeRow() and everytime I update, I setrRow all the rows in the table. It reflect immediately in the UI. BUT there will be a series of error begin with "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Invalid index" and I guess it's about some kiind of swing thread problem because I can see "RepaintManager" or "paint" in the error. It occurs especially when I move the scrollbar when it's running.(but it still occur if I don't move it)

I have a JTable in a JScrollPane in a JFrame. I initial a MyTableModel with a data and use it to Create a JTable.Like this

MyTableModel extends DefaultTableModel{
    Data data;
    //object

    MyTableModel (Data a){
    data = a;
    // do something to initial the table model,like build object[][] and add rows.   
    }
}
class main{
MyTableModel tm = new MyTableModel(data);
Jtable table = new JTable(tm);
JScrollpane jsp = new JScrollpane(table);
JFrame window = new JFrame();
window.getxxxpane().add(jsp);



}

So, as my data is always changing/updating and the changed row is plural and impossible to caculate.

while(true){
    data.change();

    refreshing the table to display the data immediately;

}

my idea is to simply build a new MyTableModel object and set it as the table's model like:

 table.setModel(new MyTableModel(data));   //data had been changed.

which doesn't work. and I tried this:

  tm = MyTableModel(data);
  tm.fireTableDataChanged();

which doesn't work either. and the combination as well:

  MyTableModol nm = new MyTableModel(data); //data had been changed
  table.setModel(nm);
  nm.fireTableDataChanged();

Could someone please give me some clue to change the TableModel object in an unchangable Jtable and update everytime.I dont want to change the tableModel Object because the calculation is huge, instead ,i Want to always create a new object with the construction method's parameter(changed data).

the most worst method is to remove the JScrollpane and rebuild one table/tablemodel/jscrollpane and re-add it, in which I have to call window.setVisible(true). window.repait() doesn't work,either,unless I move it. I create a space-wasting but runnable program for demostration ,which most of them are nonsense.

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Formatter;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

class TM extends DefaultTableModel {
    int[] inside;
    static String[] columnNames = { "Hellium", "Radon",

    };

    TM(int[] data) {
        super(columnNames, 0);
        this.inside = data;
        update();
    }

    void update() {
        Object[][] data = new Object[2][columnNames.length];

        for (int i = 0; i < 2; ++i) {

            data[i][0] = inside[0];

            data[i][1] = inside[1];
           // setValueAt(aValue, row, column);
            addRow(data[i]);

        }
        fireTableDataChanged();
    }

}

class idkName {
    TM tm;
    JButton jb, jb2;
    int data[] = { 1, 2 };
    int data2[] = { 9, 10 };
    JTable table;
    JScrollPane jsp;
    JFrame twindow;

    idkName() {
        JFrame window = new JFrame();
        window.setSize(400, 400);
        window.setLayout(new BorderLayout());
        jb = new JButton("show");
        jb2 = new JButton("change model");
        window.add(jb, BorderLayout.EAST);
        window.add(jb2, BorderLayout.WEST);
        twindow = new JFrame();

        jb.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                tm = new TM(data);
                table = new JTable(tm);
                jsp = new JScrollPane(table);
                twindow.getContentPane().add(jsp);
                twindow.setSize(500, 500);
                twindow.setVisible(true);

            }
        });
        window.setVisible(true);

        jb2.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                // tm = new TM(data2);

                tm = new TM(data2);

                System.out.println(""+tm.getValueAt(0,0));
                tm.fireTableDataChanged(); 
                twindow.setVisible(true); 

            }
        });

    }
}
public class main2 {
    TM tm;
    public static void main(String[] args) {
        idkName i = new idkName();
    }

}
  • @chsdk What does WebSockets have to do with refershing a TableModel? – copeg May 04 '15 at 16:08
  • `which doesn't work` Can you elaborate? Can you provide a working example? If you change the underling TableModel, you can call `fireTableDataChanged` to notify listeners. – copeg May 04 '15 at 16:10
  • 1
    @copeg 1. DefaultTableModel has fireTableDataChanged implemented and correctly, then calling for DefaultTableModel#fireTableDataChanged is duplicate ..., 2. "you can call fireTableDataChanged to notify listeners." == notifiers are implemented in DefaultTableModel too ... – mKorbel May 04 '15 at 16:23
  • 1
    @mKorbel, `then calling for DefaultTableModel#fireTableDataChanged is duplicate` it is unclear (at least to me) in the original question how the data is mapped to the TableModel (eg using DefaultTableModel, or overriding it's TableModel methods with a custom model). Listeners are only notified if the data is changed occurs through DefaultTableModel methods - if using an `AbstractTableModel`, `TableModel`, or DefaultTableModel that is backed by a custom data model then an explicit call may be necessary. – copeg May 04 '15 at 16:33
  • Update the `TableModel` from a `SwingWorker`. – Catalina Island May 04 '15 at 16:51
  • @copeg I recreate a simulate example demos how the data changes. the data changes completely not only its size but most of its elements so I have to recreate a tablemodel initialing with it. – GoogleSearchA May 04 '15 at 17:22
  • @Catalina Island Do I have to use that? Does the simple model recreation is impossible to do what I want because Oracle don't allow it? – GoogleSearchA May 04 '15 at 17:22
  • 1
    For [example](http://stackoverflow.com/a/25526869/230513). – trashgod May 04 '15 at 17:38
  • 1
    @copeg 1. again don't to confuse OP by posting nonsence(ise is better), 2. DefaultTableModel doesnt required any notifiers are important for lifecycle by using TableModel/AbstractTableModel, all those notifiers are implemented and correctly in API (but reduced to two available arrays), 3. Listeners are (reseted) notified correctly too, 4. fireXxxXxx never will be called ouside of XxxTableModel definition (not only desing issue) – mKorbel May 05 '15 at 07:11
  • @mKorbel perhaps my comment didn't come across as understandable as I would have liked, but the answer below explains the message I had hoped to get across. If there is something wrong with that advice then please correct or comment for clarification (at least for my sake so I can learn to stop spreading nonsense). – copeg May 05 '15 at 13:56
  • @GoogleSearchA there are two ways 1. reseting DefaultTableModel.setRowCount(0), then add a new rows from loop, 2a) recreating a DefaultTableModel, 2b) creating a new DefaultTableModel, in both cases this model must be added to JTable, the same steps you must to done by using AbstractTableModel – mKorbel May 05 '15 at 16:48
  • @GoogleSearchA this code is so far from success, to click to DefaultTableModel tag (under your question) – mKorbel May 05 '15 at 16:50
  • @mKorbel What I do now was exactly (2a) :) But I used the setRowSorter(my sorter) only once and cause the unexpected error. And do you mean my code? I think I should rewrite it with SwingWorker because there's still plenty error in the eclipse console. But it seems ok when I run it as packed *.jar. – GoogleSearchA May 05 '15 at 17:55
  • RowSorter has reference frmo XxxTableModel to JTables view, RowSorter to recreted model missing one part of, use 1st choice, then you can't add model, listeners, notifiers at runtime, is simplest, most logical, easy for reading and for write the code, one class, void with two variables (header, data) – mKorbel May 05 '15 at 20:03

1 Answers1

1

If you're going to extend DefaultTableModel, then when the data is changed, you need to update it in DefaultTableModel's internal representation using the setValueAt or setDataVector methods. If you have extensive changes (which it sounds like you do), use the setDataVector method to change all the cells and the table structure at once. Your example code looks like it's missing some updates because it's not pushing the new values in to the DefaultTableModel's data vectors.

But since you have a lot of updates, you're probably better off avoiding DefaultTableModel and just extending AbstractTableModel, using your own custom data storage, and calling the appropriate fireXxx() methods whenever your data changes. This will probably be more efficient in terms of both data conversion and number of events raised.

And then make sure all the event and value change work is done on the AWT event thread, using SwingWorkers or other threading support.

Andrew Janke
  • 23,508
  • 5
  • 56
  • 85
  • Yes, you can just replace the whole model with `setModel`, if you only have an isolated `JTable` and `TableModel`. But it's sometimes not a good approach because a) recreating the whole model is expensive, and b) events are wired up to the model; if you replace it, listeners registered on the old model will not get transferred to the new model. (2,2) and (3): it looks like because your code isn't setting up the `DefaultTableModel`'s internal data vectors. But I can't tell without a full running example. – Andrew Janke May 04 '15 at 23:38
  • "if you replace it, listeners registered on the old model will not get transferred to the new model."What can I do to re-register the listener?and whose listener? If this is impossible ,replacing it will be completely infeasible not just "not a good approach" – GoogleSearchA May 04 '15 at 23:53
  • If your `JTable` is the only listener, then it's fine, because it'll register itself on the new model when you call `setModel`. If you have other listeners, then you'd need to write custom code to track them and re-register them on the new model. – Andrew Janke May 05 '15 at 00:00
  • MyTableModel npt = new MyTableModel(Data); table.setModel(npt); this doesn't work; – GoogleSearchA May 05 '15 at 10:45
  • MyTableModel npt = new MyTableModel(Data) table.setModel(npt); this doesn't work; but this woork MyTableModel npt = new MyTableModel(Data) MyTable np = new MyTable(npt); jspp.setViewportView(np); //jspp is the scrollpane. Do you know why? and (2) I have some problem with this: ptm = new MyTableModel(Data); //ptm is the original reference variable of the tablemodel. table.setModel(ptm); ptm.setRowCount(0); and then the setRowCount() had an error: java.lang.IndexOutOfBoundsException: Invalid range; Do you know why? – GoogleSearchA May 05 '15 at 10:51
  • Your `MyTableModel` and `TM` classes aren't correct, because they're not interacting with `DefaultTableModel` correctly. If you're going to use `DefaultTableModel`, you need to make sure *all* your data updates get pushed back into `DefaultTableModel`'s internal values. To make this easier to figure out, I would forget about `DefaultTableModel` and extend `AbstractTableModel` instead, and just get that to work. – Andrew Janke May 05 '15 at 11:44
  • Sorry; I can't tell from the code in the question whether the constructor is correct now wrt pushing the data into the `DefaultTableModel`. If the constructor is correct, then `oldTable.setModel(newModel)` and `rebuild a JTable with newModel` should both work fine. – Andrew Janke May 05 '15 at 12:55
  • Finally I found that my MyTable class's setModel doesn't work at all and that cause ALL the problem, which I have never overrided it! – GoogleSearchA May 05 '15 at 13:22
  • and I found that, when I create a sorter and call setRowSorter() method in the MyTable's construction, afterwards, it will keep the original line number ( in which the data still refresh correctly but not easy to discover)even though the dataModel inside is already changed many times. and can be proven as printf(getModel().getRowCount();). I must call setAutoCreateRowSorter(true) to fix it. I am happy but this is still wierd. – GoogleSearchA May 05 '15 at 13:38