Search code examples
javaswingjpaneltransparencyjlist

Transparent JList smears when selecting elements or scrolling


I have a transparent JList and JScrollPanel on top of a gradient JPanel the code for each of those looks like this:

JPanel midPanel = new JPanel() {
        protected void paintComponent(Graphics g) {
            Paint p = new GradientPaint(0.0f, 0.0f, new Color(233, 220, 0, 0),
             getWidth(), getHeight(), new Color(239, 129, 91, 255), true);
            Graphics2D g2d = (Graphics2D)g;
            g2d.setPaint(p);
            g2d.fillRect(0, 0, getWidth(), getHeight());
        }
    };

List code

    ArrayList<String> songs = new ArrayList<>(Arrays.asList(new String[] {elements...}));
    
    DefaultListModel<String> model = new DefaultListModel<>();
    model.addAll(songs);

    JList<String> songList = new JList<String>(model);

    songList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    songList.setLayoutOrientation(JList.VERTICAL);
    songList.setVisibleRowCount(-1);
    songList.setOpaque(false);
    songList.setCellRenderer(new TransparentListCellRenderer());

    JScrollPane scroller = new JScrollPane(songList);
    scroller.setPreferredSize(new Dimension(400, 250));
    scroller.setOpaque(false);
    scroller.getViewport().setOpaque(false);
    scroller.setBorder(BorderFactory.createEmptyBorder());

    midPanel.add(scroller);

Before anything is touched it looks like this: working image

And after stuff gets selected or scrolling the elements of the list all smear and create this mess: Smeared Image

Does anyone know how to fix this? if I had to guess what was wrong it would be an issue with the gradient because the paintComponet() method is overridden so it's not getting redrawn properly but if that is the case I do not know how to fix it. Any help is much appreciated.


Solution

  • The answer is to wrap the panel in a Container that is a sort of transparent.

    public class AlphaContainer extends JComponent {
        private JComponent component;
    
        public AlphaContainer(JComponent component) {
            this.component = component;
            setLayout( new BorderLayout() );
            setOpaque( false );
            component.setOpaque( false );
            add( component );
        }
    
        /**
         *  Paint the background using the background Color of the
         *  contained component
         */
        @Override
        public void paintComponent(Graphics g) {
            g.setColor( component.getBackground() );
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    }