【问题标题】:Java image displayJava图像显示
【发布时间】:2009-12-28 00:55:49
【问题描述】:

我正在尝试创建一个可以与多个图像共存的 GUI。

有一个背景图片会占用最多的空间。 在背景图像的顶部,其他几个图像将显示在不同的位置。 这些位置将每 5 秒左右更新一次,因此速度不是一个重要因素。

所以我所需要的只是能够在每次更新时在我选择的坐标处显示或删除图像。

我正在使用 netbeans 将它们放在一起。

这是迄今为止我为完成这项工作而遇到的最合理的代码,但我不知道如何将其付诸实践,也不知道它是否可以完成我需要的工作。

对 JPanel 是什么的简短解释也会有所帮助。

public class ImagePanel extends JPanel {

  private Image img;

  public void setImage(String img) {
    setImage(new ImageIcon(img).getImage());
  }

  public void setImage(Image img) {
    int width = this.getWidth();
    int height = (int) (((double) img.getHeight(null) / img.getWidth(null)) * width);
    this.img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
  }

  @Override
  public void paintComponent(Graphics g) {
    g.drawImage(img, 0, 0, this);
  }
}

这是我目前拥有的主类的代码。我可以很容易地添加代码来确定是否应该显示给定的图像,以及它们需要放在哪里,但我不知道在哪里放什么。

public class ClientWindow extends javax.swing.JFrame {

/** Creates new form ClientWindow */
public ClientWindow() {
    initComponents();
    imagePanel1.setImage("C:\\Documents and Settings\\Robert\\Desktop\\ClientServer\\Poker Table Art\\TableAndChairs.png");
}

/** This method is called from within the constructor to
 * initialize the form.
 * WARNING: Do NOT modify this code. The content of this method is
 * always regenerated by the Form Editor.
 */
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {

    jScrollPane1 = new javax.swing.JScrollPane();
    jTextField1 = new javax.swing.JTextField();
    jScrollPane2 = new javax.swing.JScrollPane();
    jTextArea1 = new javax.swing.JTextArea();
    jCheckBox2 = new javax.swing.JCheckBox();
    imagePanel1 = new Pokertable.ImagePanel();
    imagePanel3 = new Pokertable.ImagePanel();
    jPanel1 = new javax.swing.JPanel();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setTitle("Not Logged In");
    getContentPane().setLayout(null);

    jTextField1.addKeyListener(new java.awt.event.KeyAdapter() {
        public void keyTyped(java.awt.event.KeyEvent evt) {
            jTextField1KeyTyped(evt);
        }
    });
    jScrollPane1.setViewportView(jTextField1);

    getContentPane().add(jScrollPane1);
    jScrollPane1.setBounds(0, 540, 170, 22);

    jTextArea1.setColumns(20);
    jTextArea1.setRows(5);
    jScrollPane2.setViewportView(jTextArea1);

    getContentPane().add(jScrollPane2);
    jScrollPane2.setBounds(0, 440, 166, 96);

    jCheckBox2.setText("Sit Out Next Hand");
    jCheckBox2.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jCheckBox2ActionPerformed(evt);
        }
    });
    getContentPane().add(jCheckBox2);
    jCheckBox2.setBounds(0, 410, 113, 23);

    imagePanel1.add(imagePanel3);
    imagePanel1.add(jPanel1);

    getContentPane().add(imagePanel1);
    imagePanel1.setBounds(0, 0, 520, 370);

    pack();
}// </editor-fold>

private void jCheckBox2ActionPerformed(java.awt.event.ActionEvent evt) {                                           
    // TODO add your handling code here:
}                                          

private void jTextField1KeyTyped(java.awt.event.KeyEvent evt) {                                     
    // TODO add your handling code here:
}                                    


/**
* @param args the command line arguments
*/
public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new ClientWindow().setVisible(true);

        }
    });
}

// Variables declaration - do not modify
private Pokertable.ImagePanel imagePanel1;
private Pokertable.ImagePanel imagePanel3;
private javax.swing.JCheckBox jCheckBox2;
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JTextArea jTextArea1;
private javax.swing.JTextField jTextField1;
// End of variables declaration

}

