【问题标题】:Java graphics won't delete lines, even when I call super.paintComponent(g)Java 图形不会删除线条,即使我调用 super.paintComponent(g)
【发布时间】:2020-04-14 23:49:24
【问题描述】:

SO 中的第一篇文章,希望我做得对!

我正在尝试用 Java 制作一个游戏,其中一个机器人四处行驶并在附近的墙壁上发光。问题是,即使机器人移动,这些线条也会留在屏幕上,所以它会形成一团不会擦除的线条。

在paintComponent() 中,我尝试了g.fillRect(),但这并没有删除任何线条,只是在云后面绘制了一个矩形。到目前为止,我看到的每个来源似乎都暗示了我已经做过的事情,除非我误解/忽略了一些明显的事情......

'''

//from https://www.youtube.com/watch?v=p9Y-NBg8eto

/*
Other classes in this folder:
    Robot.java      Represents a robot, its location and angular orientation.
    Obstacles.java      Represents lines; the walls the robot should detect.
    Sensor.java     Represents the beams that shine from the robot to the walls.
//*/

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.lang.Math;
import java.util.ArrayList;
public class MyPanel extends JPanel implements ActionListener, KeyListener
{
    Timer t = new Timer(5, this);

    //OBSTACLES:
    Obstacles obstacles=new Obstacles(0);

    //ROBOT:
    Robot robot = new Robot(obstacles);

    //`````````````````````````````````````````````````````````
    public MyPanel()
    {
        t.start();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        setVisible(true);
    }

    @Override
    public void paintComponent(Graphics g)
    {
        g.dispose();
        super.paintComponent(g);
        //Graphics2D g2 = (Graphics2D) g;
        g.setColor(Color.RED);
        g.fillRect(0, 0, 450, 450);
        g.setColor(Color.BLACK);
        //Graphics2D g2 = (Graphics2D) g;
        robot.drawRobot(g);
        drawBoundedBeams(g);
        obstacles.drawObstacles(g);
        drawSun(g);
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        repaint();
    }

    @Override 
    public void keyPressed(KeyEvent e)
    {
        int code = e.getKeyCode();
        if (code==KeyEvent.VK_UP)
            robot.up();
        if (code==KeyEvent.VK_DOWN)
            robot.down();
        if (code==KeyEvent.VK_LEFT)
            robot.left();
        if (code==KeyEvent.VK_RIGHT)
            robot.right();

        robot.updateSensor();
    }
    @Override public void keyTyped(KeyEvent e) {}
    @Override public void keyReleased(KeyEvent e) {}

    //```````````````````````````````````````````````````````````
    public static void main(String [] args)
    {
        JFrame f = new JFrame();
        MyPanel panel = new MyPanel();
        f.add(panel);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(800, 600);
        f.setVisible(true);
    }

    //Dummy lines. For some reason, these delete and move with the robot, no problem.
    public void drawSun(Graphics g)
    {
        int x = (int) robot.x;
        int y = (int) robot.y;
        double t = robot.angle;
        double xang = Math.cos(t);
        double yang = Math.sin(t);
        double east = (t + Math.PI/2) % (2 * Math.PI);
        double eastx = Math.cos(east);
        double easty = Math.sin(east);
        g.drawLine(x, y, x+100, y);
        g.drawLine(x, y, x-100, y);
        g.drawLine(x, y, x, y+100);
        g.drawLine(x, y, x, y-100);
        g.drawLine(x, y, x+100, y+100);
        g.drawLine(x, y, x+100, y-100);
        g.drawLine(x, y, x-100, y+100);
        g.drawLine(x, y, x-100, y-100);
        g.drawLine(x, y, x+(int)(xang*100), y+(int)(yang*100));
        g.drawLine(x, y, x-(int)(xang*100), y-(int)(yang*100));
        g.drawLine(x, y, x+(int)(eastx*100), y+(int)(easty*100));
        g.drawLine(x, y, x-(int)(eastx*100), y-(int)(easty*100));
    }

    //This was in Sensor.java, but I moved it here to try to fix it. (Didn't work.)
    //THIS is what isn't getting deleted.
    public void drawBoundedBeams(Graphics g) //Graphics2D g2
    {
        //Graphics2D g2 = (Graphics2D) g;
        for (Integer[] beam : robot.sensor.boundedBeams)
        {
            g.drawLine(beam[0], beam[1], beam[2], beam[3]); 
        }
    }
}

'''

