1

TableModelListener defines the interface for an object that listens to changes in a TableModel.

TableModelListener

How to apply this to the JTable, so that it will listen for changes in a DefaultTableModel? Furthermore, after setModel is invoked, shouldn't that functionality be built-in? Why would you not want the JTable to reflect changes to the model?

The reference for defaultTableModel in News points to the same instance as in MessagesController (is this correct?), so why do I have to explicitly invoke setModel on the JTable if the underlying object has been updated?

What's a better way for the JTable to update itself? Perhaps tableChanged?

I don't understand, if both the reference in News and the reference in MessagesController point to different objects, with the same values, why it's necessary to invoke setModel(). After all, News.defaultTableModel now has been updated. Why re-invoke setModel()?

package net.bounceme.dur.nntp;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

public class News {

    private static final Logger LOG = Logger.getLogger(News.class.getName());
    static JFrame frame = new JFrame();
    static JTextPane text = new JTextPane();
    static JSlider slider = new JSlider();
    static MessagesController messagesController = new MessagesController();
    static DefaultTableModel defaultTableModel = new DefaultTableModel();
    static JTable table = new JTable();

    private static void createAndShowGUI() {
        defaultTableModel = messagesController.getDefaultTableModel();
        table.setModel(defaultTableModel);
        table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

            public void valueChanged(ListSelectionEvent evt) {
                java.awt.EventQueue.invokeLater(new Runnable() {

                    public void run() {
                        int row = table.convertRowIndexToModel(table.getSelectedRow());
                        row = Math.abs(row);  //how can this be negative?
                        LOG.fine("row " + row);
                        MessageBean messageBean = messagesController.getMessageBean(row);
                        text.setText(messageBean.getContent());
                        text.setContentType("text/html");
                    }
                });
            }
        });

        slider.setMinimum(1);
        slider.setMaximum(messagesController.getMax());
        slider.setValue(messagesController.getMax());
        slider.addChangeListener(new javax.swing.event.ChangeListener() {

            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                java.awt.EventQueue.invokeLater(new Runnable() {

                    public void run() {
                        int index = slider.getValue();
                        LOG.fine("slider " + index);
                        messagesController.setIndex(index);
                        defaultTableModel = messagesController.getDefaultTableModel();
                        table.setModel(defaultTableModel);
                        table.getSelectionModel().setSelectionInterval(1, 1);
                    }
                });
            }
        });
        table.getSelectionModel().setSelectionInterval(1, 1);
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(3, 1));
        panel.add(table);
        panel.add(text);
        panel.add(slider);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        frame.pack();
        frame.setVisible(true);
        frame.setSize(screenSize);
    }

    public static void main(String args[]) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                createAndShowGUI();
            }
        });
    }
}

Possibly I misunderstand pass-by-value, although I have read that these terms have different meanings depending upon the context.

Thufir
  • 8,216
  • 28
  • 125
  • 273

2 Answers2

3

1) row = Math.abs(row); //how can this be negative?

if isn't there any selected row then code line

int row = table.convertRowIndexToModel(table.getSelectedRow());

returns -1 value, better would be to test if(table.getSelectedRow() > -1) before anything

2) there no reason replace TableModel, nor DefaultTableModel, JTable can returns its TableModel, JTable#getModel

3) not sure from context, but maybe you have look at JTable Sorting and Filtering

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • thanks for clearing up that -1 problem, where I guess -1 is like "false". While I don't understand your main answer, I'll come back and read it again later. I added a link to the end of my question, which is somewhat more general than perhaps stated. I might have to heavily edit my question. – Thufir Apr 26 '12 at 11:09
3

Why do I have to explicitly invoke setModel() on the JTable, if the underlying object has been updated?

You should not.

What's a better way for the JTable to update itself?

Updating the model, TableModel, should fire the events required to notify the view, JTable, to update itself. DefaultTableModel does this for you; AbstractTableModel provides convenient fireXxx() methods for your model to invoke. There's an example of the latter here. See also How to Use Tables: Creating a Table Model.

The creation of a new, empty DefaultTableModel in News appears spurious, as the (unseen) MessagesController model promptly replaces it.

It's also unclear why you use invokeLater() in the ListSelectionListener and the ChangeListener. These methods should already be running on the event dispatch thread. If not, you'll need to synchronize access to any shared data.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I must be doing this wrong. In News I have a Jtable, JFrame, etc -- the view. In MessagesController, POJO bean, I populate the DefaultTableModel. I dunno what I'm doing wrong, beyond the fact that it's not working as expected and as described above. Should I edit the question to reflect new code, or just close the question? – Thufir Apr 29 '12 at 17:17
  • The closer you can get to an [sscce](http://sscce.org/), the better. Any chance you're blocking the EDT on a network operation? See also this `SwingWorker` [example](https://sites.google.com/site/drjohnbmatthews/randomdata). – trashgod Apr 29 '12 at 17:32
  • I don't think so. I'll come back to this at a later point, maybe some time will help to understand the answer(s) better. It's not EDT problem, I'm fairly sure, and it's all on localhost. thanks! – Thufir May 03 '12 at 12:21
  • 1
    @Thufir: FWIW, the [example](https://sites.google.com/site/drjohnbmatthews/randomdata) also works with a `jdbc:h2:tcp://localhost/…` URL; ping me if you update the question. – trashgod May 03 '12 at 18:14
  • 1
    @Thufir: See also this related `TableModelListener` [example](http://stackoverflow.com/a/9155689/230513). – trashgod May 03 '12 at 19:22