为简单起见,假设我想让 TableAndChairs.png 作为稳定的背景图像,并让 Button.png 图像(带有圆圈的 D)每隔一段时间移动到一个新位置。

alt text http://img706.imageshack.us/img706/908/tableandchairs.png alt text http://img189.imageshack.us/img189/796/buttonvd.png

【问题讨论】:

  • 阅读挥杆教程,你可能会更清楚一些事情:)

标签: java user-interface image swing graphics


【解决方案1】:

只是一个想法:使用一个额外的类来保存图像和相应的坐标,并将它们放入一个列表中。

public class MyImage {    // or SubImage?
    private Image image;
    private int x;
    private int y;

    public MyImage(Image image, int x, int y) {
        this.image = image;
        this.x = x;
        this.y = y;
    }

    public void paint(Graphics g, ImageObserver obs) {
        g.drawImage(image, x, y, obs);
    }

    // getters and setters
} 


public class ImagePanel extends JPanel {

    private Image img;
    private final List<MyImage> images = new ArrayList<MyImage>();

    // setImage methods

    public void addMyImage(MyImage image) {
        images.add(image);
    }
    // or/and
    public void addMyImage(Image image, int x, int y) {
        images.add(new MyImage(image, x, y));
    }

    @Override
    public void paintComponent(Graphics g) {
        g.drawImage(img, 0, 0, this);    // check if img is null?
        for (MyImage image : images) {
            image.paint(g, this);
    }
}

【讨论】:

    【解决方案2】:

    更好的方法是扩展 JComponent 并覆盖 paintComponent 方法来绘制您的自定义桌椅组件。

    您可以使用 Circle Trigonometry 的基础来动态计算每个圆圈。我已经做了一个简单的示例,向您展示如何使用 Java2D 简单地完成此操作。可以进行很多性能调整,例如缓存、剪辑等。

    编写这段代码的原因是为了让您了解自己绘制它们是多么简单。这样做的原因是,您可以更好地控制正在绘制的内容及其绘制的位置。

    Example http://img191.imageshack.us/img191/908/tableandchairs.png

    public class JTableChairs extends JComponent {
      private final int TABLE_DIAMETER = 300;
      private final int CHAIR_DIAMETER = 50;
      private final int CHAIR_TABLE_BOUND = 50;
      private final int CANVAS_WIDTH = 500;
      private final int NUMBER_OF_CHAIRS = 10;
    
      private final int TABLE_X = (CANVAS_WIDTH - TABLE_DIAMETER) / 2;
      private final int TABLE_Y = TABLE_X;
      private final double TABLE_CENTER_X = TABLE_DIAMETER / 2.0 + TABLE_X;
      private final double TABLE_CENTER_Y = TABLE_DIAMETER / 2.0 + TABLE_Y;
      private final double TABLE_RADIUS = TABLE_DIAMETER / 2.0 + CHAIR_TABLE_BOUND;
    
      public JTableChairs() {
        super();
      }
    
      @Override
      public void paintComponent(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getSize().width, getSize().height);
    
        // Draw Table.
        g.setColor(Color.BLACK);
        g.fillOval(TABLE_X, TABLE_Y, TABLE_DIAMETER, TABLE_DIAMETER);
    
        // Draw each chair using normal circle trig functions.
        for (int i = 1; i <= NUMBER_OF_CHAIRS; i++) {
          Rectangle r = getSeatCoordinates(i);
          g.drawOval(r.x, r.y, r.width, r.height);
          g.drawString(String.valueOf(i), r.x, r.y);
        }
      }
    
