N.Jourdan
N.Jourdan

Reputation: 600

Set transparent background on JList

I'm trying to remove (or just to set invisible) the background and the borders of my JList.

When I set a transparent color on it my JList background stays white.

enter image description here

This is my custom jcombox renderer class :

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

I tried to put setOpaque(false) and setBackground(new Color(255, 0, 0, 0)) on every components however I had no good results.

One solution is to resize my images inside the list but my images are not rectangle so the corners of the list background are visible.

Upvotes: 1

Views: 1339

Answers (2)

camickr
camickr

Reputation: 324118

When testing a new concept first test it using the standard JDK classes.

So you can do this by just setting the JList and the default renderer to be transparent:

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

This approach will make the list and renderer transparent so all you see is the Border of the selected cell.

Now once you prove the basic concept works, you can create your custom renderer. If it doesn't work then you know the problem is with your custom code.

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

Don't set the background of the list using a transparent color. This is a known Swing issue. See Backgrounds With Transparency for more information on this problem.

Also, you should NOT change the properties of the list in the renderer.

Some other comments:

  1. Custom painting is done by overriding paintComponent(...) not paint().
  2. Don't set properties of the renderer component in the painting method. That is you should set the border and opaque properties in the constructor, unless these values change.
  3. Don't do I/O in the renderer. The renderer should read the files in the constructor and store the image in a cache for fast reference.

Upvotes: 1

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

I don't think that you want to do this sort of change within the cell renderer since that is responsible for drawing the list cells, which are not opaque by default, and not the JList itself.

Instead why not simply give your JList a transparent background color after creating it?

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

But if you do this, you have to watch for drawing artifacts that can occur when placing drawing on top of opaque items. I found that repainting the container holding the JList can fix this:

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

Note that if the JList is held by a JScrollPane then its components must be set to be transparent, but I'm not sure how you'd scroll if you can't see the scrollpane.

Upvotes: 4

Related Questions