2

我正在处理的程序有问题。简单解释一下,我有一个包含多列和多行的 JTable。当更改值时,特定列具有可编辑的字段,其他列值会根据输入的数据而更改。一切正常,但是当我向 JTable 添加过滤器选项时,对可编辑列所做的更改不会在应用过滤器后按预期更改其他列的值。我附上了几张图片来说明这个问题。

第一个图像显示未过滤的表正常工作。更改 Discount 列的值会将存储在 GPL 列中的相应价格减少输入折扣的百分比,并显示在 SP 列的相应行中。更改 Quantity 列的值会将相应的 SP 列价格乘以输入的数量,并显示在 Total 列的相应行中。

未过滤的表

第二张图片显示过滤后的表格未按预期工作。更改 Discount 或 Quantity 列中的值不会更改预期的列。

过滤表

我在下面添加了包含 2 个类的 SSCCE 代码。第一个是表本身,第二个是表的侦听器。

编辑我已经根据 camickr 的回答更改了课程的代码,现在可以正常工作了。

TableCellChange 类

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.math.MathContext;
import java.text.DecimalFormat;
import java.util.Locale;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

public final class TableCellChange extends JPanel {  

    private static JFrame frameTableCellChange;
    private JPanel panelTable, panelButtons;
    private JButton buttonResetDiscounts, buttonResetQuantities, buttonExit;
    private JTextField textFilterBox, quantityField, discountField;
    private JLabel labelFilter;
    private DefaultTableModel tableModel;
    private JTable table;
    private TableRowSorter<DefaultTableModel> sorter;
    private TableColumn columnDiscount, columnTotal, columnQuantity;
    private TableCellListener tableCellListener;
    private String checkForNull;
    private DecimalFormat decimalFormatUS;
    private Locale localeUSFormat;    
    private BigDecimal valueDiscount, valueGPL, resultDiscount, resultSP, resultTotal,
            backupDiscount = new BigDecimal("0"); 
    private int selectedColumnIndex, selectedRowIndex, valueQuantity, backupQuantity = 1;

    public TableCellChange() {

        super(); 

        panelTable = new JPanel();
        panelButtons = new JPanel();
        setLayout(new BorderLayout());

        createTable();
        createButtons();
        add(panelTable, BorderLayout.NORTH);
        add(panelButtons, BorderLayout.CENTER);

        // Always focus on the JTextField when opening the window
        SwingUtilities.invokeLater(new Runnable()  {
           @Override
           public void run() {  
               textFilterBox.requestFocusInWindow();
           }
        });
    } // -> TableCellChange()

