【问题标题】:Proper way to use JLabels to update an image使用 JLabels 更新图像的正确方法
【发布时间】:2013-09-16 02:12:42
【问题描述】:

我正在创建一个 GUI,并且对 swing 和 awt 还很陌生。我正在尝试创建一个 gui,它在启动时将背景设置为图像,然后使用一种方法来创建各种幻灯片。我已经尝试过了,我没有附加到代码上,所以我可以同时接受修订和/或全新的概念。

编辑(2013 年 9 月 15 日):我在播放幻灯片时遇到了问题,我似乎无法让它工作。

这是我当前的代码。

public class MainFrame extends JFrame{

JLabel backgroundL = null;
private JLabel bakckgroundL;
BufferedImage backimg;
Boolean busy;
double width;
double height;

public MainFrame() throws IOException {
    initMainframe();
}



public void initMainframe() throws IOException { 

//misc setup code, loads a default jpg as background

    setTitle("Pemin's Aura");
    busy = true;
    String backgroundDir = "resources/frame/background.jpg";

    backimg = ImageIO.read(new File(backgroundDir));
    backgroundL = new JLabel(new ImageIcon(backimg));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    refreshframe();
    setVisible(true);
    busy = false;
}
public void adjSize() { // the attempted start of a fullscreen mode
        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
    width = this.getWidth();
    height = this.getHeight();
    setVisible(true);
}

public void setmastheadText() {//unfinished code
busy = true;

busy = false;
}
public void setbackground() {
    add(backgroundL);
}
public void refreshframe() { //should refresh image?
    setSize(2049, 2049);
    setSize(2048, 2048);
}
public void loadingscreen() throws IOException, InterruptedException {

 //this is the code in question that is faulty.

    if (busy == false) {
    busy = true;

    String backgroundDir1 = "resources/frame/background.jpg";
    String backgroundDir2 = "resources/frame/scr1.jpg";
    String backgroundDir3 = "resources/frame/scr2.jpg";

    BufferedImage backimg1 = ImageIO.read(new File(backgroundDir1));
    BufferedImage backimg2 = ImageIO.read(new File(backgroundDir2));
    BufferedImage backimg3 = ImageIO.read(new File(backgroundDir3));

    backgroundL = new JLabel(new ImageIcon(backimg1));
    Thread.sleep(2000);
    setbackground();
    setVisible(true);
    backgroundL = new JLabel(new ImageIcon(backimg2));
    setbackground();
    setVisible(true);
    Thread.sleep(2000);
    bakckgroundL = new JLabel(new ImageIcon(backimg3));
    setbackground();
    setVisible(true);

    if(backimg != null) {
         backgroundL = new JLabel(new ImageIcon(backimg));;
        }
    }
    busy = false;
}//end of loading screen

【问题讨论】:

