DefualtTableCellRenderer 中 JTable 中的旧值

Old value in JTable within DefualtTableCellRenderer

几周来我一直在尝试通过使用 RGBtoHSV 更改背景颜色来使 JTable 中的 Cell 闪烁,我可以使用我在网上搜索到的一种方法,但是当涉及到多行时,它似乎不起作用。

我已经尝试创建一个自定义渲染器 class 但仍然无法找到一种方法让旧值与新值在旧值 < 新值时闪烁单元格。

我为单元格获取 oldValue 的所有尝试都失败了,所以它不在那里。我已经尝试 TableCellListener,我发现使用我的 googlefu class 但我不知道如何将其实现到渲染器中,尽管将它实现到 table 是成功的。

DefaultTableCellRenderer cTaxas = new DefaultTableCellRenderer() {

        Color gray = new Color(212, 212, 212);

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column) {
            Component cellComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
                    column);

            if (table.getValueAt(row, column) != null && !isSelected && (row % 2) == 0) {
                cellComponent.setBackground(gray);
                cellComponent.setForeground(Color.BLACK);
            } else if (table.getValueAt(row, column) != null && !isSelected) {
                cellComponent.setBackground(Color.WHITE);
                cellComponent.setForeground(Color.BLACK);
            }

            return cellComponent;
        }

    };
    cTaxas.setHorizontalAlignment(SwingConstants.CENTER);

编辑: 我正在尝试实现类似 TableCellListener.class 我在搜索时发现的东西,但在 DefaultCellRenderer.

之内
public class TableCellListener implements PropertyChangeListener, Runnable {
private JTable table;
private Action action;

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

/**
 * Create a TableCellListener.
 *
 * @param table
 *            the table to be monitored for data changes
 * @param action
 *            the Action to invoke when cell data is changed
 */
public TableCellListener(JTable table, Action action) {
    this.table = table;
    this.action = action;
    this.table.addPropertyChangeListener(this);
}

/**
 * Create a TableCellListener with a copy of all the data relevant to the
 * change of data for a given cell.
 *
 * @param row
 *            the row of the changed cell
 * @param column
 *            the column of the changed cell
 * @param oldValue
 *            the old data of the changed cell
 * @param newValue
 *            the new data of the changed cell
 */
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;
}

/**
 * Get the column that was last edited
 *
 * @return the column that was edited
 */
public int getColumn() {
    return column;
}

/**
 * Get the new value in the cell
 *
 * @return the new value in the cell
 */
public Object getNewValue() {
    return newValue;
}

/**
 * Get the old value of the cell
 *
 * @return the old value of the cell
 */
public Object getOldValue() {
    return oldValue;
}

/**
 * Get the row that was last edited
 *
 * @return the row that was edited
 */
public int getRow() {
    return row;
}

/**
 * Get the table of the cell that was changed
 *
 * @return the table of the cell that was changed
 */
public JTable getTable() {
    return table;
}

//
// Implement the PropertyChangeListener interface
//
@Override
public void propertyChange(PropertyChangeEvent e) {
    // A cell has started/stopped editing

    if ("tableCellEditor".equals(e.getPropertyName())) {
        if (table.isEditing())
            processEditingStarted();
        else
            processEditingStopped();
    }
}

/*
 * Save information of the cell about to be edited
 */
private void processEditingStarted() {
    // The invokeLater is necessary because the editing row and editing
    // column of the table have not been set when the "tableCellEditor"
    // PropertyChangeEvent is fired.
    // This results in the "run" method being invoked

    SwingUtilities.invokeLater(this);
}

/*
 * See above.
 */
@Override
public void run() {
    row = table.convertRowIndexToModel(table.getEditingRow());
    column = table.convertColumnIndexToModel(table.getEditingColumn());
    oldValue = table.getModel().getValueAt(row, column);
    newValue = null;
}

/*
 * Update the Cell history when necessary
 */