    // Create the buttons for the query result window
    public void createButtons() {
        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints gridcons = new GridBagConstraints();
        gridcons.fill = GridBagConstraints.HORIZONTAL;
        panelButtons.setLayout(gridbag);

        labelFilter = new JLabel("Quick search:");
        gridcons.insets = new Insets(5,0,0,0);
        gridcons.gridx = 0;
        gridcons.gridy = 0;
        gridcons.gridwidth = 2;
        gridbag.setConstraints(labelFilter, gridcons);
        labelFilter.setHorizontalAlignment(JLabel.CENTER);
        panelButtons.add(labelFilter);

        // Create text field for filtering
        textFilterBox = new JTextField();
        gridcons.insets = new Insets(5,0,0,0);
        gridcons.gridx = 0;
        gridcons.gridy = 1;
        gridcons.gridwidth = 2;
        gridbag.setConstraints(textFilterBox, gridcons);
                textFilterBox.getDocument().addDocumentListener(
                new DocumentListener() {
                    @Override
                    public void changedUpdate(DocumentEvent e) {
                        tableFilter();
                    }
                    @Override
                    public void insertUpdate(DocumentEvent e) {
                        tableFilter();
                    }
                    @Override
                    public void removeUpdate(DocumentEvent e) {
                        tableFilter();
                    }
                }); // -> DocumentListener()
        panelButtons.add(textFilterBox);

        // Create the button to reset the discount column to 0%
        buttonResetDiscounts = new JButton("Reset all discounts");
        buttonResetDiscounts.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e)
            {          
                BigDecimal valueGPL, valueTotal;
                int valueQuantity;
                for (int i = 0; i < table.getModel().getRowCount(); i++) {
                    valueGPL = new BigDecimal( table.getModel().
                            getValueAt(i, 2).toString().replaceAll("[$,]", "") );
                    table.getModel().setValueAt("0%", i, 3);   
                    table.getModel().setValueAt(DecimalFormat
                            .getCurrencyInstance(localeUSFormat).format(valueGPL), i, 4);
                    valueQuantity = Integer.parseInt( table.getModel().
                            getValueAt(i, 5).toString() );
                    valueTotal = valueGPL.multiply(new BigDecimal(valueQuantity),
                            new MathContext(BigDecimal.ROUND_HALF_EVEN));
                    table.getModel().setValueAt(DecimalFormat
                            .getCurrencyInstance(localeUSFormat).format(valueTotal), i, 6);
                }
            }
        });         
        gridcons.insets = new Insets(10,0,0,0);
        gridcons.gridx = 0;
        gridcons.gridy = 3;
        gridcons.gridwidth = 1;
        gridbag.setConstraints(buttonResetDiscounts, gridcons);
        panelButtons.add(buttonResetDiscounts);

        // Create button to reset the quantity column to 1 
        buttonResetQuantities = new JButton("Reset all quantities");
        buttonResetQuantities.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e)
            {             
                BigDecimal valueSP;
                for (int i = 0; i < table.getModel().getRowCount(); i++) {                    
                    valueSP = new BigDecimal( table.getModel().
                            getValueAt(i, 4).toString().replaceAll("[$,]", "") );
                    table.getModel().setValueAt("1", i, 5); 
                    table.getModel().setValueAt(DecimalFormat.
                            getCurrencyInstance(localeUSFormat).format(valueSP), i, 6);   
                }
            }          
        });         
        gridcons.insets = new Insets(10,0,0,0);
        gridcons.gridx = 1;
        gridcons.gridy = 3;
        gridcons.gridwidth = 1;
        gridbag.setConstraints(buttonResetQuantities, gridcons);
        panelButtons.add(buttonResetQuantities);

        // Create button for closing the window and releasing resources
        buttonExit = new JButton("Exit");
        buttonExit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e)
            {                
                System.exit(0);
            }
        }); 
        gridcons.insets = new Insets(5,0,0,0);
        gridcons.gridx = 0;
        gridcons.gridy = 5;
        gridcons.gridwidth = 2;
        gridbag.setConstraints(buttonExit, gridcons);
        panelButtons.add(buttonExit);    

    } // -> createButtons()


    // Filters the JTable based on user input
    private void tableFilter() {
        RowFilter<DefaultTableModel, Object> tableRowFilter;// = null;
        // If current expression doesn't parse, don't update
        try {
            tableRowFilter = RowFilter.regexFilter("(?i)" + textFilterBox.
                    getText(), 0, 1, 2);
        } catch (java.util.regex.PatternSyntaxException e) {
            return;
          }
        sorter.setRowFilter(tableRowFilter);       
    } // -> tableFilter

    // Method that creates the JTable
    public void createTable() {

        // Create listener for selecting all text when a text field gains focus
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
        .addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener() {
        @Override
           public void propertyChange(final PropertyChangeEvent e) {
               if (e.getNewValue() instanceof JTextField) {
                   SwingUtilities.invokeLater(new Runnable() {
                       @Override
                       public void run() {
                           JTextField textField = (JTextField)e.getNewValue();
                           textField.selectAll();
                       }
                   });
               }
           }
        });

        String[] columnNames = {"Model", "Description", "GPL", "Discount", "SP",
                "Quantity", "Total"};

        Object[][] data = {
            {"MR16", "desc1", "$649.00", "0%", "$649.00", new Integer(1), "$649.00"},
            {"MR24", "desc2", "$1,199.00", "0%", "$1,199.00", new Integer(1), "1,199.00"},
            {"MR62", "desc3", "$699.00", "0%", "$699.00", new Integer(1), "$699.00"},
            {"MR66", "desc4", "$1,299.00", "0%", "$1,299.00", new Integer(1), "$1,299.00"},
            {"MX80", "desc5", "$1,995.00", "0%", "$1,995.00", new Integer(1), "$1,995.00"},
            {"MX90", "desc6", "$3,995.00", "0%", "$3,995.00", new Integer(1), "$3,995.00"},
            {"MX400", "desc7", "$15,995.00", "0%", "$15,995.00", new Integer(1), "$15,995.00"},
            {"MX600", "desc8", "$31,995.00", "0%", "$31,995.00", new Integer(1), "$31,995.00"},
            {"MS22-HW", "desc9", "$1,999.00", "0%", "$1,999.00", new Integer(1), "$1,999.00"},
            {"MS42-HW", "desc10", "$3,499.00", "0%", "$3,499.00", new Integer(1), "$3,499.00"},

        };

        // Create the TableModel and populate it  
        tableModel = new DefaultTableModel(data, columnNames) {
            Class [] classes = {String.class, String.class, String.class,
                String.class, String.class, int.class, String.class, Boolean.class};                
            @Override
            public Class getColumnClass(int column) {
                return classes[column];
            }
        };

        // Create a JTable and populate it with the content of the TableModel
        table = new JTable(tableModel) {
            @Override
            public boolean isCellEditable(int row, int column) {
                if (column == 0 || column == 1 || column == 2 || column == 4 ||
                        column == 6) {
                    return false;
                }
                return true;
            }
        };

        // This sorter is used for text filtering
        sorter = new TableRowSorter<>(tableModel);
        for (int column = 3; column < 6; column++) {
            sorter.setSortable(column, false);
        }
        table.setRowSorter(sorter);

        columnTotal= table.getColumnModel().getColumn(6);
        columnTotal.setPreferredWidth(100);

        // Filter user input in the quantity text field to only allow digits
        discountField =new JTextField();
        discountField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e)
            {
                if(!Character.isDigit(e.getKeyChar()) && e.getKeyChar() !=KeyEvent.VK_BACK_SPACE) {
                    discountField.setEditable(false);
                    discountField.setBackground(Color.WHITE);
                } else {
                    discountField.setEditable(true);
                }
            }
        });

        // Set the text field to the cells of the quantity column 
        columnQuantity = table.getColumnModel().getColumn(5);
        columnQuantity.setCellEditor(new DefaultCellEditor (discountField));

        // Filter user input in the discount text field to only allow digits
        quantityField =new JTextField();
        quantityField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e)
            {
                if(!Character.isDigit(e.getKeyChar()) && e.getKeyChar() !=KeyEvent.VK_BACK_SPACE) {
                    quantityField.setEditable(false);
                    quantityField.setBackground(Color.WHITE);
                    //JOptionPane.showMessageDialog(null,"Only digit input is allowed!");
                } else {
                    quantityField.setEditable(true);
                }
            }
        });

        // Set the text field to the cells of the quantity column 
        columnDiscount = table.getColumnModel().getColumn(3);
        columnDiscount.setCellEditor(new DefaultCellEditor(discountField));

        // Create an US number format
        localeUSFormat = Locale.US;
        decimalFormatUS = (DecimalFormat) DecimalFormat.getInstance(localeUSFormat);
        decimalFormatUS.setMaximumFractionDigits(2);

        // Create abstract action which listens for changes made in the JTable  
        Action actionTableListener = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {

                TableCellListener tcl = (TableCellListener)e.getSource();
                // Get the current row and column index of the table
                selectedRowIndex = tcl.getRow();
                selectedColumnIndex = tcl.getColumn();  
                TableModel model = tcl.getTable().getModel();

                // Have a string variable check for null cell value 
                checkForNull = model.getValueAt(selectedRowIndex,selectedColumnIndex).toString();

                // Change the discounted and total price values 
                if (selectedColumnIndex == 3) {

                    // Check if the discount value is null and replace with 
                    // last used value if true                   
                    if (checkForNull.equals("")) {
                        model.setValueAt(backupDiscount + "%",selectedRowIndex, selectedColumnIndex);
                        return;
                    }

                    // Get the discount value and replace the '%' with nothing
                    valueDiscount = new BigDecimal(( model
                            .getValueAt(selectedRowIndex,selectedColumnIndex)
                            .toString().replaceAll("[%]","") ));
                    // 
                    model.setValueAt(valueDiscount + "%",selectedRowIndex, selectedColumnIndex);

                    // Check if the discount value is greater than 100
                    if ( (valueDiscount.compareTo(new BigDecimal(100)) == 1 ) ) {
                        model.setValueAt(backupDiscount + "%",selectedRowIndex, selectedColumnIndex);
                        JOptionPane.showMessageDialog(null,"Discount cannot be more than 100%.");
                    } else {
                        backupDiscount = valueDiscount;
                        valueDiscount = valueDiscount.divide(new BigDecimal(100)
                                , 2, BigDecimal.ROUND_HALF_EVEN);

                        // Calculate SP and Total values based on the discount input
                        valueGPL = new BigDecimal( ( model
                                .getValueAt(selectedRowIndex,selectedColumnIndex - 1)
                                .toString().replaceAll("[$,]","") ) );
                        // Get the quantity value
                        valueQuantity = Integer.parseInt( ( model
                                .getValueAt(selectedRowIndex,selectedColumnIndex + 2)
                                .toString() ) );
                        // Calculate the new discount value
                        resultDiscount = valueGPL.multiply(valueDiscount, 
                                new MathContext(BigDecimal.ROUND_HALF_EVEN));
                        // Calculate the new SP value
                        resultSP = valueGPL.subtract(resultDiscount, 
                                new MathContext(BigDecimal.ROUND_HALF_EVEN));
                        // Calculate the new result value
                        resultTotal = resultSP.multiply(new BigDecimal(valueQuantity), 
                                new MathContext(BigDecimal.ROUND_HALF_EVEN));
                        // Display the new SP value
                        model.setValueAt(DecimalFormat.getCurrencyInstance(localeUSFormat)
                                .format(resultSP),selectedRowIndex, selectedColumnIndex + 1);
                        // Display the new Total value
                        model.setValueAt(DecimalFormat.getCurrencyInstance(localeUSFormat)
                                .format(resultTotal),selectedRowIndex, selectedColumnIndex + 3);
                      }
                }
                // Change the total price values based on the quantity column 
                if (selectedColumnIndex == 5) {
                    // Check if the quantity value is null and replace with 
                    // last used value if true
                    if (checkForNull.equals("")) {
                        model.setValueAt(backupQuantity,selectedRowIndex, selectedColumnIndex);
                        return;
                    }

                    // Change total price value based on the quantity column
                    resultSP = new BigDecimal( ( model.
                            getValueAt(selectedRowIndex,
                            selectedColumnIndex - 1).toString().replaceAll("[$,]","") ) );
                    valueQuantity = Integer.parseInt( ( model.getValueAt(selectedRowIndex,
                            selectedColumnIndex).toString() ) );

                    // Check if the value quantity is over a certain limit
                    if (valueQuantity <= 0 || valueQuantity >= 999999) {
                        model.setValueAt(backupQuantity,selectedRowIndex, selectedColumnIndex);
                        JOptionPane.showMessageDialog(null,"Quantity value is too high or invalid!");
                    } else {

                        // If the value is under the limit: backup the new quantity
                        // value, calculate the new total value and display it
                        backupQuantity = valueQuantity;
                        resultTotal = resultSP.multiply(new BigDecimal(valueQuantity),
                                new MathContext(BigDecimal.ROUND_HALF_EVEN));
                        model.setValueAt(DecimalFormat.getCurrencyInstance(localeUSFormat)
                                .format(resultTotal), selectedRowIndex, selectedColumnIndex + 1);
                      }
                } 

            }
        }; // -> AbstractAction() 

        tableCellListener = new TableCellListener(table, actionTableListener);
        table.setPreferredScrollableViewportSize(table.
               getPreferredSize());       
        table.setRowHeight(22);

        setVisibleRowCount(table,10);

        table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
        table.setFillsViewportHeight(true);
        table.getTableHeader().setReorderingAllowed(false);
        table.getTableHeader().setResizingAllowed(false);
        panelTable.add(new JScrollPane(table));
    } // -> createTable() 

    // Method to display a fixed number of rows in the JTable viewport
    public static void setVisibleRowCount(JTable table, int rows){ 
        int height = 0; 
        for(int row=0; row<rows; row++) {
            height += table.getRowHeight(row);
        } 
        table.setPreferredScrollableViewportSize(new Dimension( 
            table.getPreferredScrollableViewportSize().width, height )); 
     }

      // Create and display the contents of the frame
      public static void showGUI() {
        // Disable boldface controls
        UIManager.put("swing.boldMetal", Boolean.FALSE);

        // Create the frame
        frameTableCellChange = new JFrame("Table frame");
        frameTableCellChange.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     
        frameTableCellChange.addWindowListener(new WindowAdapter() {
            @Override
                public void windowClosing(WindowEvent we) {
                System.exit(0);
            }
        });

        // Create and set up the content pane.
        TableCellChange newContentPane = new TableCellChange();
        newContentPane.setOpaque(true); //content panes must be opaque
        frameTableCellChange.setContentPane(newContentPane);

        // Arrange and display the window.
        frameTableCellChange.pack(); //must be called first 
        frameTableCellChange.setLocationRelativeTo(null); //center window
        frameTableCellChange.setResizable(false); 
        frameTableCellChange.setVisible(true);        
      } //-> showQueryResultGUI() 

   public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
         try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.
                    UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException |
                IllegalAccessException |
                javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(TableCellChange.class.getName()).
                    log(java.util.logging.Level.SEVERE, null, ex);
        }
        // Display the frame and it's contents      
        TableCellChange.showGUI();
            }
        });
    } //-> main(String[] args)      

} //-> TableCellChange class

编辑这个类是由 Rob Camick(又名 camickr)创建的,所有的功劳都归功于他创建了这段很棒的代码。为了遵守字符限制,仅从代码中删除了注释。

TableCellListener 类

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.Action;
import javax.swing.JTable;
import javax.swing.SwingUtilities;

/*
 *  This class listens for changes made to the data in the table via the
 *  TableCellEditor. When editing is started, the value of the cell is saved
 *  When editing is stopped the new value is saved. When the old and new
 *  values are different, then the provided Action is invoked.
 *  The source of the Action is a TableCellListener instance.
 */
public class TableCellListener implements PropertyChangeListener, Runnable {
    private JTable table;
    private Action action;

    private int row;
    private int column;
    private Object oldValue;
    private Object newValue;

    public TableCellListener(JTable table, Action action) {
        this.table = table;
        this.action = action;

        this.table.addPropertyChangeListener(this);
    }

    private TableCellListener(JTable table, int row, int column, Object oldValue, Object newValue) {
        this.table = table;
        this.row = row;
        this.column = column;
        this.oldValue = oldValue;
        this.newValue = newValue;
    }

    public int getColumn() {
        return column;
    }

    public Object getNewValue() {
        return newValue;
    }

    public Object getOldValue() {
        return oldValue;
    }

