3

I have a "car" made with various objects using graphics g and I want to move it when a button is pressed. With that, I had no problem, but I have a problem with its path. When the car is moved, the old position is not cleared out.

Code of the car (to move when button is pressed):

    static void gPostavi2(Graphics g){
    Graphics2D g2d = (Graphics2D) g;

    for(int x=500; x>89; x--){
        //risanje
        g2d.setColor(Color.blue);
        g2d.fillRect(x+10, 351, 118, 23);
        g2d.fillRect(x+12, 321, 30, 40);
        g2d.fillRect(x+45, 330, 83, 20);
        g2d.setColor(Color.black);      
        g2d.fillOval(x+19, 362, 20, 20);
        g2d.fillOval(x+90, 362, 20, 20);
        g2d.drawString("2t", x+70, 344);
        try {

            Thread.sleep(5);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }       
}

In this class are only methods for moving things around, the class extends another that has non-moving objects, buttons, labels,... and the paintComponent method.

How can I clear the old position, every time the for statement goes around ?

EDIT: some more code down here. In the main class I have only this code:

    public static void main(String[] args) {
    staticnaGrafika.dodajGumbe();
}

In staticnaGrafika I have a ton of code, but this is the beginning of paintComponent:

public class staticnaGrafika extends JPanel{

staticnaGrafika(){
        setBorder(BorderFactory.createLineBorder(Color.black));
    }
    public Dimension getPreferredSize(){
        return new Dimension(1100, 740);
    }

public void paintComponent(Graphics g){
    super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);

        //opticno stikalo 
        //preveri, ce ga plosca prekriva pri max. dvigu
        g2d.setColor(Color.black);
        g2d.fillOval(21, 148, 33, 33);
        g2d.setColor(Color.yellow);
        g2d.fillOval(22, 149, 31, 31);
        g2d.setColor(Color.black);      
        g2d.fillRect(13, 159, 11, 1); //el. prikljucnice
        g2d.fillRect(13, 166, 10, 1);
        g2d.drawOval(7, 157, 5, 5);
        g2d.drawOval(7, 164, 5, 5);

        //naslon; spodnji omejevalec hoda bata
        g2d.setColor(Color.black);
        g2d.fillRect(5, 350, 13, 43);
        g2d.fillRect(5, 380, 63, 13);
        g2d.fillRect(262, 350, 408, 13);
        g2d.fillRect(262, 350, 13, 43);
        g2d.fillRect(212, 380, 63, 13);

there is just painting in here. Below I have another method, which adds buttons, actionListeners:

    public static void dodajGumbe() {
    final JFrame f = new JFrame();

    //dvig, stop, spust
    JButton dvig = new JButton("DVIGNI");
    dvig.setBackground(Color.WHITE);
    dvig.setFocusPainted(false);
    dvig.setBounds(850,15,120,30);

    JButton stop = new JButton("STOP");
    stop.setBackground(Color.WHITE);
    stop.setFocusPainted(false);
    stop.setBounds(850,50,120,30);

    JButton spust = new JButton("SPUSTI");
    spust.setBackground(Color.WHITE);
    spust.setFocusPainted(false);
    spust.setBounds(850,85,120,30);

    //komande bremen
    JButton postavi2 = new JButton("nalozi breme");
    postavi2.setBackground(Color.WHITE);
    postavi2.setFocusPainted(false);
    postavi2.setBounds(760,240,120,30);

    JButton odvzemi2 = new JButton("razlozi breme");
    odvzemi2.setBackground(Color.WHITE);
    odvzemi2.setFocusPainted(false);
    odvzemi2.setBounds(760,275,120,30);

    JButton postavi5 = new JButton("nalozi breme");
    postavi5.setBackground(Color.WHITE);
    postavi5.setFocusPainted(false);
    postavi5.setBounds(760,330,120,30);

    JButton odvzemi5 = new JButton("razlozi breme");
    odvzemi5.setBackground(Color.WHITE);
    odvzemi5.setFocusPainted(false);
    odvzemi5.setBounds(760,365,120,30);

    Container gumbi = f.getContentPane();

    spust.addActionListener(new ActionListener(){ 
        public void actionPerformed(ActionEvent arg0) {
        dinamicnaGrafika.gSpusti(f.getGraphics());
    }});

    dvig.addActionListener(new ActionListener(){ 
        public void actionPerformed(ActionEvent arg0) {
            dinamicnaGrafika.gDvigni(f.getGraphics());
    }});

    stop.addActionListener(new ActionListener(){ 
        public void actionPerformed(ActionEvent arg0) {
            dinamicnaGrafika.gStop(f.getGraphics());
    }});

    postavi2.addActionListener(new ActionListener(){ 
        public void actionPerformed(ActionEvent arg0) {
            dinamicnaGrafika.gPostavi2(f.getGraphics());
    }});

    odvzemi2.addActionListener(new ActionListener(){ 
        public void actionPerformed(ActionEvent arg0) {
            dinamicnaGrafika.gOdvzemi2(f.getGraphics());
    }});

    postavi5.addActionListener(new ActionListener(){ 
        public void actionPerformed(ActionEvent arg0) {
            dinamicnaGrafika.gPostavi5(f.getGraphics());
    }});

    odvzemi5.addActionListener(new ActionListener(){ 
        public void actionPerformed(ActionEvent arg0) {
            dinamicnaGrafika.gOdvzemi5(f.getGraphics());
    }});

    gumbi.add(dvig);
    gumbi.add(stop);
    gumbi.add(spust);
    gumbi.add(postavi2);
    gumbi.add(odvzemi2);
    gumbi.add(postavi5);
    gumbi.add(odvzemi5);

    f.getContentPane();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.add(new staticnaGrafika());
    f.pack();
    f.setVisible(true);
}
Skynet
  • 83
  • 8
  • possible duplicate of [JPanel Graphics clearing and repainting?](http://stackoverflow.com/questions/6902771/jpanel-graphics-clearing-and-repainting) – Frakcool Sep 21 '15 at 18:14
  • Unless you maintain a list of coordinates for your car image, else your previous coordinates will not be kept. Which means to say, there is no need to clear your old position (as there is none to be cleared). The previous image is there most probably because you did not clear your screen before you repaint. – user3437460 Sep 21 '15 at 18:24
  • @Skynet I have added another fully working solution below. You should take a look at it. – user3437460 Sep 21 '15 at 21:02
  • @Skynet Have your problems been solved? – user3437460 Sep 22 '15 at 11:54

3 Answers3

4

You probably forgot to call

super.paintComponent(g);

in your paintComponent() method

@Override
protected void paintComponent(Graphics g){
    super.paintComponent(g);  //Clear screen before redraw
    //Your codes for painting..
}
user3437460
  • 17,253
  • 15
  • 58
  • 106
  • @Skynet In that case, you may want to show more of your codes, particularly on painting and updating of object's coordinates. – user3437460 Sep 21 '15 at 19:07
  • I have added more code to the post. I hope it's more clear now. – Skynet Sep 21 '15 at 19:37
  • @Skynet I am afraid the codes you added are not really related to your current problem. Do you maintain a list of coordinates for your car object? Are all the fllRect and drawOval codes supposed to be the codes for drawing your car object? – user3437460 Sep 21 '15 at 19:44
  • yes, the original code I posted is of the car. It's in a for statement, so the car is moving left on the screen, when the button is pressed. fillRect are the codes for the upper part of the car, when oval are the wheels, so you can make an image in your head. I think the coordinates are not saved anywhere. – Skynet Sep 21 '15 at 19:53
  • The thing I can make work is to draw over the same position same ovals and rect, but with background colour. – Skynet Sep 21 '15 at 20:30
  • @Skynet I have coded a full working example for you.. I will post it in a minute. – user3437460 Sep 21 '15 at 20:49
4

You should never be calling sleep() on the UI thread. Instead, I highly recommend that you use javax.swing.Timer and an ActionListener. Something like:

 void paintCar(Graphics2D g2d, int x) {
    g2d.setColor(Color.blue);
    g2d.fillRect(x+10, 351, 118, 23);
    g2d.fillRect(x+12, 321, 30, 40);
    g2d.fillRect(x+45, 330, 83, 20);
    g2d.setColor(Color.black);      
    g2d.fillOval(x+19, 362, 20, 20);
    g2d.fillOval(x+90, 362, 20, 20);
    g2d.drawString("2t", x+70, 344);
}       

int x = 0;
public MyConstructor() {
  new Timer(5, this).start();
}

public void actionPerformed(ActionEvent ae) {
  x++;
  repaint();
}

public void paintComponent(Graphics g) {
  super.paintComponent(g);
  Graphics2D g2d = (Graphics2D) g;
  paintCar(g2d, x);
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
1

It looks like the problem lies with your implementation. You could create a class for your Car objects and each car object keep track of their own coordinates.

For your case, if you are only moving the cars only when the button is clicked, you don't even need a Timer. Just update the car's position in the ActionListener for every button click.

OUTPUT: enter image description here

class Car
{
    private Color carColor;
    private int x, y;
    private int speed;
    private static int carWidth = 100;  
    private static int carHeight = 30;

    public Car(Color carColor, int speed){
        this.carColor = carColor;
        this.speed = speed;
        x = 0;
        y = 0;
    }

    public void moveTo(int x, int y){
        this.x = x;
        this.y = y;
    }

    public void draw(Graphics g){
        //Draw a car object
        g.setColor(carColor);
        g.fillRect(x, y, carWidth, carHeight);
        g.setColor(Color.BLACK);
        //Draw Wheels
        g.fillOval(x, y+carHeight, 30, 30); 
        g.fillOval(x+carWidth-30, y+carHeight, 30, 30);     
    }

    public int getX(){return x;}
    public int getY(){return y;}    
    public int getSpeed(){return speed;}        
}

So when you move your car(s), just update their positions and that's all you need to do. Pay special attention to my paintComponent() method. You should keep that method simple and clutter free. It is only responsible for painting. All the movements of cars is done else where.

class DrawingSpace extends JPanel implements ActionListener{
    Car c1, c2, c3; 

    public DrawingSpace(){
        setPreferredSize(new Dimension(800, 400));
        c1 = new Car(Color.RED, 5);
        c2 = new Car(Color.GREEN, 8);
        c3 = new Car(Color.BLUE, 10);
        c1.moveTo(10, 50);              
        c2.moveTo(10, 180);
        c3.moveTo(10, 280);                 
    }

    public void moveCars(){             
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        c1.draw(g);
        c2.draw(g);
        c3.draw(g);
    }

    @Override
    public void actionPerformed(ActionEvent e){
        //Used for timer (to animate moving cars)
        c1.moveTo((c1.getX()+c1.getSpeed()), c1.getY());
        c2.moveTo(c2.getX()+c2.getSpeed(), c2.getY());
        c3.moveTo(c3.getX()+c3.getSpeed(), c3.getY());
        if(c1.getX() > 800)
            c1.moveTo(0, c1.getY());
        if(c2.getX() > 800)
            c2.moveTo(0, c2.getY());
        if(c3.getX() > 800)
            c3.moveTo(0, c3.getY());                        
        repaint();          
    }
}

For a task like this, it will be better and easier to use javax.swing.timer instead of implementing your own loop with Thread.sleep().

class MovingCars{
    public static void main(String[] args){

      javax.swing.SwingUtilities.invokeLater(new Runnable(){
         public void run() {        
            JFrame f = new JFrame("Moving Cars");
            DrawingSpace ds = new DrawingSpace();
            f.setVisible(true);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(ds);
            f.pack();
            f.setLocationRelativeTo(null);
            Timer t = new Timer(50, ds); //Delay of 50 milliseconds
            t.start();
         }
      });       
    }
}
user3437460
  • 17,253
  • 15
  • 58
  • 106
  • **Remarks:** Everything is coded by me, and let me know if you have questions on this. When you move your cars, you can just update their coordinates. You are currently doing multiple painting through the for-loop on the same car object, that is why you are seeing the old image. – user3437460 Sep 21 '15 at 21:01