private void processEditingStopped() {
    newValue = table.getModel().getValueAt(row, column);

    // The data has changed, invoke the supplied Action

    if (!newValue.equals(oldValue)) {
        // Make a copy of the data in case another cell starts editing
        // while processing this change

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

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

}

我在我的 JTable 中使用了 celllistener,如下所示:

Action action = new AbstractAction() {
public void actionPerformed(ActionEvent e)
{
    TableCellListener tcl = (TableCellListener)e.getSource();
    System.out.println("Row   : " + tcl.getRow());
    System.out.println("Column: " + tcl.getColumn());
    System.out.println("Old   : " + tcl.getOldValue());
    System.out.println("New   : " + tcl.getNewValue());
}
};
TableCellListener tcl = new TableCellListener(table, action);

我试图让这个 class 在 JTables 渲染器中工作,这样我就可以在旧值小于从数据库中提取的新值时刷新 Cell

EDIT2:我希望有人能阐明我如何在渲染器中获取旧值或闪烁单元格的不同方法tables。

单元格渲染器旨在为所有单元格重复使用。它本身派生自 JLabel 并多次用于渲染每个单元格。

这意味着在调用时,必须为当前单元格准备GUI。你做到了。

要让多个单元格在特定值更改时闪烁,需要在每个单元格中保持该状态,或者说在闪烁点的单元格坐标的全局集合或地图中。

假设我们有 3 个闪烁状态 0、1、2,其中一个可以映射到一个整数。

思路如下代码:

Map<Point, Integer> cellsFlash = new HashMap<>();

// In change listener, when needing flashing a cell:
cellsFlash.put(new Point(column, row), 0);

// In the renderer:
Point cellRef = new Point(column, row);
Integer flashOpt = cellsFlash.get(cellRef);
if (flashOpt != null) {
    int flash = flashOpt;
    switch (flash) { ... }
    ++flash;
    if (flash > 2) {
        // End animation:
        cellsFlash.remove(cellRef);
    } else {
        // Next animation step:
        cellsFlash.put(cellRef, flash);
    }
    table.repaint(50L); // Or such
}

当然你可能想要更复杂一点的动画。

您似乎有两个要求

  1. 如何获取旧值
  2. 但是当涉及到多行时,它似乎不起作用。

不太确定它们之间的关系。您一次只能在编辑器中更改一个值,所以我认为您一次只需要闪烁一行的行颜色。

无论如何,这里有一些(十年)旧代码,允许您指定多个单元格、行或列同时闪烁不同的颜色。闪烁会一直持续到您自己停止为止。

所以我想您可以使用 TableCellListener 向致盲渲染器添加一个新的 cell/row。

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.Timer;
import javax.swing.*;
import javax.swing.table.*;

public class TableColor extends JFrame
{
    ColorRenderer colorRenderer;

    public TableColor()
    {
        String[] columnNames = {"Date", "String", "Integer", "Boolean"};
        Object[][] data =
        {
            {new Date(), "A", new Integer(1), new Boolean(true)},
            {new Date(), "B", new Integer(2), new Boolean(false)},
            {new Date(), "C", new Integer(3), new Boolean(true)},
            {new Date(), "D", new Integer(4), new Boolean(false)}
        };

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

            //  Apply background to existing renderer

            public Component prepareRenderer(
                TableCellRenderer renderer, int row, int column)
            {
                Component c = super.prepareRenderer(renderer, row, column);
                colorRenderer.setBackground(c, row, column);
                return c;
            }
        };
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane( table );
        getContentPane().add( scrollPane );

        JButton button = new JButton( "Add Row" );
        button.addActionListener( new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
//              model.addRow( createRow() );
                model.setRowCount( model.getRowCount() + 1 );
                int row = table.getRowCount() - 1;
//              table.changeSelection(row, 0, false, false);
                table.requestFocusInWindow();
                colorRenderer.setRowColor(row, Color.YELLOW);
            }
        });
        getContentPane().add(button, BorderLayout.SOUTH);

        //  Create blinking color renderer

        colorRenderer = new ColorRenderer( table );
        colorRenderer.setCellColor(1, 1, Color.RED);
        colorRenderer.setRowColor(1, Color.GREEN);
        colorRenderer.setRowColor(3, Color.GREEN);
        colorRenderer.setColumnColor(1, Color.BLUE);
        colorRenderer.startBlinking(1000);
    }

    public static void main(String[] args)
    {
        TableColor frame = new TableColor();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setVisible(true);
    }

    /*
    **  Color cell background
    */
    class ColorRenderer implements ActionListener
    {
        private JTable table;
        private AbstractTableModel model;
        private Map colors;
        private boolean isBlinking = true;
        private Timer timer;
        private Point location;

        public ColorRenderer(JTable table)
        {
            this.table = table;
            model = (AbstractTableModel)table.getModel();
            colors = new HashMap();
            location = new Point();
        }

        public void setBackground(Component c, int row, int column)
        {
            //  Don't override the background color of a selected cell

            if ( table.isCellSelected(row, column) ) return;

            //  The default render does not reset the background color
            //  that was set for the previous cell, so reset it here

            if (c instanceof DefaultTableCellRenderer)
            {
                c.setBackground( table.getBackground() );
            }

            //  Don't highlight this time

            if ( !isBlinking ) return;

            //  In case columns have been reordered, convert the column number

            column = table.convertColumnIndexToModel(column);

            //  Get cell color

            Object key = getKey(row, column);
            Object o = colors.get( key );

            if (o != null)
            {
                c.setBackground( (Color)o );
                return;
            }

            //  Get row color

            key = getKey(row, -1);
            o = colors.get( key );

            if (o != null)
            {
                c.setBackground( (Color)o );
                return;
            }

            //  Get column color

            key = getKey(-1, column);
            o = colors.get( key );

            if (o != null)
            {
                c.setBackground( (Color)o );
                return;
            }

        }

        public void setCellColor(int row, int column, Color color)
        {
            Point key = new Point(row, column);
            colors.put(key, color);
        }

        public void setColumnColor(int column, Color color)
        {
            setCellColor(-1, column, color);
        }

        public void setRowColor(int row, Color color)
        {
            setCellColor(row, -1, color);
        }

        private Object getKey(int row, int column)
        {
            location.x = row;
            location.y = column;
            return location;
        }

        public void startBlinking(int interval)
        {
            timer = new Timer(interval, this);
            timer.start();
        }

        public void stopBlinking()
        {
            timer.stop();
        }

        public void actionPerformed(ActionEvent e)
        {
            isBlinking = !isBlinking;

            Iterator it = colors.keySet().iterator();

            while ( it.hasNext() )
            {
                Point key = (Point)it.next();
                int row = key.x;
                int column = key.y;

                if (column == -1)
                {
                    model.fireTableRowsUpdated(row, row);
                }
                else if (row == -1)
                {
                    int rows = table.getRowCount();

                    for (int i = 0; i < rows; i++)
                    {
                        model.fireTableCellUpdated(i, column);
                    }
                }
                else
                {
                    model.fireTableCellUpdated(row, column);
                }
            }
        }
    }
}