~~~~~~ EDIT: I made a Minimal ~~~~~~
~~~~~~  Reproducible Example. ~~~~~~

MyPanel.java: '''

/*
Classes in this (reprex) folder:
MyPanel.java    displays things         ****PROBLEM HERE(?)
Robot.java      stores location and orientation
Sensor.java     Shines beams outward    ****PROBLEM HERE(?)

(I tried to keep the file structure consistent,
 in case that was a factor for the issue.)
//*/

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.lang.Math;
import java.util.ArrayList;
public class MyPanel extends JPanel implements ActionListener, KeyListener
{
    Timer t = new Timer(5, this);

    Robot robot = new Robot();

    //`````````````````````````````````````````````````````````
    public MyPanel()
    {
        t.start();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        setVisible(true);
    }


    //********************************************
    //********************************************
    //********************************************
    //**** Problem seems to be HERE. *************
    //**** ~~~~~~~~~~~~~~~~~~~~~~~~  *************
    //**** (See also: the method in  *************
    //**** Sensor.java; drawBeams()) *************
    //********************************************
    //********************************************
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();

        // And to smooth out the graphics, you can do the following
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        g2.setColor(Color.RED);
        g2.fillRect(0, 0, 450, 450);
        g2.setColor(Color.BLACK);
        robot.sensor.drawBeams(g2);
        g2.dispose();
    }

    @Override 
    public void actionPerformed(ActionEvent e) 
    {
        repaint();
    }

    @Override 
    public void keyPressed(KeyEvent e)
    {
        int code = e.getKeyCode();
        if (code==KeyEvent.VK_UP)
            robot.up();
        if (code==KeyEvent.VK_DOWN)
            robot.down();
        if (code==KeyEvent.VK_LEFT)
            robot.left();
        if (code==KeyEvent.VK_RIGHT)
            robot.right();

        robot.updateSensor();
    }
    @Override public void keyTyped(KeyEvent e) {}
    @Override public void keyReleased(KeyEvent e) {}

    //```````````````````````````````````````````````````````````
    public static void main(String [] args)
    {
        JFrame f = new JFrame();
        MyPanel panel = new MyPanel();
        f.add(panel);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(800, 600);
        f.setVisible(true);
    }
}

'''

