简体   繁体   中英

How to load a background image without hiding components on top in Swing

I have a JPanel that holds a few JLabel that display some informations. And i use another JLabel to hold a background image that I'm going to get from a URL. I have used GirdBagLayout to set this up and this is what I have.

来自 alux.com 频道的 Youtube 视频

Now The issue i have is this : Since the image if of high resolution, it takes time to load hence the app seems slow.

    vidThumbnailIcon = new ImageIcon(ImageIO.read(imageURL)) ////http link
    thumbnailLabel.setIcon(vidThumbnailIcon);

I have tried to put the previous lines of code in a different thread but, since it loads later, it does paint over the previously inserted JLabels That means all other components disappear. I also tried using the paint method like

 @Override
protected void paintComponent(Graphics g){
    super.paintComponent(g);
    g.drawImage(vidThumbnailIcon.getImage(), 0, 0, this.getWidth(),this.getHeight(), null);
}

and paint the background of the JPanel with no success.

The only way i have found is to get the image first, load the image to the background, and then add other components on top. But it's too slow, limited by my slow internet. Is there any alternative to this? Meaning, loading the image later but still not hiding everything else.

The code

public class VideoDetailsView extends JPanel{

    private ImageIcon vidThumbnailIcon;
    private Video video;
    public VideoDetailsView(Video video){
        this.video = video;
        try{
            var imageLink = new URL(video.thumbnailLink);
            vidThumbnailIcon = new ImageIcon(ImageIO.read(imageLink));
        } catch (MalformedURLException ex) {
            vidThumbnailIcon = new ImageIcon("assets/icons/default_thumbnail.png");
        } catch (Exception ex) { 
            vidThumbnailIcon = new ImageIcon("assets/icons/default_thumbnail.png");
        }
        initGUIComponents();
    }

    private void initGUIComponents() {
        var vidTitleLabel = new JLabel(video.title);
        CustomComponent.customizeLabel(vidTitleLabel, 4);
        var vidViewsLabel = new JLabel(video.viewCount);
        CustomComponent.customizeLabel(vidViewsLabel, 1);
        var vidChannelLabel = new JLabel(video.channel);
        CustomComponent.customizeLabel(vidChannelLabel, 1);
        var vidDateLabel = new JLabel(video.releaseDate);
        CustomComponent.customizeLabel(vidDateLabel, 1);
        var vidDurationLabel = new JLabel(video.duration);
        CustomComponent.customizeLabel(vidDurationLabel, 1);
        var vidCommentsLabel = new JLabel(video.commentCount);
        CustomComponent.customizeLabel(vidCommentsLabel, 1);
        
        var layout = new GridBagLayout();    
        var gbc = new GridBagConstraints();
        setLayout(layout);
   
        gbc.weighty = 1;
        gbc.anchor = GridBagConstraints.WEST;
        addComponent(vidViewsLabel, this, layout,gbc, 0,0,1,1);
        addComponent(vidCommentsLabel, this, layout, gbc, 0,1,1,1);
        addComponent(vidChannelLabel, this, layout,gbc, 0,2,1,1);
        addComponent(vidDateLabel, this, layout,gbc, 0,3,1,1);
        addComponent(vidDurationLabel, this, layout,gbc, 0,4,1,1);
        gbc.weightx = 1;
        addComponent(vidTitleLabel, this, layout,gbc, 0,6,2,2);
        
    }
   public void addComponent(JComponent component, Container container,
            GridBagLayout layout, GridBagConstraints gbc,
            int gridx, int gridy,
            int gridwidth, int gridheight ){
            gbc.gridx = gridx;
            gbc.gridy = gridy;
            gbc.gridwidth = gridwidth;
            gbc.gridheight = gridheight;
            container.add(component,gbc);
    }
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(vidThumbnailIcon.getImage(), 0, 0, this.getWidth(),this.getHeight(), null);
    }
}

With the help suggested from trashgod and camickr,

[1]: https://stackoverflow.com/a/25043676/230513 this is how i have proceded.

  1. Add all the text holder JLabels to the JPanel
  2. write the paintComponent method as:
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(vidThumbnailIcon.getImage(), 0, 0,componentToPaint.getWidth(),componenttoPaint.getHeight(), componentToPaint);
    }
  1. start a new Thread to download the image from URL using any multithreading technique such as SwingWorker or any other. and execute the downloading there then before the end, call repaint() .
public void run() {
        try{
                    var imageURL = new URL(thumbnailURL);
                    vidThumbnailIcon = new ImageIcon(ImageIO.read(imageURL));  
                } catch (MalformedURLException ex) {
                    vidThumbnailIcon = new ImageIcon("assets/icons/default_thumbnail.png");
                } catch (Exception ex) {
                    
                    vidThumbnailIcon = new ImageIcon("assets/icons/default_thumbnail.png");
                }
        repaint();///this helps display the image right after the downloading has ended
    }
  1. finally call this thread object after the GUI set up
     initGUIComponents(); loadThumbnail(); ///In this method, you create a thread, use it to load the image and then call repaint() inside here.

I'm not sure this is the best way to do it but atleast it worked for me. Thank family for the support

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM