java Nimbus是否优先于手动定义的渲染器?

xdnvmnnf  于 2022-10-30  发布在  Java
关注(0)|答案(1)|浏览(117)

在Swing(NetBeans 15,Sun JDK 19.0.1)中制作GUI时,我尝试为JTable行设置自定义背景颜色,但遇到了布尔单元格的问题,我似乎无法使所有单元格的背景都一致。请注意,以下代码尝试为整个表绘制背景,但我的目标是一次为一行设置背景;这段代码的唯一目的是突出Nimbus交替行着色和我个人遇到的自定义渲染器之间的奇怪交互。
这个问题似乎已经被大量记录下来了,下面是我所尝试的:
第一次尝试using a custom renderer,像这样:

class MyTableRenderer implements TableCellRenderer {
        private final TableCellRenderer renderer;

        public MyTableRenderer(TableCellRenderer renderer) {
            this.renderer = renderer;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Component c = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,  column);
            //c.setOpaque(true);
            c.setBackground(Color.red);
            return c;
        }
    }

得到了这样的结果:

取消注解c.setOpaque(true);行将产生以下结果:

第二次尝试,通过方法PrepareRenderer(),如文档here,我这样做:

tbl_Correction = new JTable() {
    @Override
    public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
        Component c = super.prepareRenderer(renderer, row, column);
        //((JComponent)c).setOpaque(true);
        c.setBackground(Color.red);
        return c;
    }
};

得到了与前面完全相同的行为,具体到取消注解setOpaque行的细节。
进一步阅读后发现,备用表行着色由Nimbus外观和感觉处理,NetBeans IDE在创建项目时自动配置了Nimbus外观和感觉,因此我尝试在Nimbus配置后添加以下行:导致了这个结果

并得出结论,光轮可能干扰了预期的单元格渲染。的确,完全删除光轮给了我想要的结果,但将UI的其余部分送回了中世纪...
奇怪的是,如果我选择一个单元格,整行都会得到正确的背景,包括布尔单元格:

我在setBackground()方法的javadoc中找到的最后一条相关信息是:It is up to the look and feel to honor this property, some may choose to ignore it.,这让我怀疑,这甚至可以工作,而不是交换光轮的其他东西。
我的结论是:无论我把渲染指令放在哪里,我只能设法改变布尔值的背景,这些布尔值在交替的行之一上,除非该行被选中。
的问题:我是否错过了一些主要的明显的配置步骤?或者也许有一种方法可以禁用Nimbus的表交替行颜色?或者再一次,这是某种已知的问题吗?
(more SO回答:this是不相关的; this不起作用;)
编辑:添加了SSCCE,尽管从IDE中生成的GUI代码并不短。

package tabletest;

import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;

public class NewJFrame extends javax.swing.JFrame {
    public NewJFrame() {
        initComponents();

        // attempt #1        
        /*
        jTable1.setDefaultRenderer(Boolean.class, new MyTableRenderer(jTable1.getDefaultRenderer(Boolean.class)));;
        jTable1.setDefaultRenderer(String.class, new MyTableRenderer(jTable1.getDefaultRenderer(String.class)));;
        */
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable() {
            //attempt #2
            @Override
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
                Component c = super.prepareRenderer(renderer, row, column);
                //((JComponent)c).setOpaque(true);
                c.setBackground(Color.red);
                return c;
            }
        }
        ;

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                { new Boolean(true),  new Integer(1),  new Float(0.1), "asd"},
                { new Boolean(true),  new Integer(2),  new Float(0.2), "lol"},
                {null,  new Integer(3),  new Float(0.3), "xd"},
                {null,  new Integer(4),  new Float(0.4), "ftw"},
                {null,  new Integer(5),  new Float(0.5), "wtf"}
            },
            new String [] {
                "bool", "int", "float", "string"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.Boolean.class, java.lang.Integer.class, java.lang.Float.class, java.lang.String.class
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }
        });
        jScrollPane1.setViewportView(jTable1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(59, 59, 59)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(174, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(25, 25, 25)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(100, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        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 ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new NewJFrame().setVisible(true);
            }
        });
    }

    //attempt #1
    class MyTableRenderer implements TableCellRenderer {
        private final TableCellRenderer renderer;

        public MyTableRenderer(TableCellRenderer renderer) {
            this.renderer = renderer;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Component c = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,  column);
            //c.setOpaque(true);
            c.setBackground(Color.red);
            return c;
        }
    }

    // Variables declaration - do not modify                     
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    // End of variables declaration                   
}
i1icjdpr

i1icjdpr1#

您在问题中写道(关于问题中的代码):
下面的代码尝试为整个表格绘制背景
这是我着手要做的。然而,你也写道:
我的目标是一次设置一行的背景
然后我尝试了一种不同的方法--仍然把整个背景涂成红色,但我希望你能适应下面的代码以满足你的要求。

第一次进场

详情如下:
https://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/color.html的最大值
和此处:
https://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/_nimbusDefaults.html
只需在UIManager类中设置适当的属性,就可以得到您想要的结果,也就是说,将整个JTable的背景设置为红色。除了JTable中显示Boolean值的第一列之外,这对所有列都有效。为此,我创建了一个自定义的[table]单元格渲染器,它基于 Nimbus look-and-feel使用的渲染器。即:

javax.swing.plaf.synth.SynthTableUI.SynthBooleanTableCellRenderer

下面是该渲染器的代码:

class BoolTableCellRenderer extends JCheckBox implements TableCellRenderer {
    private boolean isRowSelected;

    public BoolTableCellRenderer() {
        setHorizontalAlignment(JLabel.CENTER);
        setName("Table.cellRenderer");
    }

