简体   繁体   中英

Unexpected event order when clicking on row in Swing JTable

The default behaviour when clicking on a row in a JTable appears to be...

1 event=javax.swing.event.ListSelectionEvent[ source=javax.swing.DefaultListSelectionModel 673443626 ~{0} firstIndex= 0 lastIndex= 0 isAdjusting= true ]
2 mousePressed
3 event=javax.swing.event.ListSelectionEvent[ source=javax.swing.DefaultListSelectionModel 673443626 ={0} firstIndex= 0 lastIndex= 0 isAdjusting= false ]
4 mouseReleased
5 mouseClicked

Even though the mouse click is initiating the action the JTable event sneaks in before mousePressed. Why is it not...

1 mousePressed
2 event=javax.swing.event.ListSelectionEvent[ source=javax.swing.DefaultListSelectionModel 673443626 ~{0} firstIndex= 0 lastIndex= 0 isAdjusting= true ]
3 event=javax.swing.event.ListSelectionEvent[ source=javax.swing.DefaultListSelectionModel 673443626 ={0} firstIndex= 0 lastIndex= 0 isAdjusting= false ]
4 mouseReleased
5 mouseClicked

The behaviour I was after is

  1. click on a row
  2. in mousePressed, check is row selected?
  3. no - just select row.
  4. yes - perform some action.

What happens at the moment is that both steps 3 & 4 happen at once when clicking on an unselected row. There is no mouse event which can be used to detect if the row is selected or not - it will always be selected.

Or to put it another way...when you mouse-click on a row in JTable how can you test during the click event whether the row was not selected just prior to the click event?

Here is an SSCCE...

import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class JTableRowSelectTest {

    public static void main(String args[]) {

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Object rowData[][] = {{"Row1-Column1"}, {"Row2-Column1"}};
        Object columnNames[] = {"Column One"};
        final JTable table = new JTable(rowData, columnNames);

        table.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
                final int row = table.rowAtPoint(e.getPoint());
                if (row >= 0 && table.isRowSelected(row)) {
                    System.out.println("mouseClicked on selected row");
                } else {
                    // never reached.
                    System.out.println("mouseClicked on un-selected row");
                }
            }

            @Override
            public void mousePressed(MouseEvent e) {
                final int row = table.rowAtPoint(e.getPoint());
                if (row >= 0 && table.isRowSelected(row)) {
                    System.out.println("mousePressed on selected row");
                } else {
                    // never reached.
                    System.out.println("mousePressed on un-selected row");
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("mouseReleased");
            }

            @Override
            public void mouseEntered(MouseEvent e) {
            }

            @Override
            public void mouseExited(MouseEvent e) {
            }
        });

        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                System.out.println(e);
            }
        });

        frame.add(table, BorderLayout.CENTER);
        frame.setSize(300, 150);
        frame.setVisible(true);

    }
}

I already had this problem: determine which event has triggered selection change. The solution is:

if (EventQueue.getCurrentEvent() instanceof MouseEvent) {
  // handler for mouse
} else if (EventQueue.getCurrentEvent() instanceof KeyEvent) {
  // handler for key
}

Simply use it in your ListSelectionListener. I'm not sure whether this approach is absolutely correct, but it worked for me.

Thanks to @mKorbel. There is another possibility to check whether the selection change was made per mouse or keyboard. Details here .

Here is my solution although it feels like a bit of a hack and a bit smelly in that you have to use information from another event - getValueIsAdjusting(). It will only work in mousePressed() as well.

import java.awt.BorderLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class JTableRowSelectTest {

    private static boolean isValueAdjusting = false;

    public static void main(String args[]) {

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Object rowData[][] = {{"Row1-Column1"}, {"Row2-Column1"}};
        Object columnNames[] = {"Column One"};
        final JTable table = new JTable(rowData, columnNames);

        table.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("mouseClicked");
            }

            @Override
            public void mousePressed(MouseEvent e) {
                final int row = table.rowAtPoint(e.getPoint());
                if (row >= 0 && table.isRowSelected(row) && !isValueAdjusting) {
                    System.out.println("mousePressed on selected row " + row);
                } else {
                    System.out.println("mousePressed on un-selected row " + row);
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("mouseReleased");
            }

            @Override
            public void mouseEntered(MouseEvent e) {
            }

            @Override
            public void mouseExited(MouseEvent e) {
            }
        });

        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            @Override
            public void valueChanged(ListSelectionEvent e) {
                isValueAdjusting = e.getValueIsAdjusting();
                System.out.println(e);
            }
        });

        frame.add(table, BorderLayout.CENTER);
        frame.setSize(300, 150);
        frame.setVisible(true);

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM