java “突出显示” JTable 中的特定行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11872003/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 06:44:30  来源:igfitidea点击:

"Highlighting" specific rows in a JTable

javaswingjtablehighlightjtabbedpane

提问by David

I would like to highlight specific rows in a JTable whenever the contents of the a cell match with an input from the user. The following code is what I have that works thus far:

每当单元格的内容与用户的输入匹配时,我想突出显示 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;
    }
};

Notes: hashMapcontaineris a hashmapthat is globally scoped within the source file.

注意:hashMapcontainerhashmap在源文件中全局作用域的。

Now this works to some extent however, I am adding this JTableto a JTabbedPanethat is within a JFrame. JTables are dynamically created throughout the runtime of the program. However, the prepareRenderermethod causes all the specific cells in all the created JTables to be highlighted.

现在这个工作在一定程度上不过,我加入这JTable一个JTabbedPane是内部的JFrame。JTable 是在程序运行时动态创建的。但是,该prepareRenderer方法会导致所有创建的 JTable 中的所有特定单元格都突出显示。

How can I keep cells in all the JTables to keep their own specific highlighted cells rather than having all the JTables with the same exact highlighted cells in each?

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

Thanks in advance!

提前致谢!

回答by MadProgrammer

The renderers are "rubber stamps". That basically means that they carry there previous settings over to the next cell.

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

What you need to do is provide a "default" behavior

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

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

}

While I personally think that prepareRendererin this case is probably a fair solution, you really should explore the possibly of providing a base line renderer. This is a lot of work to get right but has the advantage of been portable (if you change table implementations) as well as allowing other people the chance to define the highlight rules of a given cell, which you've basically just gone and overridden, IMHO.

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

I'd also suggest taking a look at JXTableas it has in built highlighting

我还建议看看JXTable,因为它在内置突出显示中

回答by Devon_C_Miller

Generally, overriding methods on the basic Swing classes is a bad idea. The recommended approach is to create a Jcomponentthat implements TableCellRendererand apply it to the table with setDefaultRenderer(). Note that by default JTable supplies 3 of these for Object, Number, and Boolean types. Typically, a renderer looks something like this:

通常,覆盖基本 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;
}

This gives you a reusable component, rather than needing to extend JTable every place you create it. As for the same cells selecting in all tables, that is due to isRowSelectedand hashMapContaineraccessing global state instead of per-instance state. All JComponents have getClientPropertyand putClientProperty. These allow you to attach your own state object to a JTable. Then your isRowSelectedbecomes isRowSelected(table, row), which simply calls:

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

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

Like wise the hashMapContainercan also be retrieved from the table:

像明智的hashMapContainer,也可以从表中检索:

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

Update:

更新:

This is pretty much the same for a dynamically generated table. Table creation will look something like this:

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

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());

It's worth noting that as long as the renderer carries no state there is no need to create an instance per table. I'll usually create one and use it for all my tables.

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

Here's an update to the renderer above that does not use global state, rather looks to the table for properties:

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

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;
    }
}