0

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);
    }
}
Community
  • 1
  • 1
  • Swing doesn't know how to paint components with alpha based colors -> `panel.setBackground(new Color(1.0f,1.0f,1.0f,0.0f));` should probably be `panel.setOpaue(false)` – MadProgrammer Jan 25 '16 at 23:32
  • panel.setOpaque(false) doesn't actually make the background transparent. I tried adding frame.getRootPane().setOpaque(false) as well, due to some further research, and tried calling button.setOpaque(false) finally, but none of these seemed to work for me. Could there be a reason why? – Matthew Whitlock Jan 26 '16 at 03:34
  • Seems work okay for me – MadProgrammer Jan 26 '16 at 03:48
  • As a side note, `JButton#setIcon` is a bound field, that means, it triggers it's own repaint and layout request – MadProgrammer Jan 26 '16 at 03:54
  • It would suggest that the problem (or more) are located somewhere else in the code. Consider providing a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses – MadProgrammer Jan 26 '16 at 03:56
  • I've added an example to the original post. I'm making this comment as well just because I'm not sure if you get a notification for edits to the post. Thanks for your help so far, by the way. – Matthew Whitlock Jan 26 '16 at 04:18
  • Okay, seems to be a miscommunication. You can use `JFrame#setBackground` and pass it a alpha color, it's the only time that this will work. All other times, you must use `setOpaque` ... I know, thanks Sun/Oracle, that isn't confusing :P – MadProgrammer Jan 26 '16 at 04:23
  • That's what I had before, and it works for me, but as soon as I include a line using frame.setBackground(new Color(0, 0, 0, 0)); it stops allowing me to update my JButton's icon. – Matthew Whitlock Jan 26 '16 at 04:26
  • What you had before also included `panel.setBackground(new Color(1.0f,1.0f,1.0f,0.0f));`, which is, as I stated, the actual problem. Instead you should be using `panel.setOpaque(false)`, BUT keep using `frame.setBackground(new Color(0, 0, 0, 0));` – MadProgrammer Jan 26 '16 at 04:32
  • Sorry, I should have mentioned that I've already switched that over to setOpaque. Essentially, everything works perfectly if I just comment out the frame.setBackground line (without the transparent background) - then I include that line and it becomes transparent, but the button's icon stops updating. – Matthew Whitlock Jan 26 '16 at 04:35

1 Answers1

1

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

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • This works perfectly for making the window transparent, but my example of the code already made a transparent window - I seem to have miscommunicated the problem. Once the window is transparent I can no longer switch my JButtons icon from one ImageIcon to another. When the window is not transparent it works fine, but once it is transparent running 'button.setIcon(recording);' 'button.paintImmediately(button.getBounds());' does nothing. – Matthew Whitlock Jan 26 '16 at 04:47
  • @MatthewWhitlock See last update, it switches button icons just fine. You don't need to do anything special, just call `setIcon`, the button will revalidate itself, including requesting a repaint to occur – MadProgrammer Jan 26 '16 at 04:47
  • I see. I removed the call to record() within my action listener and replaced it with setIcon, and it updated the icon correctly. However, updating the icon AND calling the record() method fails to update the icon, for some reason. Even calling paintImmediately doesn't fix it. I can call other methods, just not record(). I'll look into debugging some more, but if I need some more help I'll start a new question with this new information. Thank you very much for your help! – Matthew Whitlock Jan 26 '16 at 05:07
  • See this is what I was talking about when I said the (other) problems where in the code you've not shown use. Start by having a look at [Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) and [Worker Threads and SwingWorker](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html) – MadProgrammer Jan 26 '16 at 05:09