views:

367

answers:

8

I have a JTable extension that has been in use since Java 1.3/1.4 in the project that provided things like column reordering and sorting by clicking on the column. We are upgrading to Java 1.6, and the new JTable stops the old sorting code from working. It would be somewhat extensive rework to fit everything to the new JTable API. Until then is there a way to completely disable those additions in JTable?

Edit: After the further investigation, the problem is centered around the fact that the mouse events on the header are swallowed by Swing in 1.6, and not passed on to the table implementation, even though it sets its own header rendered. So much for vaunted Java backwards compatibility.

So is there a way to get JTable 1.6 to stop? I haven't been able to. Even overriding the UI on the table and the table header didn't help.

+1  A: 

Have you tried JTable.setRowSorter(null) ?

edit : and setAutoCreateRowSorter ? (1. create table, 2. row sorter to null, 3. autocreate sorter to false, 4. set model).

Istao
Yes, unfortunately it didn't help :(
Yishai
I edit my answer, to do a second try :-)
Istao
Unfortunately that did not help either. I even had to hack at that component because it always called the super that passes a model, so that it calls set model later. Still no dice :(
Yishai
A: 
JTable.setAutoCreateRowSorter(false);

Unless the TableRowSorter is set somewhere, I don't think that you have to call setRowSorter(null)

brian_d
+1  A: 

I use this in my JTable subclass and it catches mouse events just fine:

class QueueTable extends JTable {
    public QueueTable() {
        ...
        getTableHeader().addMouseListener(new SortColumnListener(1));
    }
}

The SortColumnListener is implemented like so:

class SortColumnListener extends MouseAdapter {
    SortColumnListener(int column) { ... }

    public void mouseClicked(MouseEvent e) {
        TableColumnModel colModel = QueueTable.this.getColumnModel();
        int columnModelIndex = colModel.getColumnIndexAtX(e.getX());

        if(columnModelIndex == column) {
            // Do stuff
        }
    }
}

This catches mouse events in the SortColumnListener just fine and I can do whatever I want with those events. I have no RowSorter implementation set on the JTable and this works perfectly in Java 5 and Java 6.

For full sourcecode of this class, see: QueueTable.java

Gerco Dries
Yes, I observed that as well - you can add your own listener. But in Java 1.5, I think the point was that a mouse event on the header or on the table was equally propagated without a special listener on the header. At least I think so.
Yishai
They may very well have been, but I would consider that an implementation detail and not a promise from the API. Adding a MouseListener to the TableHeader has always been "the" way to do this afaik.
Gerco Dries
Unfortunately, even explicitly adding a listener and pumping the mouse even through that component (and I debugged it - it thinks it is a regular mouse event) *still* does not get the table to sort through it. Sigh.
Yishai
By the way, thanks for the code. Regarding your SortColumnListner, shouldn't you be using JTable.columnAtPoint? Unless you are assuming that the columns are never rearranged on the table.
Yishai
The columns are indeed never rearranged on this particular table. The layout is fixed.
Gerco Dries
+1  A: 

As I understand it you have two problems here:

  1. Because of the new sorting code in JTable, your sorting does not work.
  2. Even if you disable sorting by setRowSorter(null) or by overriding the setRowSorter(TableRowsorter) to do nothing, it does not work because the events on header are not passed to your JTable.

In that case I think the option for you is to just have your sorting code implemented as TableRowSorter. I am not aware how complex your sorting code is and whether it can map the TableRowSorter API, but this seems to be one more alternative you can try.

naikus
A: 

I tested all possibilities mentioned here on Sun table sort example and they all are working.

Unfortunately there are still many bugs in table sorting. There can not be much done until you post your code here. One possibility is to try out SwingX solution.

amra
Thanks, unfortunately the component that broke is proprietary, and although we bought the source code, I can't post it here.
Yishai
A: 

I solved your problem in your edit:

package jtableheadermouseevent;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/**
 *
 * @author martijn
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        JFrame fr = new JFrame("JTable Header Mouse Listener");
        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final JTable table = new JTable();
        JScrollPane pane = new JScrollPane(table);

        String[][] data = {{"Foo", "Bar"}, {"Baz", "Coffee"}};
        String[] columns = {"Header 0", "Header 1"};

        DefaultTableModel model = new DefaultTableModel(data, columns);
        table.setModel(model);
        fr.add(pane);
        table.getTableHeader().addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                System.out.println("Header clicked : (X: " + e.getX() + ", Y: " + e.getY() + ") With button " + e.getButton() );
                int header = table.getTableHeader().columnAtPoint(e.getPoint());
                System.out.println("This means header " + header + " is clicked!");
            }

        });
        fr.pack();
        fr.setSize(800, 300);
        fr.setVisible(true);
    }

}

This works perfect in Linux, so I suppose also on OSX and Windows. I also tested it after resizing the columns: it still know which columns was pressed. But after reordering the columns, the column which was first "column 0" became "column 1".
But you can always disallow the user to move the columns with this:

table.getTableHeader().setReorderingAllowed(false);

Hope this helps

Martijn Courteaux
yes, that allows me to add an additional listener. Unfortunately, it didn't fix the behavior.
Yishai
+1  A: 

Thanks for everyone's help. I awarded the bounty to the answer that was most helpful in helping me understand the new JTable behavior. Unfortunately, we had no choice but to rip out the old component and replace it with a JXTable. There will be issues, but it got to the point that if the problem were solved, it would be so hackish as to be too unstable, and the best solution for the project was to rip out the antiquated component and move on.

Yishai
A: 

A way to disable sorting when clicking on the header, is to remove all the table header's listeners:

        for(MouseListener listener : table.getTableHeader().getMouseListeners()){
        table.getTableHeader().removeMouseListener(listener);
    }

Then in case you want some other specific action (like column resizing) you could just add a specific listener for that particular action.

rvelaz