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