Java 如何在swing中重新绘制而不删除以前绘制的对象
所以,我想用java和swing实现DDA算法来画线,但这里有一个小问题。要绘制每个像素,我使用Java 如何在swing中重新绘制而不删除以前绘制的对象,java,swing,graphics,awt,Java,Swing,Graphics,Awt,所以,我想用java和swing实现DDA算法来画线,但这里有一个小问题。要绘制每个像素,我使用fillRect(X,Y,1,1)。因此,我需要为X和Y的不同位置绘制一条线。为了更新新绘制的“像素”,我正在使用revalidate()和repaint()但这似乎删除了我以前绘制的像素,我只看到了一点。作为一种解决方法,我在我的paintComponent(Graphics)中注释掉了super.paintComponent(g),但这似乎不是一个好的解决方案,因为这样我就无法设置背景色,如果我使
fillRect(X,Y,1,1)
。因此,我需要为X
和Y
的不同位置绘制一条线。为了更新新绘制的“像素”,我正在使用revalidate()
和repaint()
但这似乎删除了我以前绘制的像素,我只看到了一点。作为一种解决方法,我在我的paintComponent(Graphics)
中注释掉了super.paintComponent(g)
,但这似乎不是一个好的解决方案,因为这样我就无法设置背景色,如果我使用Thread.sleep()
(另一方面,我只看到一个点)减慢速度,我就会看到画出一条线。这是密码
import javax.swing.*;
import java.awt.*;
public class Painter extends JPanel {
private double x1,y1,x2,y2;
Painter(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
@Override
protected void paintComponent(Graphics g) {
//super.paintComponent(g);
setBackground(Color.black);
g.setColor(Color.RED);
g.fillRect((int)x1,(int)y1,1,1);
}
public void drawLine() {
double DX = (x2-x1);
double DY = (y2-y1);
double steps = (Math.abs(DX) > Math.abs(DY) ) ? Math.abs(DX) : Math.abs(DY);
double xIncrement = DX/(steps);
double yIncrement = DY/(steps);
try {
for (int i = 0; i < steps; ++i) {
Thread.sleep(50);
x1 += xIncrement;
y1 += yIncrement;
revalidate();
repaint();
}
}
catch (Exception e) {
}
}
}
如何修复它?您应该跟踪当前点以重新绘制它们
private final List<ArrayList<Integer>> points = new ArrayList<ArrayList<Integer>>();
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.black);
g.setColor(Color.RED);
for(ArrayList<Integer> point : points) {
g.fillRect(point.get(0),point.get(1),1,1);
}
}
public void drawLine() {
double DX = (x2-x1);
double DY = (y2-y1);
double steps = (Math.abs(DX) > Math.abs(DY) ) ? Math.abs(DX) : Math.abs(DY);
double xIncrement = ((double)DX/(double)(steps));
double yIncrement = ((double)DY/(double)(steps));
try {
for (int i = 0; i < steps; ++i) {
Thread.sleep(50);
x1 += xIncrement;
y1 += yIncrement;
points.add(new ArrayList<Integer>(){{add((int)x1); add((int)y1);}});
revalidate();
repaint();
}
}
catch (Exception e) {
}
}
private final List points=new ArrayList();
@凌驾
受保护组件(图形g){
超级组件(g);
挫折背景(颜色:黑色);
g、 setColor(Color.RED);
用于(阵列列表点:点){
g、 fillRect(point.get(0),point.get(1),1,1);
}
}
公共空水位线(){
双DX=(x2-x1);
双DY=(y2-y1);
双步骤=(Math.abs(DX)>Math.abs(DY))?Math.abs(DX):Math.abs(DY);
双x增量=((双)DX/(双)(步数));
双阴增量=((双)DY/(双)(步数));
试一试{
对于(int i=0;i
这是一个糟糕的设计,但我做它来演示你必须做什么。最好的情况是创建一个Point类并将点存储在
数组列表中
我将使用屏幕外图像解决问题,这样您就不必忽略super.paintComponent()代码>:
导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.image.buffereImage;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
公共类油漆工扩展JPanel{
缓冲图像办公室;
制图主任;
专用双x1,y1,x2,y2;
油漆工(内部x1、内部y1、内部x2、内部y2){
这是1.x1=x1;
这是1.y1=y1;
这是0.x2=x2;
这1.y2=y2;
}
@凌驾
受保护的组件(图形g){
超级组件(g);
g、 drawImage(offi,0,0,this);
}
私人提款(){
if(offi==null){
OFI=(BuffereImage)createImage(getWidth(),getHeight());
offg=offi.getGraphics();
offg.setColor(颜色为黑色);
offg.fillRect(0,0,getWidth(),getHeight());
}
offg.setColor(颜色为红色);
副秘书长(内部)x1,(内部)y1,1,1);
}
公共空水位线(){
双DX=(x2-x1);
双DY=(y2-y1);
双步骤=(Math.abs(DX)>Math.abs(DY))?Math.abs(DX):Math.abs(DY);
双X增量=DX/(步);
双yIncrement=DY/(步);
对于(int i=0;i{
JFrame JFrame=新JFrame(“图形”);
油漆工dpl=新油漆工(0,0533333);
jFrame.add(dpl);
jFrame.setSize(720480);
jFrame.setresizeable(false);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(jFrame.EXIT_ON_CLOSE);
新螺纹(()->dpl.drawLine()).start();;
});
}
}
有时会看到一条线,有时只看到一个点,原因是swing会合并在短时间内发生的连续调用。这取决于您希望如何绘制线。您应该从单独的线程调用drawLine
<代码>重绘
可以安全地从EDT外部调用,您可以通过调用EDT上的绘图线
(其中包含sleep()
)来阻止EDT。@西格玛:这是您想要的解决方案(+1)。在IF块中,可以考虑包装<代码> G.DRAWMAMAGE(…)<代码>,<代码> if(Offi!= NULL)< /代码>如果它有可能是NULL。不需要PrimtCe组件(…)方法上的“同步”关键字。所有Swing绘制代码都在事件调度线程(EDT)上执行。@camickr我认为,由于我在回答中使用了单独的动画线程,paintComponent()
中的代码可能必须与draw()中的代码同步。单独同步paintComponent()
确实毫无意义,但我认为使draw
同步可能比从paintComponent()
中删除同步的更干净,因为buffereImage
不是完全线程安全的。
private final List<ArrayList<Integer>> points = new ArrayList<ArrayList<Integer>>();
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.black);
g.setColor(Color.RED);
for(ArrayList<Integer> point : points) {
g.fillRect(point.get(0),point.get(1),1,1);
}
}
public void drawLine() {
double DX = (x2-x1);
double DY = (y2-y1);
double steps = (Math.abs(DX) > Math.abs(DY) ) ? Math.abs(DX) : Math.abs(DY);
double xIncrement = ((double)DX/(double)(steps));
double yIncrement = ((double)DY/(double)(steps));
try {
for (int i = 0; i < steps; ++i) {
Thread.sleep(50);
x1 += xIncrement;
y1 += yIncrement;
points.add(new ArrayList<Integer>(){{add((int)x1); add((int)y1);}});
revalidate();
repaint();
}
}
catch (Exception e) {
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Painter extends JPanel {
BufferedImage offi;
Graphics offg;
private double x1,y1,x2,y2;
Painter(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
@Override
protected synchronized void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(offi,0,0,this);
}
private void draw(){
if(offi == null){
offi = (BufferedImage)createImage(getWidth(),getHeight());
offg = offi.getGraphics();
offg.setColor(Color.black);
offg.fillRect(0,0,getWidth(),getHeight());
}
offg.setColor(Color.RED);
offg.fillRect((int)x1,(int)y1,1,1);
}
public void drawLine() {
double DX = (x2-x1);
double DY = (y2-y1);
double steps = (Math.abs(DX) > Math.abs(DY) ) ? Math.abs(DX) : Math.abs(DY);
double xIncrement = DX/(steps);
double yIncrement = DY/(steps);
for (int i = 0; i < steps; ++i) {
x1 += xIncrement;
y1 += yIncrement;
/*try{
Thread.sleep(50); //sleep if you want it to be animated
}catch(InterruptedException e){
e.printStackTrace();
}*/
draw();
repaint();
}
}
public static void main(String[] args){
SwingUtilities.invokeLater(() -> {
JFrame jFrame = new JFrame("Graphics");
Painter dpl = new Painter(0,0,533,333);
jFrame.add(dpl);
jFrame.setSize(720,480);
jFrame.setResizable(false);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
new Thread(() -> dpl.drawLine()).start();;
});
}
}