    public int getRow() {
        return row;
    }

    public JTable getTable() {
        return table;
    }
    @Override
    public void propertyChange(PropertyChangeEvent e) {  
        if ("tableCellEditor".equals(e.getPropertyName())) {
            if (table.isEditing()) {
                processEditingStarted();
            } else {
                processEditingStopped();
            }
        }
    }

    private void processEditingStarted() {
        SwingUtilities.invokeLater(this);
    }
    @Override
    public void run() {
        row = table.convertRowIndexToView(table.getEditingRow());
        row = table.getEditingRow();

        column = table.convertColumnIndexToModel(table.getEditingColumn());

        oldValue = table.getModel().getValueAt(row, column);
        newValue = null;
    }

    private void processEditingStopped() {
        newValue = table.getModel().getValueAt(row, column);   
        if (!newValue.equals(oldValue)) {

            TableCellListener tcl = new TableCellListener(
                getTable(), getRow(), getColumn(), getOldValue(), getNewValue());

            ActionEvent event = new ActionEvent(
                tcl,
                ActionEvent.ACTION_PERFORMED,
                "");
            action.actionPerformed(event);
        }
    }
}

我知道在过滤表时,表视图的索引会发生变化,并且必须与底层模型的索引同步。为了使过滤表工作,如何做到这一点?