  • 您在哪里有问题?或者你想要代码审查?
  • 我会在我的问题中澄清这一点,感谢您提醒我。我想要一个代码审查,但我的问题是我似乎无法让“幻灯片”工作。
  • 遵循标准 Java 命名约定。方法名称中的单词应在第一个单词之后大写。 (即,您需要做的就是通过 JDK 中的方法名称来学习)。 refreshFrame() 方法是一段糟糕的代码。没有理由使用两个不同的值两次调用相同的方法。实际上创建框架的常规方法是使用 pack() 方法,并让每个组件以自己的大小显示。
  • 改善自己的最好方法是接受真实而直率的建议。 @camickr,谢谢。我意识到 pack() 是最常见的方式,并且我熟悉它的作用。但是,如果我想有空白,只有背景,我不会使用 pack()。之前试过,没用,虽然有JLable,但是框架变成了最小的,所以如果你想帮助我,请这样做,这将是一个很大的帮助
  • the frame became the smallest it could possibly be even though there was a JLable - 您是否阅读过 JLabel API 并点击 How to Use Labels 上的 Swing 教程链接?它有一个关于如何更好地构建程序的工作示例,它显示带有图像的标签,代码使用 pack() 并且框架大小合适。我猜不出你可能做错了什么。这就是为什么您应该从一个工作示例开始并对其进行修改。

标签: java swing jframe jlabel javax.imageio


【解决方案1】:

有关使用基于 Swing 的 Timer 显示图像的工作示例,请参阅 ImageViewer

另见How to use Swing Timers


当我在这里时,另一个(更漂亮的)图像动画示例。它使用这张墨卡托地块地图。图像可以水平平铺,因此可以根据需要向左/向右滚动。

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import javax.swing.*;

import java.net.URL;
import javax.imageio.ImageIO;

public class WorldView {

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://i.stack.imgur.com/P59NF.png");
        final BufferedImage bi = ImageIO.read(url);
        Runnable r = new Runnable() {

            @Override
            public void run() {
                int width = 640;
                int height = 316;
                Graphics2D g = bi.createGraphics();

                float[] floats = new float[]{0f, .4f, .55f, 1f};
                Color[] colors = new Color[]{
                    new Color(20, 20, 20, 0),
                    new Color(0, 10, 20, 41),
                    new Color(0, 10, 20, 207),
                    new Color(0, 10, 20, 230),};
                final LinearGradientPaint gp2 = new LinearGradientPaint(
                        new Point2D.Double(320f, 0f),
                        new Point2D.Double(0f, 0f),
                        floats,
                        colors,
                        MultipleGradientPaint.CycleMethod.REFLECT);

                final BufferedImage canvas = new BufferedImage(
                        bi.getWidth(), bi.getHeight() + 60,
                        BufferedImage.TYPE_INT_RGB);

                final JLabel animationLabel = new JLabel(new ImageIcon(canvas));
                ActionListener animator = new ActionListener() {

                    int x = 0;
                    int y = 30;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Graphics2D g = canvas.createGraphics();
                        g.setColor(new Color(55, 75, 125));

                        g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

                        int offset = (x % bi.getWidth());
                        g.drawImage(bi, offset, y, null);
                        g.drawImage(bi, offset - bi.getWidth(), y, null);

                        g.setPaint(gp2);
                        g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

                        g.dispose();

                        animationLabel.repaint();

                        x++;
                    }
                };
                Timer timer = new Timer(40, animator);
                timer.start();
                JOptionPane.showMessageDialog(null, animationLabel);
                timer.stop();
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}

这是该图像的一个版本,添加了赤道(它位于图像中心的“南”44 像素处)。

【讨论】:

  • 不客气。我添加了另一个(更可爱,但更复杂)的示例。 ..主要是因为我正在构建一组示例代码可以热链接到的图像(就像上面的代码一样),并且该图像将成为其中之一。 ;)
【解决方案2】:

您正在调用 Thread.sleep(...) 并且可能在 EDT 或 Swing 事件线程上(全名是 Event Dispatch T线程)。该线程负责所有 Swing 绘画/绘图和用户交互,因此休眠它只会冻结您的整个 GUI。相反,您应该使用 Swing Timer 来允许您交换 JLabel 的 ImageIcon。

所以,简单地说:

  • 不要在 Swing 事件线程(事件调度线程或 EDT)上调用 Thread.sleep(...)
  • 请使用 Swing Timer 来执行重复的延迟动作。
  • 不要制作和添加许多 JLabel。只需制作并添加一个。
  • 通过在标签上调用 setIcon(...) 来交换 JLabel 显示的 ImageIcon。
  • 最好(更干净)将if (busy == false) { 写成if (!busy) {

例如,

ImageIcon[] icons = {...}; // filled up with your ImageIcons

if (!busy) {
  int timerDelay = 2000;
  new Timer(timerDelay, new ActionListener() {
    private int i = 0;
    public void actionPerfomed(ActionEvent e) {
      myLabel.setIcon(icons(i));
      i++;
      if (i == icons.length) {
        ((Timer)e.getSource).stop();
      } 
    };
  }).start();
}

【讨论】:

  • 由于我对你写的大部分内容都不熟悉,请问.start()方法是做什么的?另外,这段代码中 ActionListener 和 actionPerformed 分别有什么用途? PS:感谢您的提示
  • 阅读 How to Use Timers 上的 Swing 教程以了解基础知识。本教程还有一个关于 Concurrency 的部分,您应该阅读它(它解释了有关 EDT 的更多信息)。您应该从教程中下载示例以改进您的程序结构(即 GUI 代码应该在 EDT 上执行)。你不应该扩展 JFrame。
  • @Hovercraft Full Of Eels 当我尝试编写您的代码时,我在new Swing(timerDelay 上看到一个错误,即 Swing 'cannot be resolve to a type' 。你知道该怎么做吗?
  • @Aaron 他可能想说new javax.swing.Timer(..) 或者如果你导入它只是new Timer(..)
  • @Aaron:不要复制我的代码(一方面,我没有测试它,而是即时输入它),而是使用它的想法。是的,除了您使用的最基本的类之外,您必须导入任何其他类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多