【问题标题】:Set transparent background on JList在 JList 上设置透明背景
【发布时间】:2018-12-10 15:08:36
【问题描述】:

我正在尝试删除(或只是设置为不可见)我的 JList 的背景和边框。

当我在其上设置透明颜色时,我的 JList 背景保持白色。

这是我的自定义 jcombox 渲染器类:

package Utils.UI.CustomeComboBox;

import Parameter.Model.ThemeEnum;
import Repository.Parameter.ThemeParameterRepository;
import Utils.UI.FileGetter;
import Utils.UI.Utils;

import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import java.awt.*;

public class CustomComboBoxRenderer extends BasicComboBoxRenderer {

    private Image backgroundImage;
    private Font font;
    private final static int WIDTH = 190;
    private final static int HEIGHT = 49;

    public CustomComboBoxRenderer() {
        super();

        this.setOpaque(false);
        this.setHorizontalTextPosition(AbstractButton.CENTER);
        this.setVerticalAlignment(AbstractButton.CENTER);
        this.setPreferredSize(new Dimension(CustomComboBoxRenderer.WIDTH, CustomComboBoxRenderer.HEIGHT));
        this.font = FileGetter.getFont().deriveFont(Utils.DEFAULT_SIZE_BUTTON_TEXT);
    }

    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
    {
        super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        list.setOpaque(false);
        list.setBackground(new Color(255, 0, 0, 0));
        list.setBorder(BorderFactory.createEmptyBorder());
        if (index == -1 || isSelected) {
            this.backgroundImage = FileGetter.getImage("_button13.png");
        } else {
            this.backgroundImage = FileGetter.getImage("_button02.png");
        }

        return this;
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;

        // background image
        g2d.drawImage(this.backgroundImage, 0, 0, this);

        // text
        g2d.setFont(this.font);
        g2d.setColor((Color) ThemeParameterRepository.getColor(ThemeEnum.SECOND_COLOR).getValue());
        FontMetrics fontMetrics = g.getFontMetrics(this.font);
        g2d.drawString(
            this.getText(),
            (CustomComboBoxRenderer.WIDTH - fontMetrics.stringWidth(this.getText())) / 2,
            ((CustomComboBoxRenderer.HEIGHT - fontMetrics.getHeight()) / 2) + fontMetrics.getAscent()
        );

        g2d.finalize();
    }
}

我尝试将setOpaque(false)setBackground(new Color(255, 0, 0, 0)) 放在每个组件上,但没有得到好的结果。

一种解决方案是调整列表内的图像大小,但我的图像不是矩形,因此列表背景的角是可见的。

【问题讨论】:

    标签: java swing jlist paintcomponent jcomponent


    【解决方案1】:

    我认为您不想在单元格渲染器中进行此类更改,因为它负责绘制默认情况下不透明的列表单元格,而不是 JList 本身。

    为什么不在创建 JList 后简单地给它一个透明的背景颜色呢?

     list.setBackground(new Color(0, 0, 0, 0));
    

    但是,如果您这样做,则必须注意在将绘图放置在不透明项目之上时可能出现的绘图伪影。我发现重新绘制包含 JList 的容器可以解决这个问题:

    import javax.swing.*;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.ListSelectionListener;
    
    public class JListTest {
    
    
        private static void createAndShowGui() {
            final JFrame frame = new JFrame("JList Test");
            final JPanel panel = new JPanel();
    
            String[] listData = {"One", "Two", "Three", "Four", "Five", "Six"};
            final JList<String> list = new JList<>(listData);
            // list.setOpaque(false);
            list.setBackground(new Color(0, 0, 0, 0));
            list.addListSelectionListener(new ListSelectionListener() {
    
                @Override
                public void valueChanged(ListSelectionEvent e) {
                    panel.repaint();
                }
            });
    
            panel.add(list);
    
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(panel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    

    请注意,如果 JList 由 JScrollPane 保存,则必须将其组件设置为透明,但如果看不到滚动窗格,我不确定您将如何滚动。

    【讨论】:

      【解决方案2】:

      在测试新概念时,首先使用标准 JDK 类对其进行测试。

      因此,您只需将 JList 和默认渲染器设置为透明即可:

      JList<String> list = new JList<String>(...);
      list.setOpaque(false);
      DefaultListCellRenderer renderer = new DefaultListCellRenderer();
      renderer.setOpaque( false );
      list.setCellRenderer( renderer );
      

      这种方法将使列表和渲染器透明,因此您看到的只是所选单元格的边框。

      现在,一旦您证明基本概念有效,您就可以创建自定义渲染器。如果它不起作用,那么您知道问题出在您的自定义代码上。

      list.setBackground(new Color(255, 0, 0, 0));
      

      不要使用透明颜色设置列表的背景。这是一个已知的 Swing 问题。有关此问题的更多信息,请参阅Backgrounds With Transparency

      此外,您不应更改渲染器中列表的属性。

      其他一些cmets:

      1. 自定义绘制是通过覆盖 paintComponent(...) 而不是 paint() 来完成的。
      2. 不要在绘画方法中设置渲染器组件的属性。也就是说,您应该在构造函数中设置边框和不透明属性,除非这些值发生变化。
      3. 不要在渲染器中进行 I/O。渲染器应读取构造函数中的文件并将图像存储在缓存中以供快速参考。

      【讨论】: