在细胞选择jtable事件之前

时间:2011-10-29 00:09:14

标签: java swing jtable

当要选择单元格时是否会触发任何事件?有ListSelectionListener,但它只有在选择发生后触发的事件。我需要某种方法来取消选择事件并使用ListSelectionListener它并不容易,因为选择已经发生并且我需要一些状态变量来指示选择是正常还是取消之前的选择。

有没有办法关闭选择通知?然而,这不是100%好的解决方案(如果一些侦听器在其本地存储中保存选择状态会有问题)这总比没有好。

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.ListSelectionModel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.JTable;

public class JTableExample extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 6040280633406589974L;
    private JPanel contentPane;
    private JTable table;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JTableExample frame = new JTableExample();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public JTableExample() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        table = new JTable(new MyTableModel());
        ListSelectionModel selectionModel = table.getSelectionModel();
        selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        selectionModel.addListSelectionListener(new MySelectionListener());
        contentPane.add(table, BorderLayout.CENTER);
    }

    class MyTableModel extends AbstractTableModel {
        /**
         * 
         */
        private static final long serialVersionUID = -8312320171325776638L;

        public int getRowCount() {
            return 10;
        }

        public int getColumnCount() {
            return 10;
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            return rowIndex * columnIndex;
        }
    }

    class MySelectionListener implements ListSelectionListener {
        public void valueChanged(ListSelectionEvent e) {
            int selectedRow = table.getSelectedRow();
            if (selectedRow == 5) {
                System.out.println("I would like this selection never happened.");
            }
        }
    }

}

3 个答案:

答案 0 :(得分:6)

无论你想达到什么目标:认为“mouseEvent”还不够,选择可能因其他原因而改变(f.i.键盘输入,程序触发器......)。恢复侦听器中未经改变的更改不是一种选择:正如您已经指出的那样,需要保留选区的副本并且可能会混淆其他侦听器。

唯一的方法(我认为,可能是其他人,当然;-)首先是不要让它发生:实现List SelectionModel,如果不改变选择,满足某些条件。我最喜欢的(有偏见的:-)是VetoableListSelectionModel它是DefaultListSelectionModel的子类,在SingleSelectionMode中,在实际更改之前等待来自感兴趣方的否决。

这是使用它的(原始)代码段:

    VetoableListSelectionModel vetoableSelection = new VetoableListSelectionModel();
    VetoableChangeListener navigationController = new VetoableChangeListener() {

        public void vetoableChange(PropertyChangeEvent evt)
                throws PropertyVetoException {
            // custom method that implements your condition 
            if (!canSelect((int) evt.getOldValue(), (int) evt.getNewValue()))
                throw new PropertyVetoException("uncommitted changes",
                        evt);
        }

    };
    vetoableSelection.addVetoableChangeListener(navigationController);
    myTable.setSelectionModel(vetoableSelection);

答案 1 :(得分:1)

我能想到的唯一方法是处理MouseEvent并使用MouseAdapters,获取坐标并以某种方式检查鼠标指针是否悬停在单元格上,如果它是,做你想做的事。您可能必须addMouseListener才能获得效果。

答案 2 :(得分:1)

假设您已将ListSelectionModel的选择模式设置为所需的值并添加了一个侦听器,您可能会发现检查谓词getValueIsAdjusting()很有帮助,“返回true如果选择正在经历一系列变化。“实际上,当鼠标停止或以true模式之一拖动时,它为INTERVAL

这可能也有助于更多地了解这项工作的目标,因为另一种方法可能会有所帮助。当然,sscce始终是有序的。

附录:这似乎有效,但@ kleopatra的approach会阻止丢失先前的选择。

private static final int FORBID = 5;
class MySelectionListener implements ListSelectionListener {

    public void valueChanged(ListSelectionEvent e) {
        int selectedRow = table.getSelectedRow();
        if (selectedRow == FORBID) {
            selectionModel.removeIndexInterval(FORBID, FORBID);
            System.out.println(FORBID + " forbidden.");
        }
    }
}
  如果用户未接受他在该行中所做的更改,则禁止用户更改行。

您可以使用条件为stopCellEditing()的自定义CellEditor,如example所示。