Sensor.java: '''

import java.lang.Math;
import java.util.ArrayList;
import java.awt.*;

class Sensor
{
    private Robot robot;

    public int numPieces;
    public Integer range = 300;
    public ArrayList<Double> offsets = new ArrayList<Double>();         //the angles of each beam
    public ArrayList<Integer[]> beams = new ArrayList<Integer[]>();     //the beams that stretch out to the range   public ArrayList<Integer[]> boundedBeams = new ArrayList<Integer[]>();

    public Sensor(Robot robot)
    {
        this.robot=robot;
        make12Sonars();
    }
    public void make12Sonars()  
    {
        numPieces=12;
        double offset = 0;
        while (offset < 2*Math.PI)
        {
            offsets.add(offset);
            offset += Math.PI / 6;
        }
    }

    public void updateSensor()
    {
        makeBeams();
    }

    //```````````````````````````````````````````````````````
    public void makeBeams()     //Makes the maximum beams from the angles.
    {
        System.out.println("~~~MAKING BEAMS~~~");
        for (Integer i=0; i<offsets.size(); i++)
        {
            System.out.println("\tat index "+i);
            Double offset = offsets.get(i);
            Double angle = (offset + robot.angle) % (2*Math.PI);

            Integer[] beam = getSegment(robot.x, robot.y, angle, Double.valueOf(range));
            beams.add(i, beam);
            System.out.println("\t\tadded "+beam[0]+", "+beam[1]+", "+beam[2]+", "+beam[3]);
        }
    }

    static public Integer[] getSegment(Double startX, Double startY, Double angle, Double radius)
    {
        Double x2 = radius * Math.cos(angle) + startX;
        Double y2 = radius * Math.sin(angle) + startY;
        Integer[] segment = {startX.intValue(), startY.intValue(), x2.intValue(), y2.intValue()};
        return segment;
    }


    //********************************************
    //********************************************
    //********************************************
    //**** Problem seems to be HERE. *************
    //**** ~~~~~~~~~~~~~~~~~~~~~~~~  *************
    //**** (The lines drawn here     *************
    //****  do not delete.)          *************
    //********************************************
    //********************************************
    public void drawBeams(Graphics g)
    {
        Integer x = (int) robot.x;
        Integer y = (int) robot.y;
        for (Integer[] beam : beams)
        {
            g.drawLine(beam[0], beam[1], beam[2], beam[3]);
        }
    }
}

'''

机器人.java: '''

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.lang.Math;
class Robot
{
    public double x=0, y=0; //center of the robot
    public double velx=0, vely=0; //velocity of the robot
    public double angle=0, speed=4; //radians, speed(before_direction)

    public Sensor sensor;
    public Robot()
    {
        sensor=new Sensor(this);
    }
    public void updateSensor() {sensor.updateSensor();}

    //`````````````````````````````````````````````````````````````
    //*
    public void up() {x+=velx; y+=vely;}
    public void down() {x-=velx; y-=vely;}
    public void left()
    {
        angle -= 0.1;
        angle = angle % (2*Math.PI);
        velx = speed * Math.cos(angle);
        vely = speed * Math.sin(angle);
    }
    public void right()
    {
        angle += 0.1;
        angle = angle % (2*Math.PI);
        velx = speed * Math.cos(angle);
        vely = speed * Math.sin(angle);
    }   //*/
}

'''

【问题讨论】:

    标签: java swing graphics jpanel paintcomponent


    【解决方案1】:

    您不应该在paintComponent() 的开头处理default graphics context。最好的办法是通过 create 创建一个副本,然后在您从 paintComponent() 返回之前将其处理掉。

    Try this as a your `paintComponent()` method.
    
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g.create();
    
            // And to smooth out the graphics, you can do the following
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
    
            g2.setColor(Color.RED);
            g2.fillRect(0, 0, 450, 450);
            g2.setColor(Color.BLACK);
            robot.drawRobot(g2);
            drawBoundedBeams(g2);
            obstacles.drawObstacles(g2);
            drawSun(g2);
            g2.dispose();
        }
    
    

    如果这不能帮助解决您的问题,请发送Minimal Reproducible Example 来说明问题。它不应依赖任何不在 JDK API 中的东西(即第三方类、库等)

    【讨论】:

    • 谢谢您——很遗憾,您的建议的 A 部分不起作用,因此我已尽最大努力编辑了原始帖子。
    • 首先,将定时器延迟设置为大约 50 毫秒 t.setDelay(50)。我用MyPanel 构造函数做到了。然后,在 makeBeams 方法中的 for loop 之前,输入 beams.clear();
    • 哇,所以它甚至不是 JPanel 的问题,只是我自己的数据存储!非常感谢您解决这个问题;对此,我真的非常感激!! (这个问题现在基本上解决了。)保重!! :)
    猜你喜欢
    • 2012-09-30
    • 2015-05-09
    • 2016-06-16
    • 2010-11-02
    • 1970-01-01
    • 2011-09-07
    • 2015-04-27
    • 2015-12-20
    • 2019-10-03
    相关资源
    最近更新 更多