Matthew Whitlock
Matthew Whitlock

Reputation: 43

ImageIcon stops changing when I make my frame's background transparent?

For some reason, when I run "frame.setBackground(new Color(1.0f,1.0f,1.0f,0.0f));", then change my button's icon and repaint (even with paintImmediately) the icon of my button refuses to change. Just commenting out that line has it working again, but I kinda want that to work.

public static void main (String[] args) throws Exception
{
    robot = new Robot();
    frame = new JDialog();

    frame.setUndecorated(true);
    frame.setSize(59,61);
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
    Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
    int x = (int) rect.getMaxX() - frame.getWidth() - 17;
    int y = (int) rect.getMaxY() - frame.getHeight() - 40;
    frame.setLocation(x, y);
    frame.setAlwaysOnTop(true);
    frame.setBackground(new Color(1.0f,1.0f,1.0f,0.0f));

    panel = new JPanel(new BorderLayout());
    panel.setBackground(new Color(1.0f,1.0f,1.0f,0.0f));
    frame.add(panel);

    InputStream in = HelloWorld.class.getResourceAsStream("/Working/mic2.png");
    notRecording = new ImageIcon(ImageIO.read(in));
    in = HelloWorld.class.getResourceAsStream("/Working/mic3.png");
    recording = new ImageIcon(ImageIO.read(in));
    button = new JButton(notRecording);
    button.setContentAreaFilled(false);
    button.setBorder(BorderFactory.createEmptyBorder());
    panel.add(button);

    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e)
        {
            try
            {
                record();
            }
            catch(Exception ex)
            {
                ex.printStackTrace();
                System.out.println("Exception");
            }
        }
    });

    frame.setVisible(true);

}

When I later run

button.setIcon(recording);
button.paintImmediately(button.getBounds());

Nothing happens.

Edit: I've read over the other thread, and checked the answer they provided, but I can't seem to find any other source that verifies SWING can't handle alpha values, and in fact most sources recommend it. Additionally, calling setOpaque according to setOpaque(true/false); Java seems to imply that using setOpaque is a much more complex concept than just transparency. Additionally, replacing setBackground with setOpaque doesn't work, so I don't think the thread should be closed due to the other thread covering a similar material.

Here's an example of what isn't working for me. In theory, this would leave just the text, or at least only the section that the button occupies of the dialog remaining visible, with the rest not opaque.

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

public class RunnableExample
{
    public static void main(String[] args)
    {
        JDialog dialog = new JDialog();
        dialog.setUndecorated(true);
        dialog.setSize(59,61);
        dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        dialog.setAlwaysOnTop(true);
        dialog.getRootPane().setOpaque(false);

        JPanel panel = new JPanel();
        panel.setOpaque(false);
        dialog.add(panel);

        JButton button = new JButton("test");
        button.setContentAreaFilled(false);
        button.setBorderPainted(false);
        button.setOpaque(false);
        panel.add(button);

        dialog.setVisible(true);
    }
}

Upvotes: 0

Views: 69

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347184

To make a window transparent, you must use setBackground (on an instance of window class, like JFrame or JDialog) and pass it a transparent color (new Color(0, 0, 0, 0))`), this is the ONLY time you can use a alpha based color on a Swing component.

Swing doesn't know how to paint components with a alpha based color, it only knows how to deal with fully transparent or fully opaque components, which is controlled via setOpaque, for example...

I be blank

import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JDialog dialog = new JDialog();
                dialog.setUndecorated(true);
                dialog.setBackground(new Color(0, 0, 0, 0));
                dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                dialog.setAlwaysOnTop(true);
                dialog.getRootPane().setOpaque(false);

                JPanel panel = new JPanel();
                panel.setOpaque(false);
                dialog.add(panel);

                JButton button = new JButton("test");
                button.setContentAreaFilled(false);
                button.setBorderPainted(false);
                button.setOpaque(false);
                panel.add(button);

                dialog.pack();
                dialog.setLocationRelativeTo(null);
                dialog.setVisible(true);
            }
        });
    }

}

I can further prove it by adding

panel.setBorder(new CompoundBorder(new LineBorder(Color.RED), new EmptyBorder(10, 10, 10, 10)));

to the code, which produces

Still blank

The red line is actually the output of the frame (technically the panel, but for this, it's the same thing)

And because there's something wrong with the button/icons...

Play Icon

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JDialog dialog = new JDialog();
                dialog.setUndecorated(true);
                dialog.setBackground(new Color(0, 0, 0, 0));
                dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                dialog.setAlwaysOnTop(true);
                dialog.getRootPane().setOpaque(false);

                JPanel panel = new JPanel();
                panel.setOpaque(false);
                dialog.add(panel);

                try {
                    JButton button = new JButton(new ImageIcon(ImageIO.read(getClass().getResource("/play.png"))));
                    button.setContentAreaFilled(false);
                    button.setBorderPainted(false);
                    button.setOpaque(false);
                    panel.add(button);
                    panel.setBorder(new CompoundBorder(new LineBorder(Color.RED), new EmptyBorder(10, 10, 10, 10)));

                    button.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            try {
                                button.setIcon(new ImageIcon(ImageIO.read(getClass().getResource("/record.png"))));
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            }
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }

                dialog.pack();
                dialog.setLocationRelativeTo(null);
                dialog.setVisible(true);
            }
        });
    }

}

Upvotes: 1

Related Questions