【问题标题】:How to display an images instantly in Java Applet?如何在 Java Applet 中即时显示图像?
【发布时间】:2013-07-25 03:32:59
【问题描述】:

我在 Java Applet 中创建了一个简单的记忆游戏。我的卡有问题。图像在第一次出现时需要一些额外的加载时间。如何解决?我需要在卡片翻转后立即显示图像。

我显示加载屏幕,直到应用程序不在 AppStates.READYAppStates.WAIT_FOR_START 状态,但它没有帮助。

Memo.cs - 加载图片的主类

public class Memo extends JApplet {

    //...   

    public void init() {
        //...   
        try {
            SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { createGUI(); }});
        } 
        catch(Exception e) {
            e.printStackTrace();
        }
    }

    private void createGUI() {
        final Model model = new Model(...);
        final View view = new View(model);

        getContentPane().add(view, BorderLayout.CENTER);
        setBackground(backgroundColor);
        setPreferredSize(new Dimension(width, height));

        model.setLoading(loadImages(loadingPath, format, 1));
        model.setCardsImages(loadImages(cardImagePath, format, 13));
        //...
        model.setAppState(AppStates.PROCESS);

        model.startNewGame();
        view.repaint();
    }

    private Image[] loadImages(String path1, String path2, int count) {
        Image[] imgs = new Image[count];        
        for(int i = 0; i < count; ++i) {
            imgs[i] = getImage(getCodeBase(), path1 + i + path2);
        }
        return imgs;
    }
}

Model.cs - 保存图像和应用程序状态,初始化板

public class Model {

    //...

    private AppStates appState;
    private Image[] cardsImages;

    public Model(...) {
        //...
        appState = AppStates.INIT;
    }

    public void startNewGame() {
        setAppState(AppStates.PROCESS);

        //... - init board - table with images' id

        setAppState(AppStates.WAIT_FOR_START);
    }

    public void setCardsImages(Image[] cardsImages) {
        this.cardsImages = cardsImages;
    }

    public Image getCardsImage(int v) {
        return cardsImages[v];
    }

    public AppStates getAppState() {
        return appState;
    }

    public void setAppState(AppStates appState) {
        this.appState = appState;
        //...
    }

    //...
}

View.cs - 显示板

public class View extends JPanel {

    //...

    private Model model;

    public View(Model model) {
        this.model = model;
        //...
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        if(model != null) {
            switch (model.getAppState()) {

            //...

            case WAIT_FOR_START:            
            case READY:
                //...
                drawBoard(g2d, model.getBoard(), model.getStates(), model.getFrontTypes());
                break;

            }
        }
        repaint();
    }

    private void drawBoard(Graphics2D g2d, int[][] board, int[][] states, int[][] frontTypes) {
        if(board != null && states != null && board.length > 0 && states.length > 0) {
            for(int x = 0; x < board.length; x++) {
                for(int y = 0; y < board[x].length; y++) {  
                    if(states[x][y] != Model.HIDE) {
                        Image img = null;

                        //...
                        img = model.getCardsImage(board[x][y]);

                        g2d.drawImage(
                                img,
                                model.getFirstCardX() + x * model.getCardDistance() + x * model.getCardWidth(), 
                                model.getFirstCardY() + y * model.getCardDistance() + y * model.getCardHeight(), 
                                model.getCardWidth(), 
                                model.getCardHeight(),
                                null);

                        //...
                    }
                }
            }
        }
    }
}

