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

Java 将对象添加到面板,而不重新开始?,java,swing,graphics,panel,Java,Swing,Graphics,Panel,假设我已经创建了一个框架和面板。我正在进行一些计算,我想在该框架/面板中已经显示的现有图形中添加一些内容。如何添加到现有的图形对象 例如,从下面的代码开始,这将创建一个包含一些图形的简单窗口。现在它已经出现在屏幕上,并且“paintComponent”方法已经执行,我想为这个对象添加额外的图形(线、框等) 我只看到两种选择: 创建一个全新的对象,从“零开始”,将所有旧对象添加到图形对象“g” 将逻辑放入“paintComponent”方法,以侦听要添加的其他对象,然后等待重新绘制帧(例如fram

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

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

我只看到两种选择:

  • 创建一个全新的对象,从“零开始”,将所有旧对象添加到图形对象“g”
  • 将逻辑放入“paintComponent”方法,以侦听要添加的其他对象,然后等待重新绘制帧(例如frame.repaint())
  • 这两个似乎都不是特别优雅。什么是“标准”解决方案?什么是正确的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)不感兴趣的一个原因是,最终,我会在面板中列出一长串对象。这意味着我需要等待整个计算完成才能获得所有的“亮点”

    我想看到屏幕上出现的亮点。这意味着我要么需要等待整个计算完成(如上所述),要么需要在添加每个新的高光后从高光列表的开始重新渲染。当我真正想做的只是添加到现有渲染中时,每次渲染将花费越来越长的时间


    这两种选择似乎都不是很聪明。必须有更好的方法…

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

    大概是这样的:

    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();
    
    我已经有一段时间没有这样做了。我不记得您是希望在整个计算过程中保留图形对象,还是希望处理它并为每次更新创建一个新的图形对象。此外,如果可以调整组件的大小,或者如果图像没有填充整个组件,则需要考虑以不同的大小重新创建缓冲区,并绘制整个组件

    有关更多详细信息,请参见此

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

  • 使用
    接口
    ,例如
    可绘制
    ,并使用方法
    绘制
    来覆盖

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

    public class Ball implements Drawable {
        ...
        @Override
        public void draw(Graphics g) {
            g.fillOval(x, y, width, height);
        }
    }
    
  • 在panel类中保留一个
    列表
    。在paint方法中遍历列表,并调用每个列表的draw方法

    List<Drawable> drawables;
    ...
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (drawables != null) {
            for (Drawable drawable : drawables) {
                drawable.draw(g);
            }
        }
    }
    
  • 请记住,您可以使用所需的多种不同类型的类来实现
    Drawable
    。您可以拥有一个
    正方形
    圆形
    绵羊
    ,只要它们实现了接口并覆盖了
    绘制
    方法,就可以将其添加到列表中,并在
    绘制组件
    方法中绘制


  • 渲染到屏幕外缓冲区,在计算过程中更新该缓冲区并请求重新绘制,然后在重新绘制时将缓冲区blit到屏幕。我对Graphics2D体系结构的理解是,每个g.object都会向要渲染的对象列表中添加一些内容。您是否建议我在屏幕外的缓冲区中进行渲染,但每次都要用干净的面板从头开始?这就是我想要避免的。我可以将屏幕上的缓冲区复制到屏幕外的缓冲区并添加到其中吗?如果要提高计算速度,请查看fork/join框架。它分割计算,使多个线程可以在一个目标上工作。我不太清楚你们所说的“看到屏幕上的所有亮点”是什么意思。如果高亮显示,你的意思是“悬停在某物上,它会亮起”,但是想要立即看到高亮显示,这取决于你计划如何高亮显示内容。不,我建议屏幕外缓冲区包含计算的当前状态,当计算发现它们时,您只需使用最新的更改对其进行更新。Google中的blit+java的点击率相对较低。。。你能为“BLIT”提供一个参考吗?关闭…让我进一步解释:步骤1:创建背景对象。此对象包含其中的功能。创建包含许多表示这些特征的形状(例如矩形)的图形对象。向用户展示这一点,这样他们就不必永远等着看我在做什么。步骤2:开始筛选屏幕上显示的对象。当你找到一个符合你想要的,画一个圆圈围绕它。这一步可能需要很长时间,因此您不希望用户等待重新渲染整个内容,而是希望显示增量进度。一旦你有了一个屏幕外的缓冲区,你就可以很容易地在它上面画一个背景图像,在它上面画矩形,在它上面画圆圈,等等。这样就可以“重新渲染整个东西”。当你知道在哪里画一个圆时,你只需画一个圆,然后调用重新绘制。很好。。。这就是我想要理解的哲学。现在把它付诸实践,看看我是否能使它工作!
    public void addDrawable(Drawable drawable) {
        drawables.add(drawable);
        repaint();
    }