I'm working on simple counter. My problem is that drawString() method draws new string over the old one. How to clear the old one before? Code...
package foobar;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class board extends JPanel implements Runnable {
Thread animator;
int count;
public board() {
this.setBackground( Color.WHITE );
count = 0;
animator = new Thread( this );
animator.start();
}
@Override
public void run() {
while( true ) {
++count;
repaint();
try {
animator.sleep( 1000 );
} catch ( InterruptedException e ) {}
}
}
@Override
public void paint( Graphics Graphics ) {
Graphics.drawString( Integer.toString( count ), 10, 10 );
}
}
P.S. I'm new to Java, so please don't be afraid to tell me what other things I should fix in my code...
Several problems in your code:
- Don't have a while (true) loop or Thread.sleep in a Swing GUI. Use a Swing Timer instead.
- Override JPanel's paintComponent, not its paint method.
- The first call in paintComponent(Graphics g) should be super.paintComponent(g), so your JPanel can do its house keeping and get rid of old graphics.
edit:
- My bad, your while (true) and Thread.sleep(...) will work since they're in a background thread, but,...
- Thread.sleep is a static method and should be called on the class, Thread, and
- I still think a Swing Timer would be an easier way to do this.
- Even easier still is to not even use a paint or paintComponent method, but rather simply set the text of a JLabel for your display.
e.g.,
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Board2 extends JPanel {
private static final int TIMER_DELAY = 1000;
private int counter = 0;
private JLabel timerLabel = new JLabel("000");
public Board2() {
add(timerLabel);
new Timer(TIMER_DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
counter++;
timerLabel.setText(String.format("%03d", counter));
}
}).start();
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Board2");
frame.getContentPane().add(new Board2());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
I think Graphics.clearRect is what you're looking for.
I would do it like this:
public void paintComponent(Graphics g)
{
super.paintComponent(g);
//draw all the other stuff
}
Aaah! This is normal. Imagine your panel as a blackboard. Each time you want to repaint what you have writed in, you will have to erase the blackboard first.
In Java, as well as in Graphics in general, things go in a similar way. In your paint method, do this:
Graphics.clearRect(0,0, getWidth(),getHeight());
//CLEAR the entire component first.
Graphics.drawString(...); //now that the panel is blank, draw the string.
When you can handle the topic better, do super.paint(Graphics)
instead of clearRect()
.