public class Ova extends JPanel implements ActionListener{
int x=0;
Timer timer=new Timer(100,this);
int y=0,x1=5,y1=5;
public static void main(String[] ds)
{
Ova ss=new Ova();
ss.nn();
}
private void nn() {
JFrame frame=new JFrame("fram");
frame.setSize(1000,600);
JPanel as=new JPanel();
frame.add(as);
frame.add(new Ova());
frame.setVisible(true);
timer.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawOval(x, y, 50, 50);
}
public void actionPerformed(ActionEvent e) {
if (x<0 || x>950){
x1=-x1;
}
if (y<0 || y>530)
{
y1=-y1;
}
x=x+x1;
y=y+y1;
repaint();
}
}
Whenever I put timer.start() inside paintComponent() the repaint() method works but if I start the timer outside the paint component method the repaint method does not work.Please explain the reasons. Thank you.
Problem
You have mis-matched reference issue
Start with this snippet...
public class Ova extends JPanel implements ActionListener {
int x = 0;
Timer timer = new Timer(100, this);
int y = 0, x1 = 5, y1 = 5;
public static void main(String[] ds) {
Ova ss = new Ova();
ss.nn();
}
private void nn() {
JFrame frame = new JFrame("fram");
frame.setSize(1000, 600);
JPanel as = new JPanel();
frame.add(as);
frame.add(new Ova());
frame.setVisible(true);
timer.start();
}
First, main creates an instance of Ova, then the method nn creates a new instance of Ova and then you start the timer...
Now the question you need to ask is, which Ovas timer did you start...the one on the screen or the one main created...
I can tell, it was the one that main created, which is not visible on the screen
(A possible) Solution
Start by never creating a JFrame inside a JPanel (or other component). The only time I would do something like that is via a static support method...
Remove the nn method and replace it with a begin (or something like that) method that starts the timer.
In the main method, create an instance of Ova, add it to an instance of JFrame and call Ova's begin method...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Ova extends JPanel implements ActionListener {
int x = 0;
Timer timer = new Timer(100, this);
int y = 0, x1 = 5, y1 = 5;
public static void main(String[] ds) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
Ova ova = new Ova();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(ova);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
ova.begin();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
private void begin() {
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, 50, 50);
}
#Override
public void actionPerformed(ActionEvent e) {
if (x < 0 || x > 950) {
x1 = -x1;
}
if (y < 0 || y > 530) {
y1 = -y1;
}
x = x + x1;
y = y + y1;
repaint();
}
}
Avoid calling setSize on anything, instead, override the getPreferredSize method of the component and return a preferred size and then use pack on the JFrame to wrap the frame around this. You will get far better and reliable results.
Related
This is just a simple red ball going up and down and i see it flickering. I already saw few subjects about that but did not find any answer that helped me.
Thank you :)
The Window class with the go method that makes the ball goes up and down.
The panel that also contains the ball positions and that just repaints.
Window.java
import java.awt.Dimension;
import javax.swing.JFrame;
public class Window extends JFrame
{
public static void main(String[] args)
{
new Window();
}
public Panel pan = new Panel();
public Window()
{
this.setSize(600, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setContentPane(pan);
this.setVisible(true);
go();
}
private void go()
{
int vecY = 1;
while (true)
{
if (pan.y <= 100)
{
vecY = 1;
}
else if (pan.y >= 400)
{
vecY = -1;
}
pan.y += vecY;
pan.repaint();
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
Panel.java
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Panel extends JPanel
{
public int x = 300;
public int y = 300;
public void paintComponent(Graphics g)
{
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.red);
g.fillOval(x, y, 50, 50);
}
}
There are a number of possible issues. The primary issue is likely to be a thread race condition between your while-loop and the paintComponent method.
Your while-loop is capable of change the state of the y position before the paintComponent has a chance to paint it's state. Painting is done at the leisure of the paint sub system, so calling repaint simply makes a request to the RepaintManager which decides what and when an actual paint cycle might take place, this means that you could be dropping frames.
For most animations in Swing, a Swing Timer is more the capable. It's safe to update the UI from within, as the ActionListener is called within the context of the EDT but won't block the EDT
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Window extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Window();
}
});
}
public Panel pan = new Panel();
public Window() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(pan);
pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
go();
}
private void go() {
Timer timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pan.updateAnmationState();
}
});
timer.start();
}
public class Panel extends JPanel {
private int x = 300;
private int y = 300;
private int vecY = 1;
public void updateAnmationState() {
if (y <= 100) {
vecY = 1;
} else if (y >= 400) {
vecY = -1;
}
y += vecY;
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.red);
g.fillOval(x, y, 50, 50);
}
}
}
This example worked fine for me on MiniMac
I have tried a ton of different things to try to get the JLabel to show but I don't understand why it is not working. I have tried resizing it, though that is not what i want to do, I have tried other classes, but I would prefer to stick with this one, and it is starting to get really frustrating. If you have any ideas please help. But please try to keep them simple and explain very clearly as I am still quite new to java. I have only been going for about three or four months. Here is my code:
package com.thefallenpaladin;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
/**
* Created by darkp_000 on 11/4/2015.
*/
#SuppressWarnings("serial")
public class Game extends JPanel implements KeyListener,MouseListener {
public boolean mainMenu = true;
public int winWidth = 700; //Window Stats
public int winHeight = 600;
public int buttonOneX = 60; // Button Stats
public int buttonOneY = 240;
public int buttonOneW = 100;
public int buttonOneH = 75;
public boolean buttonOne = false;
public int mouseX; // not set because it is set in mouseClicked
public int mouseY;
public static void main(String[] args) {
Game game = new Game();
JFrame window = new JFrame("I hate this");
JLabel onePlayer = new JLabel();
onePlayer.setLocation(0,0/*game.buttonOneX + game.buttonOneX/2,game.buttonOneY + game.buttonOneY/2*/);
window.add(game);
window.setFocusable(true);
window.setResizable(false);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setSize(700,600); //TODO
window.setVisible(true);
game.requestFocusInWindow();
game.add(onePlayer);
game.addKeyListener(game);
game.addMouseListener(game);
window.setLocationRelativeTo(null);
while(true) { // Main Game loop
onePlayer.setText("One Player");
game.repaint();
game.customUpdate();
}
}
public void customUpdate() {
if(mouseX > buttonOneX && mouseX < buttonOneX+buttonOneX && mouseY > buttonOneY && mouseY < buttonOneY+buttonOneY && mainMenu) {
buttonOne = true;
System.out.print("Starting Game");
}
}
public void paint(Graphics g) {
if(mainMenu) {
g.setColor(Color.CYAN); // Set main menu
g.fillRect(0,0,winWidth,winHeight);
g.setColor(Color.GREEN);
g.fillRect(buttonOneX,buttonOneY,buttonOneW,buttonOneH);
}
if(buttonOne) {
mainMenu = false;
g.setColor(Color.GREEN);
g.fillRect(0,0,winWidth,winHeight);
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
System.out.println(e);
}
public void keyReleased(KeyEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
// System.out.println(e);
mouseX = e.getX();
mouseY = e.getY();
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
Okay so you've made a couple of basic mistakes...
First, JLabel onePlayer = new JLabel(); creates an empty label, with no size (0x0) and since labels are transparent by default, you'd not see it
Next, you've overridden paint of a top level container (JFrame), but failed to honor the paint chain effectively preventing any of the child components from ever getting painted
public void paint(Graphics g) {
if (mainMenu) {
g.setColor(Color.CYAN); // Set main menu
g.fillRect(0, 0, winWidth, winHeight);
g.setColor(Color.GREEN);
g.fillRect(buttonOneX, buttonOneY, buttonOneW, buttonOneH);
}
if (buttonOne) {
mainMenu = false;
g.setColor(Color.GREEN);
g.fillRect(0, 0, winWidth, winHeight);
}
}
So, if I remove your paint method and change JLabel onePlayer = new JLabel(); to JLabel onePlayer = new JLabel("I'm a label"); I get this output...
Also...
while (true) { // Main Game loop
onePlayer.setText("One Player");
game.repaint();
game.customUpdate();
}
has the potential to try screw up your program, you have no guarantee's in what thread your main method is been called and you should not make assumptions.
Start by creating a custom component, extending from something like JPanel and override it's paintComponent method, place your custom painting there. In fact, you should have a panel for each state of your game (menu, running, settings, etc).
Add these to your frame (probably using a CardLayout to enable you to easily switch between them)
Use either a Thread or Swing Timer as a main game loop, one which you create explicitly.
Have a look at Painting in AWT and Swing, Performing Custom Painting, How to Use CardLayout and How to use Swing Timers for some more details
As a "conceptual" example...
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class AwesomeGame {
public static void main(String[] args) {
new AwesomeGame();
}
public AwesomeGame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ContentPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface NavigationController {
public void letsPlay();
}
public class ContentPane extends JPanel implements NavigationController {
private CardLayout cardLayout;
private GamePane gamePane;
public ContentPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
add(new MenuPane(this), "TheMenu");
add((gamePane = new GamePane()), "TheGame");
cardLayout.show(this, "TheMenu");
}
#Override
public void letsPlay() {
cardLayout.show(this, "TheGame");
gamePane.play();
}
}
public class MenuPane extends JPanel {
public MenuPane(NavigationController navigationController) {
JLabel label = new JLabel("My Super Dupa Awesome Game!");
label.setFont(label.getFont().deriveFont(Font.BOLD, 48));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
JButton play = new JButton("Play Now!");
play.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
navigationController.letsPlay();
}
});
add(play, gbc);
setBackground(Color.GREEN);
}
}
public class GamePane extends JPanel {
public GamePane() {
setBackground(Color.BLUE);
}
public void play() {
Timer timer = new Timer(500, new ActionListener() {
int count;
#Override
public void actionPerformed(ActionEvent e) {
count++;
if (count % 2 == 0) {
setForeground(Color.BLACK);
} else {
setForeground(Color.RED);
}
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
String text = "I bet you're blowen away by it's awesomness!";
FontMetrics fm = g2d.getFontMetrics();
int x = (getWidth() - fm.stringWidth(text)) / 2;
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(text, x, y);
g2d.dispose();
}
}
}
I try to write a code to draw a Oval run from the top left down to the bottom right. But when I run to program, it show the blank screen on app.
Why is this happening?
Here is my code:
import javax.swing.*;
import java.awt.*;
public class SimpleAnimation {
int x = 70;
int y = 70;
public static void main(String[] arg){
SimpleAnimation gui = new SimpleAnimation();
gui.go();
}
public void go(){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel drawPanel = new MyDrawPanel();
frame.getContentPane().add(drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
for (int i = 0; i < 130; i++){
x++;
y++;
drawPanel.repaint();
try{
Thread.sleep(50);
} catch(Exception ex){}
}
} // close go() method
class MyDrawPanel extends JPanel{
#Override
public void paintComponents(Graphics g) {
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);
}
} // close inner class
} // close outer class
You should Override paintComponent() instead of paintComponents().
So change the public void paintComponents() {...} to public void paintComponent() {...}
But just for the hint:
Try to use Timers instead of Threads. Always try not to mess with the swing thread. In your case you can use javax.swing.Timer to call the repaint in 50 ms intervals:
counter = 0;
t = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(counter>=130)
t.stop();
counter++;
x++;
y++;
drawPanel.repaint();
}
});
t.start();
javax.swing.Timer t and int counter are member variables for your class.
Good Luck.
You are not calling super.paintComponent(g); and also you need to call paintComponents rather than repaint method. Please try it with below code. I hope it helps :)
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SimpleAnimation {
int x = 70;
int y = 70;
public static void main(String[] arg) {
SimpleAnimation gui = new SimpleAnimation();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel drawPanel = new MyDrawPanel();
frame.getContentPane().add(drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
for (int i = 0; i < 130; i++) {
x++;
y++;
drawPanel.paintComponents(drawPanel.getGraphics());
try {
Thread.sleep(50);
} catch (Exception ex) {
}
}
} // close go() method
class MyDrawPanel extends JPanel {
#Override
public void paintComponents(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
g.drawOval(50, 50, 50, 50);
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);
}
} // close inner class
} // close outer class
I'm trying to get a rectangle in my JFrame to move when I press a given key on the keyboard, but I'm seemingly having a hard time doing that. Here's my code:
package TestPackage;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JComponent;
public class Mainframe extends JComponent implements KeyListener
{
private static final long serialVersionUID = 1L;
int x = 350;
int y = 250;
public static void main (String[] args)
{
JFrame frame = new JFrame ("Mainframe");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize (800, 600);
frame.setFocusable (true);
frame.getContentPane().setBackground (Color.WHITE);
frame.getContentPane().add (new Mainframe());
frame.addKeyListener (new Mainframe());
frame.setVisible (true);
}
public void paint (Graphics graphics)
{
graphics.setColor (Color.BLACK);
graphics.fillRect (x, y, 100, 100);
}
public void keyPressed (KeyEvent event)
{
if (event.getKeyCode() == KeyEvent.VK_A)
{
x++;
repaint();
}
else if (event.getKeyCode() == KeyEvent.VK_D)
{
y++;
repaint();
}
}
public void keyReleased (KeyEvent event) {}
public void keyTyped (KeyEvent event) {}
}
I'm sure it's a problem with my KeyListener, as everything else works perfectly. Does anybody know what I'm doing wrong? Thanks.
You're creating two instances of MainFrame, one you add to the frame and one you use as the JFrame's KeyListener, this means that any modifications the KeyListener instance makes to the x/y values, won't be seen by the instance on the UI
Don't use KeyListener, it has too many focus related issues, use the Key Bindings API which was designed to overcome these issues. See How to Use Key Bindings
Don't override paint (and especially if you're not going to call super.paint), instead, you should override the paintComponent method (and call super.paintComponent). See Painting in AWT and Swing and Performing Custom Painting for more details
Make sure you are creating and modifying the UI only from within the context of the Event Dispatching Thread, see Initial Threads for more details
For example...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Mainframe extends JComponent {
private static final long serialVersionUID = 1L;
int x = 350;
int y = 250;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Mainframe");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setFocusable(true);
frame.getContentPane().setBackground(Color.WHITE);
frame.getContentPane().add(new Mainframe());
frame.setVisible(true);
}
});
}
public Mainframe() {
bindKeyWith("y.up", KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), new VerticalAction(-1));
bindKeyWith("y.down", KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), new VerticalAction(1));
bindKeyWith("x.left", KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), new HorizontalAction(-1));
bindKeyWith("x.right", KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), new HorizontalAction(1));
}
protected void bindKeyWith(String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
g.setColor(Color.BLACK);
g.fillRect(x, y, 100, 100);
}
public abstract class MoveAction extends AbstractAction {
private int delta;
public MoveAction(int delta) {
this.delta = delta;
}
public int getDelta() {
return delta;
}
protected abstract void applyDelta();
#Override
public void actionPerformed(ActionEvent e) {
applyDelta();
}
}
public class VerticalAction extends MoveAction {
public VerticalAction(int delta) {
super(delta);
}
#Override
protected void applyDelta() {
int delta = getDelta();
y += delta;
if (y < 0) {
y = 0;
} else if (y + 100 > getHeight()) {
y = getHeight() - 100;
}
repaint();
}
}
public class HorizontalAction extends MoveAction {
public HorizontalAction(int delta) {
super(delta);
}
#Override
protected void applyDelta() {
int delta = getDelta();
x += delta;
if (x < 0) {
x = 0;
} else if (x + 100 > getWidth()) {
x = getWidth() - 100;
}
repaint();
}
}
}
make your main like this and it will work
public static void main (String[] args)
{
JFrame frame = new JFrame ("Mainframe");
JComponent test = new Mainframe();
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize (800, 600);
frame.setFocusable (true);
frame.getContentPane().setBackground (Color.WHITE);
frame.getContentPane().add (test);
frame.addKeyListener ((KeyListener) test);
frame.setVisible (true);
}
Is it possible to repaint a JPanel from within a loop in another object? I have a JFrame that consists of a JPanel (DrawPanel) and a SA object. I would like to update/repaint the JPanel during the while loop in this SA object. I started a new thread, but still panel.repaint() does not execute.
public class Mainform extends JFrame {
private DrawPanel DrawPanel;
public static void main(String[] args) {
DrawPanel panel = new DrawPanel();
SA sa = new SA(panel);
Thread t = new Thread(sa);
t.start();
//...
}
}
public class DrawPanel extends JPanel implements MouseMotionListener, MouseListener {
public DrawPanel() {
super();
setBackground(Color.WHITE);
addMouseWheelListener(this);
addMouseListener(this);
addMouseMotionListener(this);
}
//...
}
public class SA implements Runnable {
private DrawPanel panel;
public SA(DrawPanel p) {
this.panel = p;
init();
}
public void run() {
while (true) {
//...
panel.repaint();
}
}
}
EDIT: run is public
The basic answer is "yes".
This assumes that the component you are trying to repaint is
Added to a container
That container is attached to some kind of native peer (ie a window)
That window is visible.
The RepaintManager is generally smart enough to know not to waste time painting something that isn't displayable.
The following example is rather basic, but will increment a counter within the paintComponent of a JPanel each time it is called. The Runnable, which is attached to a Thread, will update every second...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RepaintTest {
public static void main(String[] args) {
new RepaintTest();
}
public RepaintTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane tp = new TestPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(tp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Thread thread = new Thread(new Repainter(tp));
thread.setDaemon(true);
thread.start();
}
});
}
public class Repainter implements Runnable {
private JPanel panel;
public Repainter(JPanel panel) {
this.panel = panel;
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
panel.repaint();
}
}
}
public class TestPane extends JPanel {
private int repaints = 0;
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics g2d = (Graphics2D) g.create();
repaints++;
FontMetrics fm = g2d.getFontMetrics();
String text = Integer.toString(repaints);
int x = (getWidth() - fm.stringWidth(text)) / 2;
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(text, x, y);
g2d.dispose();
}
}
}