添加对象到面板,而不重新开始?

时间:2014-04-21 17:38:24

标签: java swing graphics panel

假设我已经创建了一个Frame和Panel。我正在做一些计算,我想在已经显示在该框架/面板中的现有图形中添加一些内容。 如何添加到现有的Graphics对象?

例如,从下面的代码开始,这将创建一个带有一些图形的简单窗口。现在它已经在屏幕上,并且已经执行了“paintComponent”方法,我想为这个对象添加额外的图形(线条,方框......)

我只看到两个选项:

  1. 创建一个全新的对象并从“scratch”开始将所有旧对象添加到Graphics对象“g”
  2. 将逻辑放入“paintComponent”方法以侦听要添加的其他对象,然后等待重绘帧(例如frame.repaint())
  3. 两者似乎都不是特别优雅。什么是“标准”解决方案?考虑这种情况的OO方式是什么?

    import javax.swing.JFrame;
    import java.awt.Graphics;
    import javax.swing.JPanel;
    import java.awt.Color;
    import javax.swing.JLabel;
    import javax.swing.ImageIcon;
    import java.awt.BorderLayout; 
    
    public class testSimpleOverlay extends JPanel
    {
        public testSimpleOverlay()                       // set up graphics window
        {
            super();
            setBackground(Color.WHITE);
        }
    
        public void paintComponent(Graphics g)  // draw graphics in the panel
        {
            int width = getWidth();             // width of window in pixels
            int height = getHeight();           // height of window in pixels
    
            super.paintComponent(g);            // call superclass to make panel display correctly
    
    
            g.drawString("Hello, World", 100, 150); 
            g.drawLine(0, 0, 20, 40); 
            g.drawRect(10, 10, 200, 100); 
    
        }
    
        public static void main(String[] args)
        {
            testSimpleOverlay panel = new testSimpleOverlay();                            // window for drawing
            JFrame application = new JFrame();                            // the program itself
    
            application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   // set frame to exit
                                                                      // when it is closed
            application.add(panel);           
    
            application.setSize(500, 400);         // window is 500 pixels wide, 400 high
            application.setVisible(true);          
        }
    
    }
    

    对于那些对细节感兴趣的人,我打算在屏幕上放置一个栅格化图像(不是PNG或JPEG,而是计算),然后在我的代码“找到”图像中的对象时突出显示部分图像。

    我对选项(1)不感兴趣的一个原因是,最终,我将在Panel中有一长串对象。这意味着我需要等待整个计算完成以获得所有“亮点”。

    我希望看到屏幕上显示的高光。这意味着我需要等待整个计算完成(如上所述),或者我需要在添加每个新突出显示之后从突出显示列表的开头重新渲染。当我真正想做的就是添加到现有渲染中时,每次渲染都会花费更长时间。

    这些选项似乎都不是很聪明。必须有更好的方法......

2 个答案:

答案 0 :(得分:1)

  

“考虑这种情况的OO方式是什么?”

  1. 使用interface,假设Drawable方法draw覆盖

    public interface Drawable {
        public void draw(Graphics);
    }
    
  2. 让一个或多个类实现该类

    public class Ball implements Drawable {
        ...
        @Override
        public void draw(Graphics g) {
            g.fillOval(x, y, width, height);
        }
    }
    
  3. 在面板类中保留List<Drawable>。在paint方法中迭代List并调用每个方法的draw方法

    List<Drawable> drawables;
    ...
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (drawables != null) {
            for (Drawable drawable : drawables) {
                drawable.draw(g);
            }
        }
    }
    
  4. 每当您想要添加另一个可绘制对象时,只需将其添加到列表并重新绘制

    public void addDrawable(Drawable drawable) {
        drawables.add(drawable);
        repaint();
    }
    
  5. 请注意,您可以使用所需的多种类来实现Drawable。您可以拥有SquareCircleSheepDragon,只要它们实现了界面并覆盖draw方法,就可以将其添加到列表并使用paintComponent方法绘制。

答案 1 :(得分:0)

您可以创建一个BufferedImage并将其用作屏幕外缓冲区,逐步将结果渲染到该缓冲区,然后在绘制组件时将其绘制到屏幕上。

这样的事情:

public class Overlay extends JPanel {
    private BufferedImage buffer;

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (buffer == null) {
            buffer = (BufferedImage) createImage(
                             getSize().width, getSize().height);
        }
        g.drawImage(buffer, 0, 0, this);
    }

    public BufferedImage getBuffer() {
        return buffer;
    }
}

其他地方:

public class Calculate implements Runnable {
    private Overlay overlay;

    public void run() {
        // perform calculations
        Graphics2D g2 = overlay.getBuffer().createGraphics();
        // update buffer
        g2.dispose();
        overlay.repaint();
    }
}

new Thread(new Calculate(overlay).start();

我暂时没有这样做。我不记得你是否想要保持图形对象的整个时间,计算正在进行,或者如果你想处理它并为每次更新创建一个新的。此外,如果可以调整组件的大小,或者图像没有填充整个组件,则还需要考虑以不同的大小重新创建缓冲区,并绘制整个组件。

有关详细信息,请参阅此off-screen paint example