4

2 回答 2

5

您错误地实现了 TableCellListener 的操作。您不能使用选定的行/列,因为这些值在表格视图中。TableCellListener 在模型上工作。

查看Table Cell Editor提供的示例操作。要获取已更改的行/列,您必须引用 TableCellListener 本身。

编辑:

这是我的简单文本示例。当您更改“价格”时,“价格变化”和“价值”列会自动更新。

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import javax.swing.table.*;

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

    public static void createAndShowGUI()
    {
        String[] columnNames = {"Stock", "Shares", "Price", "Price Change", "Value"};
        Object[][] data =
        {
            {"IBM",    new Integer(100),  new Double(85),  new Double(0), new Double(8500)},
            {"Apple",  new Integer(300),  new Double(30),  new Double(0), new Double(9000)},
            {"Sun",    new Integer(1500), new Double(5),   new Double(0), new Double(7500)},
            {"Google", new Integer(100),  new Double(100), new Double(0), new Double(10000)}
        };

        DefaultTableModel model = new DefaultTableModel(data, columnNames)
        {
            public Class getColumnClass(int column)
            {
                return getValueAt(0, column).getClass();
            }

            public boolean isCellEditable(int row, int column)
            {
                return column == 2;
            }
        };

        JTable table = new JTable(model);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);

        //  Add a sorter

        TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<DefaultTableModel>(model);
        table.setRowSorter(sorter);

        //  Filter

        try
        {
            RowFilter<DefaultTableModel, Object> rf = RowFilter.regexFilter("l", 0);
            sorter.setRowFilter(rf);
        }
        catch (java.util.regex.PatternSyntaxException e) {}

        Action action = new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                TableCellListener tcl = (TableCellListener)e.getSource();
                int column = tcl.getColumn();

                if (column == 2)
                {
                    int row = tcl.getRow();
                    double oldPrice = ((Double)tcl.getOldValue()).doubleValue();
                    double newPrice = ((Double)tcl.getNewValue()).doubleValue();
                    TableModel model = tcl.getTable().getModel();

                    double priceChange = new Double(newPrice - oldPrice);
                    model.setValueAt(priceChange, row, 3);

                    double shares = ((Integer)model.getValueAt(row, 1)).doubleValue();
                    Double value = new Double(shares * newPrice);
                    model.setValueAt(value, row, 4);
                }
            }
        };

      TableCellListener tcl = new TableCellListener(table, action);

        JFrame.setDefaultLookAndFeelDecorated(true);
        JFrame frame = new JFrame("Table Cell Listener");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( scrollPane );
        frame.setSize(400, 160);
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}
于 2013-04-20T20:15:00.113 回答
4

您可能需要进行从视图到模型的转换。看看如何使用表格教程的排序和过滤部分:

当表使用排序器时,用户看到的数据可能与数据模型指定的顺序不同,并且可能不包括数据模型指定的所有行。用户实际看到的数据称为视图,并且有自己的一组坐标。JTable 提供了从模型坐标转换为视图坐标的方法——convertColumnIndexToView 和 convertRowIndexToView——以及从视图坐标转换为模型坐标的方法——convertColumnIndexToModel 和 convertRowIndexToModel。

编辑:从视图(表)转换为模型:

替换这些行:

row = table.convertRowIndexToView(table.getEditingRow());
row = table.getEditingRow();

和:

row = table.convertRowIndexToModel(table.getEditingRow());
于 2013-04-20T16:43:17.733 回答