    public Component getTableCellRendererComponent(JTable   table,
                                                   Object   value,
                                                   boolean  isSelected,
                                                   boolean  hasFocus,
                                                   int      row,
                                                   int      column) {
        isRowSelected = isSelected;
        if (isSelected) {
            setForeground(unwrap(table.getSelectionForeground()));
            setBackground(unwrap(Color.red));
        }
        else {
            setForeground(unwrap(table.getForeground()));
            setBackground(unwrap(Color.red));
        }
        setSelected((value != null && ((Boolean)value).booleanValue()));
        return this;
    }

    private Color unwrap(Color c) {
        if (c instanceof UIResource) {
            return new Color(c.getRGB());
        }
        return c;
    }

    public boolean isOpaque() {
        return true;
    }
}

我还编写了一个自定义的TableModel

class PrimitivesTableModel extends DefaultTableModel {

    public PrimitivesTableModel(Object[][] data, Object[] columnNames) {
        super(data, columnNames);
    }

    public Class<?> getColumnClass(int columnIndex) {
        Class<?> columnClass;
        switch (columnIndex) {
            case 0:
                columnClass = Boolean.class;
                break;
            case 1:
                columnClass = Integer.class;
                break;
            case 2:
                columnClass = Float.class;
                break;
            case 3:
                columnClass = String.class;
                break;
            default:
                columnClass = Object.class;
        }
        return columnClass;
    }
}

下面是第一种方法的代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class NewsFram {

    private void buildAndDisplayGui() {
        JFrame frame = new JFrame("NewsFram");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(createTable(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JScrollPane createTable() {
        Object[][] data = new Object[][]{{Boolean.valueOf(true), Integer.valueOf(1), Float.valueOf(0.1f), "asd"},
                                         {Boolean.valueOf(true), Integer.valueOf(2), Float.valueOf(0.2f), "lol"},
                                         {null, Integer.valueOf(3), Float.valueOf(0.3f), "xd"},
                                         {null, Integer.valueOf(4), Float.valueOf(0.4f), "ftw"},
                                         {null, Integer.valueOf(5), Float.valueOf(0.5f), "wtf"}};
        String[] columnNames = new String[]{"bool", "int", "float", "string"};
        PrimitivesTableModel model = new PrimitivesTableModel(data, columnNames);
        JTable table = new JTable(model);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.setDefaultRenderer(Boolean.class, new BoolTableCellRenderer());
        JScrollPane scrollPane = new JScrollPane(table);
        return scrollPane;
    }

    public static void main(String[] args) {
        UIManager.put("Table:\"Table.cellRenderer\".background", Color.red);
        UIManager.put("Table.alternateRowColor", Color.red);
        for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                try {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
                catch (ClassNotFoundException |
                       IllegalAccessException |
                       InstantiationException |
                       UnsupportedLookAndFeelException x) {
                    x.printStackTrace();
                }
            }
        }
        EventQueue.invokeLater(() -> new NewsFram().buildAndDisplayGui());
    }
}
第二次接近

此方法不修改UIManager默认值,而是覆盖prepareRenderer方法(在JTable类中)。请注意,此方法还使用与第一种方法相同的TableModel和自定义渲染器。
我覆盖了prepareRenderer方法,而不是创建另一个基于 Nimbus look-and-feel使用的通用JTable单元格渲染器的自定义渲染器,因为该渲染器比SynthBooleanTableCellRenderer复杂得多。
下面是第二种方法的代码:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;

import javax.swing.JCheckBox;
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.plaf.UIResource;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class NewFrame {

    private void buildAndDisplayGui() {
        JFrame frame = new JFrame("NewFrame");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(createTable(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JScrollPane createTable() {
        Object[][] data = new Object[][]{{Boolean.valueOf(true), Integer.valueOf(1), Float.valueOf(0.1f), "asd"},
                                         {Boolean.valueOf(true), Integer.valueOf(2), Float.valueOf(0.2f), "lol"},
                                         {null, Integer.valueOf(3), Float.valueOf(0.3f), "xd"},
                                         {null, Integer.valueOf(4), Float.valueOf(0.4f), "ftw"},
                                         {null, Integer.valueOf(5), Float.valueOf(0.5f), "wtf"}};
        String[] columnNames = new String[]{"bool", "int", "float", "string"};
        PrimitivesTableModel model = new PrimitivesTableModel(data, columnNames);

        @SuppressWarnings("serial")
        JTable table = new JTable(model) {
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
                Object value = getValueAt(row, column);
                boolean isSelected = false;
                boolean hasFocus = false;

                // Only indicate the selection and focused cell if not printing
                if (!isPaintingForPrint()) {
                    isSelected = isCellSelected(row, column);
                    boolean rowIsLead = (selectionModel.getLeadSelectionIndex() == row);
                    boolean colIsLead = (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
                    hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
                }
                Component cmpt = renderer.getTableCellRendererComponent(this,
                                                                        value,
                                                                        isSelected,
                                                                        hasFocus,
                                                                        row,
                                                                        column);
                if (!(value instanceof Boolean)) {
                    cmpt.setBackground(Color.red);
                }
                return cmpt;
            }
        };

        table.setDefaultRenderer(Boolean.class, new BoolTableCellRenderer());
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        JScrollPane scrollPane = new JScrollPane(table);
        return scrollPane;
    }

    public static void main(String[] args) {
        for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                try {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
                catch (ClassNotFoundException |
                       IllegalAccessException |
                       InstantiationException |
                       UnsupportedLookAndFeelException x) {
                    x.printStackTrace();
                }
            }
        }
        EventQueue.invokeLater(() -> new NewFrame().buildAndDisplayGui());
    }
}

相关问题