触发valueChanged事件后从JTable中删除行

时间:2012-07-24 23:50:25

标签: java swing jtable listselectionlistener

我正在使用ListSelectionListener从所选行更新我的JTextField(countryTxt)。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

public class App {

    JFrame frame = new JFrame();
    JTable table = new JTable();
    DefaultTableModel model = new DefaultTableModel(new Object[][] {},
            new String[] { "Country", "City", "Street" });
    JButton button = new JButton("Remove");
    JTextField countryTxt = new JTextField();

    int row;

    public App() {
        table.setModel(model);
        data();
        table.getSelectionModel().addListSelectionListener(
                new ListSelectionListener() {
                    @Override
                    public void valueChanged(ListSelectionEvent e) {
                        if (!e.getValueIsAdjusting()) {
                            row = table.getSelectedRow();
                            countryTxt.setText((String) model
                                    .getValueAt(row, 0));
                        }
                    }
                });
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                model.removeRow(row);
            }
        });
        frame.add(countryTxt,BorderLayout.NORTH);
        frame.add(new JScrollPane(table), BorderLayout.CENTER);
        frame.add(button, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        frame.setLocationRelativeTo(null);
    }

    public void data() {
        model.addRow(new String[] { "USA", "New York", "First street" });
        model.addRow(new String[] { "Russia", "Moscow", "Second street" });
        model.addRow(new String[] { "Japan", "Osaka", "Osaka street" });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new App();
            }
        });
    }
}

但是,当我选择一行并点击button时,它会让我和ArrayIndexOutOfBounds例外。当我没有在表格中选择一行并单击button时,一切正常。显然,我可以在未触发valueChanged事件时删除一行。所以我的问题是:如何在触发valueChanged事件后删除一行。提前谢谢。

3 个答案:

答案 0 :(得分:3)

一些观察结果:

  • 通过键盘或鼠标选择行正确更新countryTxt字段。

  • 您可以使用控制> - 标签来跳出表格并返回panel

  • 不要使用setBounds();请使用pack()

  • 我在没有MigLayout的情况下测试了您的示例,但我认为这与您的发现无关。

答案 1 :(得分:3)

查看getLeadSelectionIndex()方法

的javadoc
  

从最近一次调用setSelectionInterval(),addSelectionInterval()或removeSelectionInterval()返回第二个索引参数

这不是你所期望的。您最好使用JTable#getSelectedRow(),当然这仍需要您检查它是否与-1不同。

答案 2 :(得分:2)

我不得不追踪一个类似的问题,涉及清单前一段时间。这里的主要问题是按钮监听器对model.removeRow(row)的调用是向模型的选择监听器发送valueChanged事件,然后该选择监听器将尝试使用不存在的选择(即列表索引)更新文本字段-1)。我已经对您的代码进行了这些修复,相关部分标有注释。此代码允许选择/删除项目而不会抛出异常。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

public class App {
    JFrame frame = new JFrame();
    DefaultTableModel model = new DefaultTableModel(new Object[][] {},
            new String[] { "Country", "City", "Street" });
    JTable table = new JTable(model);
    JButton button = new JButton("Remove");
    JTextField countryTxt = new JTextField();

    public App() {
        data();
        table.getSelectionModel().addListSelectionListener(
                new ListSelectionListener() {
                    @Override
                    public void valueChanged(ListSelectionEvent e) {
                        if (!e.getValueIsAdjusting()) {
                            // get the current selected row
                            int i = table.getSelectedRow();
                            // if there is a selected row, update the text field
                            if(i >= 0) {
                               countryTxt.setText((String) model
                                    .getValueAt(i, 0));
                            }
                        }
                    }
                });
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                // get the current selected row
                int i = table.getSelectedRow();
                // if there's no selection, but there are some rows,
                // we'll just delete the first row
                if(i < 0 && model.getRowCount() > 0) {
                   i = 0;
                }

                // if we have a valid row to delete, do the deletion
                if(i >= 0) {
                    countryTxt.setText("");
                    model.removeRow(i);
                    table.revalidate();
                }
            }
        });
        frame.add(countryTxt,BorderLayout.NORTH);
        frame.add(new JScrollPane(table), BorderLayout.CENTER);
        frame.add(button, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        frame.setLocationRelativeTo(null);
    }

    public void data() {
        model.addRow(new String[] { "USA", "New York", "First street" });
        model.addRow(new String[] { "Russia", "Moscow", "Second street" });
        model.addRow(new String[] { "Japan", "Osaka", "Osaka street" });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new App();
            }
        });
    }
}