【问题讨论】:

    标签: java image swing applet


    【解决方案1】:

    您可以利用Swing 中的双缓冲,并在一切准备就绪时立即显示。

    如果您需要在中间进行,您可以保留一个预先开发的副本并在需要时显示它。

    【讨论】:

      【解决方案2】:

      预取图像的一种方法是使用MediaTracker。使用此类可确保在给定点加载图像。这是文档中的一个很好的演示:

      import java.applet.Applet;
      import java.awt.Color;
      import java.awt.Image;
      import java.awt.Graphics;
      import java.awt.MediaTracker;
      
      public class ImageBlaster extends Applet implements Runnable {
          MediaTracker tracker;
          Image bg;
          Image anim[] = new Image[5];
          int index;
          Thread animator;
      
          // Get the images for the background (id == 0)
          // and the animation frames (id == 1)
          // and add them to the MediaTracker
          public void init() {
              tracker = new MediaTracker(this);
              bg = getImage(getDocumentBase(),
                      "images/background.gif");
              tracker.addImage(bg, 0);
              for (int i = 0; i < 5; i++) {
                  anim[i] = getImage(getDocumentBase(),
                          "images/anim"+i+".gif");
                  tracker.addImage(anim[i], 1);
              }
          }
      
          // Start the animation thread.
          public void start() {
              animator = new Thread(this);
              animator.start();
          }
      
          // Stop the animation thread.
          public void stop() {
              animator = null;
          }
      
          // Run the animation thread.
          // First wait for the background image to fully load
          // and paint.  Then wait for all of the animation
          // frames to finish loading. Finally, loop and
          // increment the animation frame index.
          public void run() {
              try {
                  tracker.waitForID(0);
                tracker.waitForID(1);
              } catch (InterruptedException e) {
                  return;
              }
              Thread me = Thread.currentThread();
              while (animator == me) {
                  try {
                      Thread.sleep(100);
                  } catch (InterruptedException e) {
                      break;
                  }
                  synchronized (this) {
                      index++;
                      if (index >= anim.length) {
                          index = 0;
                      }
                  }
                  repaint();
              }
          }
      
          // The background image fills the frame so we
          // don't need to clear the applet on repaints.
          // Just call the paint method.
          public void update(Graphics g) {
              paint(g);
          }
      
          // Paint a large red rectangle if there are any errors
          // loading the images.  Otherwise always paint the
          // background so that it appears incrementally as it
          // is loading.  Finally, only paint the current animation
          // frame if all of the frames (id == 1) are done loading,
          // so that we don't get partial animations.
          public void paint(Graphics g) {
              if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) {
                  g.setColor(Color.red);
                  g.fillRect(0, 0, size().width, size().height);
                  return;
              }
              g.drawImage(bg, 0, 0, this);
              if (tracker.statusID(1, false) == MediaTracker.COMPLETE) {
                  g.drawImage(anim[index], 10, 10, this);
              }
          }
      }
      

      如果您可以保证这将始终在 Java 1.4 或更高版本上运行,您可以使用[ImageIO.read][2] 来获取您的图像。它将等到图像加载完毕。

      【讨论】:

      • 由于 OP 使用基于 Swing 的组件,MediaTracker 是多余的。 JPanel 是一个 ImageObserver。 ;)
      【解决方案3】:

      来自 JavaDocs..

      public Image getImage(URL url)

      ..

      无论图像是否存在,此方法总是立即返回。当此小程序尝试在屏幕上绘制图像时,将加载数据。

      请改用ImageIO.read(URL)。此方法将“阻塞”(它将在该代码行处停止),直到读取图像。所以当应用程序。去使用图像,它已经完全加载了。

      解决问题的另一种方法(不是您想要的方式)是改变..

      g2d.drawImage(
          img,
          model.getFirstCardX() + x * model.getCardDistance() + x * model.getCardWidth(), 
          model.getFirstCardY() + y * model.getCardDistance() + y * model.getCardHeight(), 
          model.getCardWidth(), 
          model.getCardHeight(),
          null);
      

      到..

      g2d.drawImage(
          img,
          model.getFirstCardX() + x * model.getCardDistance() + x * model.getCardWidth(), 
          model.getFirstCardY() + y * model.getCardDistance() + y * model.getCardHeight(), 
          model.getCardWidth(), 
          model.getCardHeight(),
          this);
      

      如果图像是异步加载的(例如使用Applet.getImage(URL)),GUI 将被通知在更多可用时重新绘制。

      【讨论】:

      • 很好的答案。谢谢。 :)
      猜你喜欢
      • 1970-01-01
      • 2014-09-18
      • 1970-01-01
      • 2012-03-12
      • 2014-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多