0

作为一名非 java 专家,我想知道如何更改下面的代码以使其正常工作。这是我想做的

  • 调用java代码时args包含多个图像文件名
  • 我想查看此列表中的第一张图片
  • 然后当我按下一个键时,一个索引会改变,并显示下一个图像。

使用下面提出的建议,这是一段可编译的运行代码:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;


public class LoadImageApp extends Component {

    BufferedImage img;
    private static int index = 0;

    public void paint(Graphics g) {
        g.drawImage(img, 0, 0, null);
    }

    public LoadImageApp(String filename) {
        try {
            img = ImageIO.read(new File(filename));
        } catch (IOException e) {
            System.out.println(e.getMessage());
            System.exit(0);
        }
    }

    public Dimension getPreferredSize() {
        if (img == null) {
            return new Dimension(100,100);
        } else {
            return new Dimension(img.getWidth(null), img.getHeight(null));
        }
    }

    static public void changeImage(JFrame frame, String filename) {
        System.out.println("Using file "+filename);
        frame.add(new LoadImageApp(filename));
        frame.pack();
        frame.setVisible(true);
        frame.repaint();
    }

    public static void main(final String[] args) {

        char c=0;
        String filename = args[0];
        int numberImages = args.length;

        final JFrame f = new JFrame("Load Image Sample");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        f.addKeyListener(new KeyAdapter(){
                public void keyPressed(KeyEvent event) {
                    int key = event.getKeyCode();
                    if (key==81) {
                        System.exit(0);
                    } else if (key==89) {
                        System.out.println("yes");
                    } else if (key==78) {
                        System.out.println("no");
                    }
                    index += 1;
                    f.removeAll();
                    changeImage(f, args[index]);
                }
            });

        // show first image here
        changeImage(f, args[index]);

    }
}

如果我使用像这样的代码

java LoadImageApp *.jpg

它只显示第一张图片。我可以按键,但显示的图像没有改变。我想改变图像。

我已经找到revalidate()repaint()可能的解决方案。尽管frame.revalidate()根本不存在,frame.repaint()(inside changeImage) 仍然没有改变任何东西。我仍然看到显示的第一张图片。

无论如何,这是正确的方法吗?有没有更优雅的方式?

4

3 回答 3

2

我写了一个程序来演示你的要求,这里是代码:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ImageShow {

  /** Inner class: JPanel that displays images. **/
  static class JImagePanel extends JPanel {

    protected final LinkedList<BufferedImage> images;
    protected BufferedImage currentImage;
    protected int currentIndex;

    public JImagePanel(final LinkedList<BufferedImage> images) {
      super(true);
      this.setFocusable(false);
      this.images = images;
      this.setIndex(0);
    }

    /** Has to be private to not cause issues when used in the constructor. **/
    private void setIndex(final int index) {
      if (index >= this.images.size()) {
        this.currentIndex = 0;
      } else if (index < 0) {
        this.currentIndex = this.images.size() - 1;
      } else {
        this.currentIndex = index;
      }

      this.currentImage = this.images.get(this.currentIndex);
      this.setPreferredSize(new Dimension(this.currentImage.getWidth(), this.currentImage.getHeight()));
      this.repaint();
    }

    public void shiftIndex(final int amount) {
      this.setIndex(this.currentIndex + amount);
    }

    @Override
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.drawImage(this.currentImage, 0, 0, null);
    }
  }

  public static void main(final String[] args) {
    final LinkedList<BufferedImage> images = loadImages(args);
    if (images.size() > 0) {
      final JFrame window = new JFrame("Image Show");
      window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      final JImagePanel imagePanel = new JImagePanel(images);
      window.add(imagePanel);

      window.addKeyListener(new KeyAdapter() {
        private void shiftIndex(final int amount) {
          imagePanel.shiftIndex(amount);
          window.pack();
          window.setLocationRelativeTo(null);
        }

        @Override
        public void keyReleased(KeyEvent e) {
          switch (e.getKeyCode()) {
            case KeyEvent.VK_ESCAPE:
              window.dispose();
              e.consume();
              break;
            case KeyEvent.VK_LEFT:
            case KeyEvent.VK_NUMPAD4:
              shiftIndex(-1);
              e.consume();
              break;
            case KeyEvent.VK_RIGHT:
            case KeyEvent.VK_NUMPAD6:
              shiftIndex(+1);
              e.consume();
              break;
          }
        }
      });

      window.pack();
      window.setLocationRelativeTo(null);
      window.setVisible(true);
    } else {
      System.err.println("No image could be loaded.\nPlease provide a list of image files as parameters.");
    }
  }

  private static LinkedList<BufferedImage> loadImages(final String[] filenames) {
    final LinkedList<BufferedImage> result = new LinkedList<>();
    for (String filename : filenames) {
      try {
        final File file = new File(filename);
        final BufferedImage image = ImageIO.read(file);
        if (image == null) {
          throw new IOException("Unknown image format");
        }
        result.add(image);
      } catch (IOException e) {
        System.err.println("Unable to load image \"" + filename + "\": " + e.getMessage());
      }
    }
    return result;
  }
}

