繁体   English   中英

如何在 Swing 中加载背景图像而不在顶部隐藏组件

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

我有一个JPanel ,其中包含一些显示一些信息的JLabel 我使用另一个 JLabel 来保存我将从 URL 获得的背景图像。 我已经使用GirdBagLayout来设置它,这就是我所拥有的。

来自 alux.com 频道的 Youtube 视频

现在我遇到的问题是:由于图像是高分辨率的,因此加载需要时间,因此应用程序似乎很慢。

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

我试图将前面的代码行放在不同的线程中,但是由于它稍后加载,它确实会覆盖先前插入的JLabels这意味着所有其他组件都消失了。 我也尝试过使用绘画方法,比如

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

并没有成功绘制JPanel的背景。

我发现的唯一方法是先获取图像,将图像加载到背景,然后在顶部添加其他组件。 但它太慢了,受我网速慢的限制。 有没有其他选择? 意思是稍后加载图像但仍然没有隐藏其他所有内容。

编码

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

在垃圾神和 camickr 建议的帮助下,

[1]: https://stackoverflow.com/a/25043676/230513这就是我的处理方式。

  1. 将所有文本持有者 JLabels 添加到 JPanel
  2. 将paintComponent方法写为:
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(vidThumbnailIcon.getImage(), 0, 0,componentToPaint.getWidth(),componenttoPaint.getHeight(), componentToPaint);
    }
  1. 使用任何多线程技术(例如 SwingWorker 或任何其他技术)启动一个新线程以从 URL 下载图像。 并在那里执行下载,然后在结束之前调用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. 最后在 GUI 设置后调用这个线程 object
     initGUIComponents(); loadThumbnail(); ///In this method, you create a thread, use it to load the image and then call repaint() inside here.

我不确定这是最好的方法,但至少它对我有用。 感谢家人的支持

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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