JTable - Boolean.class 单元渲染器和 Nimbus 外观问题

Posted

技术标签:

【中文标题】JTable - Boolean.class 单元渲染器和 Nimbus 外观问题【英文标题】:JTable - Problems with Boolean.class Cell Renderer and Nimbus Look and Feel 【发布时间】:2013-04-09 21:04:51 【问题描述】:

我正在使用 JTable 来可视化一些数据。一列注定要通过复选框显示布尔数据。我通过从我的表模型中覆盖的 getColumnClass() 函数返回 Boolean.class 来实现这一点。

不幸的是,这会导致一个带有复选框但没有适合当前行的背景颜色的单元格。

我使用这篇文章的答案解决了这个问题:JTable - Boolean Cell Type - Background

现在我试图增加交替行的对比度。我通过设置我正在使用的 Nimbus LAF 的适当属性来实现这一点。

UIDefaults defaults = UIManager.getLookAndFeelDefaults();
defaults.put("Table.alternateRowColor", new Color(217, 217, 217));

如您所见,布尔单元格的背景仍然是旧的 Nimbus Table.alternateRowColor 颜色。

有没有办法改变这种情况?我这样做完全错了吗?有没有更好的方法来实现交替的背景颜色和更高的对比度?

编辑

起因于

java 版本 "1.7.0_17" Java(TM) SE Runtime Environment (build 1.7.0_17-b02) Java HotSpot(TM) 服务器虚拟机(build 23.7-b01,混合模式),操作系统是 Ubuntu 12.04

【问题讨论】:

+1 好问题,好收获,如果您将发布 SSCCE,简短、可运行、可编译,这对于未来的读者来说可能是一个非常好的问题 【参考方案1】:

我(终于)能够让它工作了。秘诀是在创建任何内容之前更改默认值。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.UIResource;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;

public class TestTable10 

    public static void main(String[] args) 
        new TestTable10();
    

    public TestTable10() 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                try 
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                 catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) 
                

                UIManager.getLookAndFeelDefaults().put("Table.alternateRowColor", Color.RED);

                JTable table = new JTable(new MyModel());
                ((JComponent) table.getDefaultRenderer(Boolean.class)).setOpaque(true);


                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            
        );
    

    public class MyModel extends AbstractTableModel 

        @Override
        public int getRowCount() 
            return 10;
        

        @Override
        public int getColumnCount() 
            return 2;
        

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) 
            switch (columnIndex) 
                case 0:
                    return "Hello";
                case 1:
                    return true;
            
            return "?";
        

        @Override
        public Class<?> getColumnClass(int columnIndex) 
            return columnIndex == 0 ? String.class : Boolean.class;
        
    


【讨论】:

谢谢,看起来不错。不幸的是,我在这里使用 Netbeans 平台,因此“在您更改任何内容之前”可能很难确定。我目前正在尝试使用模块安装程序在启动时执行此操作,看看它是如何进行的。我也在尝试@mKorbel 的答案,因为它独立于 LAF。 不错的解决方案。我承认最好改变 L&F 级别的外观,而不是像其他答案建议的那样对其进行硬编码。 @AdamDyga 我看到很多人因为很多原因直接跳起来更新JTable,我对此有个人问题,因为它将解决方案与扩展紧密结合在一起。如果您能找到保持代码可移植性的方法,那么付出努力是值得的,恕我直言【参考方案2】:

我将使用标准渲染器概念来完成这项工作,而不是使用 Nimbus 常量

渲染器适用于 Nimbus,覆盖所有颜色,不包括 JTableHeader

代码基于@camickrs Table Row Rendering

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableRowRenderingTip extends JPanel 

    private static final long serialVersionUID = 1L;

    public TableRowRenderingTip() 
        Object[] columnNames = "Type", "Company", "Shares", "Price", "Boolean";
        Object[][] data = 
            "Buy", "IBM", new Integer(1000), new Double(80.5), Boolean.TRUE,
            "Sell", "Dell", new Integer(2000), new Double(6.25), Boolean.FALSE,
            "Short Sell", "Apple", new Integer(3000), new Double(7.35), Boolean.TRUE,
            "Buy", "MicroSoft", new Integer(4000), new Double(27.50), Boolean.FALSE,
            "Short Sell", "Cisco", new Integer(5000), new Double(20), Boolean.TRUE
        ;
        DefaultTableModel model = new DefaultTableModel(data, columnNames) 
            private static final long serialVersionUID = 1L;

            @Override
            public Class getColumnClass(int column) 
                return getValueAt(0, column).getClass();
            
        ;
        JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.addTab("Alternating", createAlternating(model));
        add(tabbedPane);
    

    private JComponent createAlternating(DefaultTableModel model) 
        JTable table = new JTable(model) 
            private static final long serialVersionUID = 1L;

            @Override
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column) 
                Component c = super.prepareRenderer(renderer, row, column);
                if (!isRowSelected(row))  //  Alternate row color
                    c.setBackground(row % 2 == 0 ? getBackground() : Color.orange);
                
                return c;
            
        ;
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        ((JComponent) table.getDefaultRenderer(Boolean.class)).setOpaque(true);
        return new JScrollPane(table);
    

    public static void main(String[] args) 
        try 
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) 
                if ("Nimbus".equals(info.getName())) 
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                
            
         catch (Exception e) 
            return;
        
        SwingUtilities.invokeLater(new Runnable() 
            @Override
            public void run() 
                createAndShowGUI();
            
        );
    

    public static void createAndShowGUI() 
        JFrame.setDefaultLookAndFeelDecorated(false);
        JFrame frame = new JFrame("Table Row Rendering");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new TableRowRenderingTip());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    

【讨论】:

起初这看起来很棒。但我没有得到和你一样的结果。我的 Boolean.class 列仍然不像其他列。不幸的是,我没有可以在这里发布的SSCCE,但我正在努力。 编辑: 很奇怪。我将您的代码复制到一个新类中,但仍然得到不同的look。 一切都隐藏在你的渲染器中,有一些东西......,请确保你将布尔值(true/false)放入JTable而不是JCheckBox,也没有关于JCheckBox的东西,那么你运气不好,需要覆盖 UIManager 中 JCheckBox 的所有键 正如我在编辑中所说:即使使用您的代码,我也会得到不同的结果。很奇怪.. java version "1.7.0_17" Java(TM) SE Runtime Environment (build 1.7.0_17-b02) Java HotSpot(TM) Server VM (build 23.7-b01, mixed mode), OS是Ubuntu 12.04 或者(通过阅读@MadProgrammer 的评论),GUI builedr 有 onw 错误,它们的生命周期与标准 Oracles JDK 不同,那些框架有 Oracles 和自己的错误 ....【参考方案3】:

为了解决这个问题,我使用了 jxtable() 而不是 jtable(),并且我使用了自己的 prepareRenderer 作为行颜色(你可以使用 mKorbel 的,将它放到 netbeans 中的表格中,只需自定义 jxtable 的代码() 组件),因为此解决方案:JTable - Boolean Cell Type - Background 不适用于我的多色行。我的平台:Windows 7 32bit,java版本“1.7.0_21”, Java(TM) SE 运行时环境 (build 1.7.0_21-b11), Java HotSpot(TM) Client VM(build 23.21-b01,混合模式,共享),netbeans IDE 7.3

这是 png(没有足够的声誉:D):jxtable()。

【讨论】:

【参考方案4】:

在设置 Nimbus L&F 之后,立即添加以下行:

    UIManager.getLookAndFeelDefaults().put("Table:\"Table.cellRenderer\".background", Color.DARK_GRAY);
    UIManager.getLookAndFeelDefaults().put("Table.background",new ColorUIResource(Color.DARK_GRAY));
    UIManager.getLookAndFeelDefaults().put("Table.alternateRowColor",Color.DARK_GRAY.brighter());

注意 Table.background 的 ColorUIResource 的用法。 这为我解决了复选框背景问题。

【讨论】:

以上是关于JTable - Boolean.class 单元渲染器和 Nimbus 外观问题的主要内容,如果未能解决你的问题,请参考以下文章

找到 JTable 单元格并绘制它

合并 JTable 中的单元格

java的swing编程,Jtable的单元格如何赋值

使用单元格格式获取 JTable 整数单元格值

JTable:单击按钮时更改单元格背景

Java - Jtable - 不同颜色的单元格