请注意,这不是编写此工具的最佳方式,但它确实有效。

你通常应该做的:

  • 每个类都应该在自己的 .java 文件中。这个想法是有一个结构,即使你在 3 年后重新访问这个代码也很容易阅读。

  • 您不应该像我在这里对主函数中的 window 和 imagePanel 所做的那样使用来自另一个范围的变量。而是使用构造函数来存储具有给定值或值副本的局部变量(取决于您的需要),就像我在 JImagePanel 构造函数中所做的那样。
    您是否需要价值的副本取决于您所做的事情以及您愿意承担多少风险。在此示例中,在创建 JImagePanel 之后更改图像列表可能会搞砸。

  • 你永远不应该像在你的关键监听器版本中那样使用数字。你永远不知道哪个键码对应哪个键!只要可用,就使用提供的常量或函数来获得这样的“神奇”数字。

  • 当涉及到错误处理时,总是期待最坏的情况。一次尝试捕获并处理所有可能的错误。其次,总是尽量避免潜在的问题。您无法制造的错误是您不必担心的错误。
    在您的版本中,每次按下按钮时都会从磁盘加载图像文件。如果此时图像不再存在,会发生什么?在我的版本中,一切都预先检查,一旦完成,程序就不会再失败(至少在尝试切换图像时不会失败)。;)

  • 一般来说:尝试为初学者找到一本关于 Java 的好书或在线教程。如果您只是破解,您将错过 Java 已经为您准备的所有这些好东西,这不仅会加快开发速度,而且还会防止您可能编写的所有错误。

于 2013-10-05T17:38:52.553 回答
0

这或多或少是你想要的。我建议你从头开始学习 Java 并填补你的空白。

    public class LoadImageApp extends JPanel {

        //Current image the Canvas shows
        private Image currentImage;

        //change the current image and repaint
        public void setCurrentImage(Image currentImage) {
                this.currentImage = currentImage;                
                repaint();
        }

        @Override
        public void paintComponent(Graphics g) {
                g.clearRect(0, 0, getWidth(), getHeight());
                if (currentImage != null)
                g.drawImage(currentImage, 0, 0, null);
        }

        @Override
        public Dimension getPreferredSize() {
                if (currentImage == null) {
                        return new Dimension(100, 100);
                } else {
                        return new Dimension(currentImage.getWidth(null), currentImage.getHeight(null));
                }
        }

        public static void main(final String[] args) throws IOException {

                if (args.length > 0){
                        final Image [] images = new Image[args.length];

                        for (int i = 0; i < images.length; i++){
                                images[i] = ImageIO.read(new File(args[i]));
                        }

                        //It is a goog practice to attach your code to AWT thread.
                        SwingUtilities.invokeLater(new Runnable() {                                
                                @Override
                                public void run() {
                                        LoadImageApp app = new LoadImageApp();
                                        JFrame f = new JFrame("Load Image Sample");

                                        f.getContentPane().setLayout(new BorderLayout());
                                        f.getContentPane().add(app, BorderLayout.CENTER);

                                        f.addKeyListener(new MyKeyAdapter(app, images));
                                        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                                        f.setVisible(true);
                                }
                        });
                }
        }        
    }

    // We create another class for the KeyAdapter
    class MyKeyAdapter extends KeyAdapter{

        //The canvas so we can tell it that the current  image has change
        private LoadImageApp canvas;

        //index of the current image
        private int index;

        //All the images
        private Image [] images;

        public MyKeyAdapter(LoadImageApp canvas, Image[] images) {
                super();
                this.canvas = canvas;
                this.images = images;                    
                rotateRight();
        }

        @Override
        public void keyPressed(KeyEvent event) {
                int key = event.getKeyCode();                    
                if (key == 81) {
                        System.exit(0);
                } else if (key == KeyEvent.VK_LEFT) {
                        rotateLeft();
                } else if (key == KeyEvent.VK_RIGHT) {
                        rotateRight();
                }
        }

        private void rotateRight() {
                //change the image in the canvas
                canvas.setCurrentImage(images[index]);                    
                //increment index
                index++;                    
                //last element + 1, set it to 0
                if (index >= images.length) index = 0;
        }

        private void rotateLeft() {
                //change the image in the canvas
                canvas.setCurrentImage(images[index]);                    
                //decrement index
                index--;                    
                //< 0, set it to last image
                if (index < 0) index = images.length - 1;
        }
}
于 2013-10-05T16:46:03.363 回答
0

关键字final表示变量在初始化后不会改变。为了在匿名内部类中使用变量,即KeyAdapter它必须被声明为final。

所以你需要:

 public static void main(final String[] args) {

 final JFrame f = new JFrame("Load Image Sample");

但这不适用于index您计划更改它。所以我建议将它声明为类级别的静态变量,即在函数之外。

private static int index = 0;
于 2013-10-05T16:49:33.453 回答