ali-nb
ali-nb

Reputation: 51

Swing paint method

I have problem in paint method in a JPanel. At first I create a class that extends JFrame. Then I create a class that extends panel and create a object from this class and add to frame.

I want by pressing the right button on keyboard (VK_RIGHT) the little rectangles be drawn on panel Within 2 seconds. (That means rectangle clear and be drawn in a new location. My problem is: I can not do timing paint method and repaint method. I wish every two seconds rectangle go ahead for 5 times (step by step) but rectangle go ahead just one.

my codes are:

Panel

import java.awt.Color;

import java.awt.Graphics;

import javax.swing.JPanel;

public class Panel extends JPanel{

    private int x;
    private int y;
    public Panel()
    {
        x=100;
        y=100;
        this.setBackground(Color.RED);
    }

    //--------------------------------

    @Override
    public void paint(Graphics g)
    {
        super.paint(g);

        g.setColor(Color.BLACK);

        g.fillRect(x, y, 20, 20);
    }

    //--------------------------------

    @Override
    public void repaint()
    {
        super.repaint();

        x+=20;
    }

    //--------------------------------
}

Frame

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import javax.swing.JFrame;

public class Frame extends JFrame {

    private Panel p;

    public Frame()
    {
        super("Test");
        this.setBounds(1200, 300, 400, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        p=new Panel();
        this.add(p);


        this.addKeyListener(new KeyLis());
    }

    //----------------------------------

    public static void main(String[] args) {

        Frame a=new Frame();

        a.setVisible(true);
    }

    //-----------------------------------

    private class KeyLis implements KeyListener
    {

        @Override
        public void keyPressed(KeyEvent arg0) {

            if(arg0.getKeyCode() == KeyEvent.VK_RIGHT)
            {
                for(int i=0;i<5;i++)
                {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    p.repaint();
                }
            }
        }
        //---------------
        @Override
        public void keyReleased(KeyEvent arg0) {
            // TODO Auto-generated method stub

        }
        //---------------
        @Override
        public void keyTyped(KeyEvent arg0) {
            // TODO Auto-generated method stub

        }
        //---------------
    }
    //-----------------------------------------
}

Upvotes: 0

Views: 1254

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347184

Your problem, primarily, is the for-loop in the KeyListener, which is blocking the Event dispatching thread, preventing updates from been painted.

Simple solution is to use a Swing Timer, it waits in the background, triggers ticks on the EDT, making safe it update the ui from and schedules updates at regular intervals.

See Concurrency in Swing and How to use Swing Timers for more details

If, for some reason, you find Swing Timer to difficult to comprehend, you could also try using a SwingWorker, which will allow you to use a background thread to loop in, but which provides methods to update states within the context of the EDT.

See Worker Threads and SwingWorker for more details

Recommendations

Override paintComponent instead of paint as a general rule. See Performing Custom Painting for more details

Don't use repaint to update your state, you may not be the only one calling it, instead, create a model which can be shared between the view and you key controller.

See Model-View-Controller and Observer Pattern for some ideas

I'd also discourage the use of KeyListener and make use of the key bindings API instead

See How to Use Key Bindings for more details

Upvotes: 2

Emanuel Ramirez
Emanuel Ramirez

Reputation: 412

If you are set on using a Thread:

Changed your KeyPressed event to:

        @Override
        public void keyPressed(KeyEvent arg0) {

            if (arg0.getKeyCode() == KeyEvent.VK_RIGHT) {
                PaintThread th = new PaintThread(p);
                th.start();
            }
        }

Created a Thread:

import java.util.logging.Level;
import java.util.logging.Logger;

public class PaintThread extends Thread{

    Panel panel;

    PaintThread(Panel panel){
        this.panel = panel;
    }

    @Override
    public void run() {
        for(int i = 0; i<5; i++){
            try {
                this.sleep(1000);
                panel.repaint();
            } catch (InterruptedException ex) {
                Logger.getLogger(PaintThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

}

Upvotes: 0

Related Questions