      public Rectangle getSeatCoordinates(int seat) {
        // Clamp from 0 to number of chairs to make sure it doesn't
        // go over/under bounds.
        seat = seat < 1 ? 1 :
               (seat > NUMBER_OF_CHAIRS ? NUMBER_OF_CHAIRS : seat) - 1;
    
        // Calculate the coordinates using trig functions.
        double arcAngle = Math.toRadians(360 / NUMBER_OF_CHAIRS * seat);
        int x = (int)(TABLE_CENTER_X + TABLE_RADIUS * Math.cos(arcAngle) -
                CHAIR_DIAMETER / 2.0);
        int y = (int)(TABLE_CENTER_Y + TABLE_RADIUS * Math.sin(arcAngle) -
                CHAIR_DIAMETER / 2.0);
        return new Rectangle(new Point(x, y),
                             new Dimension(CHAIR_DIAMETER, CHAIR_DIAMETER));
      }
    }
    

    说,你需要做一些监听,所以当你按下任何圆圈时,你想突出显示它。使用 2D 中的碰撞检测,您可以做到这一点。请注意,这样做的丑陋方式如下:

      public boolean setSeat(Point coord) {
        // Quick collision detection. This is bad performance since its
        // checking each point.
        for (int i = 1; i <= NUMBER_OF_CHAIRS; i++) {
          Rectangle r = getSeatCoordinates(i);
          if (r.contains(coord)) {
            Graphics g = getGraphics();
            g.setColor(Color.RED);
            g.drawRect(r.x, r.y, r.width, r.height);
            g.dispose();
            return true;
          }
        }
        return false;
      }
    

    并且在构造函数中,可以添加鼠标监听器:

    addMouseListener(new MouseAdapter() {
      @Override
      public void mouseReleased(MouseEvent e) {
        setSeat(e.getPoint());
      }
    });
    

    我希望你学到一两件事:x

    【讨论】:

      【解决方案3】:

      如果您的每个面板都是这些 ImagePanel 中的一个,并且您只是将另一对 int 作为参数,那么您的最终绘制方法将简单地将您的 n 个不同的图像面板绘制到主图形对象上:

      public class Example extends JApplet{
           ImagePanel[] images;
      
      //whatever code you want for the rest of your applet
      
           public void paint(){
               for(ImagePanel i : images)
                    images.paintComponent();
               }
           }
       }
      

      你会将 ImagePanel 修复为:

      @Override
      public void paintComponent(Graphics g) {
          g.drawImage(img, x, y, this);
      }
      

      【讨论】:

      • 这是一个应用程序,而不是一个小程序。这会影响您覆盖paint() 方法的事实吗?
      • 我不这么认为。基本思想是相同的。我只有 JApplet 代码,但如果你发布你的主类,我可以给你更多帮助
      • 对于图像本身,它们没有任何逻辑,因此不需要处理事件。但我不确定 WHERE 代码会更新所有内容,以及如何控制正在更新的组件的属性。
      • 是的。你应该阅读一些教程或玩一下(我是通过玩来学习的)。但你的主要问题是你似乎没有覆盖paint方法。签名是 public void paint(Graphics g) - 要么你需要调用 repaint。我不完全确定。此外,使用 JApplet 然后将其放入 JFrame 以使其成为应用程序可能会更容易
      【解决方案4】:

      使用您的 ImagePanel 显示背景图像。

      然后将面板设置为使用空布局管理器。现在您可以将 ImageIcon 添加到 JLabel 并将 JLabel 添加到面板。确保你使用:

      label.setSize(label.getPreferredSize());

      否则标签不会出现。默认情况下,标签将出现在位置 (0, 0),尽管您可以使用 setLocation(...) 方法进行更改。

      要制作动画,您可以使用 Swing Timer 并将其设置为每 5 秒触发一次。当 Timer 触发时,您可以通过更改其位置来移动图像。

      如果您不知道如何使用计时器,请阅读 Swing 教程中关于“如何使用计时器”的部分。

      【讨论】:

      • 这不会改变我的回答,当然,图像移动必须发生一些“事件”。该事件可以定期安排(通过使用计时器),或者可以是用户控制的事件(例如通过单击按钮)。关键是每当事件发生时,您都必须做“某事”。在不知道你在做什么的细节的情况下,我只是建议“某事”应该设置图标的位置,这样它看起来就像它在棋盘上从一个玩家移动到另一个玩家。
      猜你喜欢
      • 2017-08-10
      • 2016-05-02
      • 1970-01-01
      • 1970-01-01
      • 2012-06-03
      • 2012-01-27
      • 2011-04-02
      • 2011-11-19
      相关资源
      最近更新 更多