Black square showing when adding a .GIF on JPanel

2019-02-17 23:07发布

问题:

My problem is that when adding a .GIF to a JPanel, it shows this black square background for the .GIF.

Result when adding on JPanel:

It happens when I use this line:

p2.add(loadBar); // where p2 = new JPanel();

However, when I add the same .GIF on the JFrame, the black square is not there anymore. Like this:

jf.add(loadBar); // where jf = new JFrame();

Result when adding on JFrame:

Part of the class code:

String loadLink = "http://i.imgur.com/mHm6LYH.gif";
        URL ajaxLoad = null;
        try {
            ajaxLoad = new URL(loadLink);
        } catch (MalformedURLException e3) {
            // TODO Auto-generated catch block
            e3.printStackTrace();
        }
        ImageIcon loading = new ImageIcon(ajaxLoad);
        JLabel loadBar = new JLabel(loading);
        loadBar.setBounds(70, 60, 54, 55);
        loadBar.setOpaque(false);
        //jf.add(loadBar);
        p2.add(loadBar);

Could someone please explain why it is happening like this? Thank you for your time and reading.

EDIT:

// Creates the Initialization Panel
        p2 = new JPanel();
        // Sets the background, black with 125 as alpha value
        // This is less transparent
        p2.setLayout(null);
        p2.setBackground(new Color(0,0,0,150));
        // Sets a border to the JPanel
        p2.setBorder(new LineBorder(Color.WHITE));
        // Sets some size to the panels
        p2.setBounds(20, 20, 200, 150);

        // Adds the loading gif
        String loadLink = "http://i.imgur.com/mHm6LYH.gif";
        URL ajaxLoad = null;
        try {
            ajaxLoad = new URL(loadLink);
        } catch (MalformedURLException e3) {
            // TODO Auto-generated catch block
            e3.printStackTrace();
        }
        ImageIcon loading = new ImageIcon(ajaxLoad);
        JLabel loadBar = new JLabel(loading);
        loadBar.setBounds(70, 60, 54, 55);
        loadBar.setOpaque(false);
        p2.add(loadBar);

That is the JPanel which is shown in the first image without the JLabel. I can't really show the JFrame part in the code because it is spread all over the class. But I don't think the problem is with JFrame so it could be this JPanel :/

回答1:

Your problem is here...

p2.setBackground(new Color(0,0,0,150));

Swing does not support alpha based backgounds, either your component is transparent or it's not.

Doing this means that the component "attempts" to use the alpha value as the background fill color, but the paint manager doesn't know it should paint beneath the component, causing all sorts of problems and issues

Now, this a little tricky. You need to make the container transparent by using setOpaque(false), but this now means that the background is not painted.

What you need to do is create a custom component, set it's opaque property to false and override it's paintComponent method and fill the background with your alpha based color. I normally like using a AlphaComposite, but this works as wel...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class TranslucentPanelExample {

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

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

                try {
                    JLabel background = new JLabel(
                            new ImageIcon(ImageIO.read(
                                            getClass().getResource("/background.jpg"))));
                    background.setLayout(new GridBagLayout());
                    background.add(new WaitPane());

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(background);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

    public class WaitPane extends JPanel {

        public WaitPane() {
            setLayout(new GridBagLayout());
            setBorder(new EmptyBorder(12, 12, 12, 12));
            // This is very important
            setOpaque(false);
            setBackground(new Color(0, 0, 0, 150));

            String loadLink = "http://i.imgur.com/mHm6LYH.gif";
            URL ajaxLoad = null;
            try {
                ajaxLoad = new URL(loadLink);
            } catch (MalformedURLException e3) {
                // TODO Auto-generated catch block
                e3.printStackTrace();
            }

            ImageIcon loading = new ImageIcon(ajaxLoad);
            JLabel loadBar = new JLabel(loading);
            loadBar.setHorizontalAlignment(JLabel.CENTER);
            loadBar.setVerticalAlignment(JLabel.CENTER);
            add(loadBar);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(getBackground());
            g.fillRect(0, 0, getWidth(), getHeight());
        }

    }

}

Layout managers, layout managers, layout managers...

I can't stress enough how important layout managers are. You are relying on "magic" numbers which may not always meet reality...



回答2:

Looking at your code, I see nothing wrong. Just to be sure, I tested your code out as is, adding in my own JFrame and JPanel. Here is what I ended up with:

import javax.swing.*;
import java.net.*;

public class Test {
public static void main(String[] args) {
    JFrame frame = new JFrame("Test");
    frame.setSize(600, 400);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    JPanel panel = new JPanel();
    String loadLink = "http://i.imgur.com/mHm6LYH.gif";
    URL ajaxLoad = null;
    try {
        ajaxLoad = new URL(loadLink);
    } catch (MalformedURLException e3) {
        e3.printStackTrace();
    }
    ImageIcon loading = new ImageIcon(ajaxLoad);
    JLabel loadBar = new JLabel(loading);
    loadBar.setBounds(70, 60, 54, 55);
    loadBar.setOpaque(false);
    panel.add(loadBar);    
    frame.add(panel);
    frame.setVisible(true);
    }
}

When I ran it, it worked as it should, without any problems. The .GIF was animated and in its proper place in the frame. Could you copy the code above and test that it works for you the same way? Also, could you show us your code in which you initialize your JFrame and JPanel that contain the image? Thanks.



回答3:

It's taking time to load the image as per your first snapshot.

Please have a look at Monitoring with an ImageObserver to check the status of the image.

Add the image in JPanel when its fully loaded.


Sample code:

    new Thread(new Runnable() {

        @Override
        public void run() {
            int width = loading.getIconWidth();

            if (width >= 0) {
                isImageLoaded = true;
                p2.add(loadBar);
                return;
            }

            // Wait if the image is not loaded yet
            while (!isImageLoaded) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                }
            }
        }
    }).start();