Reputation: 51
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
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
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
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