0

每当单元格的内容与用户的输入匹配时,我想突出显示 JTable 中的特定行。以下代码是我迄今为止所拥有的:

JTable table = new JTable(model) {
    public Component prepareRenderer(
            TableCellRenderer renderer, int row,
            int column) {
        Component c = super.prepareRenderer(renderer,
                row, column);
        if (!isRowSelected(row) ) {
            c.setBackground((hashMapcontainer
                    .containsKey(row)) ? Color.GREEN
                    : getBackground());
        }
        return c;
    }
    @Override
    public boolean isCellEditable(int row, int column) {
        return false;
    }
};

注意:hashMapcontainer是一个hashmap在源文件中全局作用域的。

现在这在某种程度上有效,但是,我将其添加JTable到 aJTabbedPane中的 a 中JFrame。JTables 是在整个程序运行时动态创建的。但是,该prepareRenderer方法会突出显示所有创建的 JTable 中的所有特定单元格。

如何在所有 JTable 中保留单元格以保留自己特定的突出显示单元格,而不是让所有 JTable 中的每个单元格都具有完全相同的突出显示单元格?

提前致谢!

4

3 回答 3

4

渲染器是“橡皮图章”。这基本上意味着他们将以前的设置带到下一个单元格。

您需要做的是提供“默认”行为

if (!isRowSelected(row) ) {
    c.setBackground((hashMapcontainer
        .containsKey(row)) ? Color.GREEN
        : getBackground());
} else {

    // Define the default background color
    // Don't forget to take into the selection state

}

虽然我个人认为prepareRenderer在这种情况下可能是一个公平的解决方案,但您确实应该探索提供基线渲染器的可能性。要做到这一点需要做很多工作,但具有可移植性(如果您更改表实现)以及允许其他人有机会定义给定单元格的突出显示规则的优势,而您基本上只是走了并覆盖了这些规则, 恕我直言。

我还建议看一下JXTable,因为它具有内置突出显示功能

于 2012-08-08T20:42:55.087 回答
3

通常,覆盖基本 Swing 类的方法是一个坏主意。推荐的方法是创建一个Jcomponent实现TableCellRenderer并将其应用于表的setDefaultRenderer(). 请注意,默认情况下,JTable 为 Object、Number 和 Boolean 类型提供其中的 3 个。通常,渲染器看起来像这样:

public class MyRenderer extends JLable, implements TableCellRenderer{
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, 
         boolean isSelected, boolean hasFocus, int row, int column) {
    // Set up default state here 
    c.setBackground(Color.white);
    c.setForeground(Color.black);
    // ...
    if (!isRowSelected(row) ) {
        c.setBackground((hashMapcontainer
                .containsKey(row)) ? Color.GREEN
                : getBackground());
    }
    return c;
}

这为您提供了一个可重用的组件,而不是在您创建它的每个地方都需要扩展 JTable。至于在所有表中选择相同的单元格,这是由于访问全局状态isRowSelectedhashMapContainer不是每个实例状态。所有JComponents 都有 getClientPropertyputClientProperty。这些允许您将自己的状态对象附加到JTable. 然后你的isRowSelectedbecome isRowSelected(table, row),它只是调用:

MyObject myObj = (MyObject)table.getClientProperty("MySelectionProperty");
myObj.isRowSelected(row);

同样,hashMapContainer也可以从表中检索:

MyHashContainer myHash = (MyHash)table.getClientProperty("MyHashContainer");

更新:

这对于动态生成的表几乎相同。表创建将如下所示:

JTable t = new JTable();
// other typical table setup, t.setModel(...); etc
t.setDefaultRenderer(String.class, myRenderer);
t.putClientProperty("MySelectionProperty", new MyObject());
t.putClientProperty("MyHashContainer", new MyHashContainer());

值得注意的是,只要渲染器不携带状态,就不需要为每个表创建一个实例。我通常会创建一个并将其用于我的所有表格。

这是上面渲染器的更新,它不使用全局状态,而是查看表中的属性:

public class MyRenderer extends JLable, implements TableCellRenderer{
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, 
        boolean isSelected, boolean hasFocus, int row, int column) {

        // Pull hashMapContainer from the per-table client properties
        MyHashContainer hashMapcontainer = (MyHashContainer)table.getClientProperty("MyHashContainer");

        // Set defaults as above            

        if (!isRowSelected(table, row) ) {
            // Same as above
        }
        return c;
    }
    // Private method to check for row selection
    private boolean isRowSelected(JTable t, int row) {
        int[] selectedRows = table.getSelectedRows();
        for (int i = 0; i < selectedRows.length; i++) {
            if (selectedRows[i] == row) {
                return true;
            }
         }
         return false;
    }
}
于 2012-08-09T11:20:28.093 回答
0

我希望我的 JTable 使用突出显示颜色显示更新的行,以便轻松查看正在更新的行。我就是这样完成的。该解决方案被实现为传统 TableCellRenderer 的包装器。像这样使用它:

RowHighlighter highlighter = new RowHighlighter(table);
table.setDefaultRenderer(Date.class, highlighter.wrap(new DefaultTableCellRenderer()));

STEPS 和 PERIOD 允许配置(我猜应该是一个参数)高光如何淡入背景。在此示例中,它将在 2 秒内经过 50 步淡化为单元格的背景颜色。这也保留了真实渲染器的背景颜色,包括当前是否选择了行。

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellRenderer;

class RowHighlighter implements TableModelListener, ActionListener {
    
    private static int STEPS = 50;
    private static int PERIOD = 2000;
    
    private Map<Integer, Integer> rowHighlights = new HashMap<>();
    private JTable table;
    
    public RowHighlighter(JTable table) {
        this.table = table;
        table.getModel().addTableModelListener(this);
        Timer timer = new Timer(PERIOD/STEPS, this);
        timer.start();
    }
    
    @Override
    public void tableChanged(TableModelEvent e) {
        int first = e.getFirstRow();
        int last = e.getLastRow();
        for (int i=first; i<=last; i++) {
            rowHighlights.put(i, STEPS);
        }
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        if (rowHighlights.size() == 0)
            return;
        Iterator<Map.Entry<Integer, Integer>> it = rowHighlights.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Integer, Integer> entry = it.next();
            int v = entry.getValue();
            if (v > 1) {
                entry.setValue(v - 1);
            } else {
                it.remove();
            }
        }
        table.repaint();
    }
    
    public TableCellRenderer wrap(TableCellRenderer delegate) {
        return new HighlightingTableCellRenderer(rowHighlights, delegate);
    }
    
    private static class HighlightingTableCellRenderer implements TableCellRenderer {

        private Map<Integer, Integer> rowMap;
        private TableCellRenderer delegate;
        
        public HighlightingTableCellRenderer(Map<Integer, Integer> rowMap, TableCellRenderer delegate) {
            this.rowMap = rowMap;
            this.delegate = delegate;
        }
        
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            Component c = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            Integer v = rowMap.get(row);
            if (v != null) {
                Color background = c.getBackground();
                Color highlight = getColor(v, Color.PINK, background);
                c.setBackground(highlight);
            }
            return c;
        }
        
        private Color getColor(int n, Color from, Color to) {
            float p = ((float)n)/STEPS;
            
            return new Color((int)(from.getRed() * p + to.getRed() * (1-p)),
                    (int)(from.getGreen() * p + to.getGreen() * (1-p)),
                    (int)(from.getBlue() * p + to.getBlue() * (1-p)));
        }
        
    }

}
于 2021-06-18T12:53:18.383 回答