Timer Flickers When It Reaches 0 - java

importing libraries
public class Countdown1 extends Applet implements Runnable {
// getting user input
String input = JOptionPane.showInputDialog("Enter seconds: ");
// converting string to integer
int counter = Integer.parseInt(input);
Thread countdown;
public void start() {
countdown = new Thread(this);
countdown.start();
}
// executed by thread
public void run() {
Timer timer;
timer = new Timer(1000, new ActionListener() /* counting down time inputted */ {
public void actionPerformed(ActionEvent evt) {
if (counter > 0) {
counter--;
// repainting each second
repaint();
}
}
});
// timer started
timer.start();
}
public void paint(Graphics g) {
//painting text and time
g.setFont(new Font("Times New Roman", Font.BOLD, 35));
g.drawString("Seconds: " + String.valueOf(counter), 260, 210);
setBackground(Color.orange);
setForeground(Color.magenta);
// change background to cyan when timer reaches 0
if (counter == 0) {
setBackground(Color.cyan);
}
}
}

The problem isn't your Timer (although I do question the need to start it within a separate thread), the problem is with overriding paint.
Top level containers like Applet are not double buffered, meaning that the each paint action tends to be sent to the underlying Graphics device desperately.
Now you can over come this by employee some double buffering process OR you could...
Extend from JApplet instead
Create a custom component extending from something like JPanel and override it's paintComponent method instead, moving your custom painting to this method
Add this component to the applet instead.
It should solve the immediate issue...
You should also avoid calling setForeground or setBackground from within any paint method. In fact, you should avoid calling any method that might call repaint from within any paint method...
Take a look at Performing Custom Painting
I'm pretty sure that String input = JOptionPane.showInputDialog("Enter seconds: "); this is a bad idea. Instead, you should provide some kind of control or option within the UI to change this value...
Crude example
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Countdown1 extends JApplet {
#Override
public void init() {
add(new CounterPane());
}
public class CounterPane extends JPanel {
String input = JOptionPane.showInputDialog("Enter seconds: ");
int counter = Integer.parseInt(input);
public CounterPane() {
Timer timer;
timer = new Timer(1000, new ActionListener() /* counting down time inputted */ {
public void actionPerformed(ActionEvent evt) {
System.out.println(counter);
if (counter > 0) {
counter--;
setBackground(Color.orange);
setForeground(Color.magenta);
if (counter <= 0) {
setBackground(Color.cyan);
}
repaint();
}
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(new Font("Times New Roman", Font.BOLD, 35));
g.setColor(getForeground());
g.drawString("Seconds: " + String.valueOf(counter), 260, 210);
}
}
}

Related

Why using an if statement inside a paintComponent(Graphics g) method invalidates all code inside the method?

I'm trying to create a JFrame object which contains a JPanel object. Inside the JPanel object there are 3 JButtons that when clicked, are intended to change the background color of the JPanel.
I also want to draw an image which size equals the one of the JPanel object to give the impression of a background image but as you may imagine I want it to be drown only the first time, when the user hasn't clicked any buttons yet. Once a button is clicked I intend to call the repaint() method inherited from the Component class which in my understanding should make a call to the paintComponent(Graphics g).
Given the fact I want the image to be drawn only when the user hasn't clicked any buttons, inside the paintComponent(Graphics g) I'm trying to use an if statement so when the paintComponent(Graphics g) method is called the second time by the repaint() method, it will execute inside an else statement and simply call the super.paintComponent(Graphics g) method that in my understanding, should paint it without the image. The problem is that as soon as I put the if statement inside the paintComponent method it seems to invalidate the entire code inside the method.
Any suggestions or explanation on why is this happening would be appreciated.
The code is below:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class PruebaEventosSelf {
public static void main(String[] args) {
// TODO Auto-generated method stub
MarcoBotonSelf marco=new MarcoBotonSelf();
marco.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MarcoBotonSelf extends JFrame{
public MarcoBotonSelf() {
setExtendedState(MarcoBotonSelf.MAXIMIZED_BOTH);
setTitle("National Aeronautics and Space Administration NASA");
Image image=Toolkit.getDefaultToolkit().getImage("C:\\Users\\wagne\\OneDrive\\Desktop\\Nasa.png");
setIconImage(image);
LaminaBoton lamina=new LaminaBoton();
add(lamina);
setVisible(true);
}
}
class LaminaBoton extends JPanel implements ActionListener {
JButton botonAzul=new JButton("Blue");
JButton botonNegro=new JButton("Black");
JButton botonGris=new JButton("Gris");
boolean repaint=false;
public LaminaBoton() {
botonAzul.addActionListener(this);
add(botonAzul, Container.CENTER_ALIGNMENT);
botonNegro.addActionListener(this);
add(botonNegro, Container.LEFT_ALIGNMENT);
botonGris.addActionListener(this);
add(botonGris, Container.CENTER_ALIGNMENT);
}
public void paintComponent(Graphics g) {
if(repaint) {
super.paintComponent(g);
}else {
Image imagen=Toolkit.getDefaultToolkit().getImage("C:\\Users\\wagne\\OneDrive\\Desktop\\NASA.jpg");
g.drawImage(imagen, 0, 0, this);
}
}
public void actionPerformed(ActionEvent e) {
Object pulsado=e.getSource();
if (pulsado==botonAzul){
repaint=true;
repaint();
this.setBackground(Color.blue);
System.out.println("Blue is working!");
}else if(pulsado==botonNegro) {
System.out.println("Black is working!");
setBackground(Color.BLACK);
}else {
System.out.println("Gray is working!");
setBackground(Color.DARK_GRAY);
}
}
}
HERE'S ANOTHER WAY I TRIED:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class PruebaEventosSelf {
public static void main(String[] args) {
// TODO Auto-generated method stub
MarcoBotonSelf marco=new MarcoBotonSelf();
marco.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MarcoBotonSelf extends JFrame{
public MarcoBotonSelf() {
setExtendedState(MarcoBotonSelf.MAXIMIZED_BOTH);
setTitle("National Aeronautics and Space Administration NASA");
Image image=Toolkit.getDefaultToolkit().getImage("C:\\Users\\wagne\\OneDrive\\Desktop\\Nasa.png");
setIconImage(image);
LaminaBoton lamina=new LaminaBoton();
add(lamina);
setVisible(true);
}
}
class LaminaBoton extends JPanel implements ActionListener {
JButton botonAzul=new JButton("Blue");
JButton botonNegro=new JButton("Black");
JButton botonGris=new JButton("Gris");
boolean repaint=false;
public LaminaBoton() {
botonAzul.addActionListener(this);
add(botonAzul, Container.CENTER_ALIGNMENT);
botonNegro.addActionListener(this);
add(botonNegro, Container.LEFT_ALIGNMENT);
botonGris.addActionListener(this);
add(botonGris, Container.CENTER_ALIGNMENT);
}
public void paintComponent(Graphics g) {
Image imagen=Toolkit.getDefaultToolkit().getImage("C:\\Users\\wagne\\OneDrive\\Desktop\\NASA.jpg");
g.drawImage(imagen, 0, 0, this);
if (repaint) super.paintComponent(g);
}
public void actionPerformed(ActionEvent e) {
Object pulsado=e.getSource();
if (pulsado==botonAzul){
repaint=true;
repaint();
this.setBackground(Color.blue);
System.out.println("Blue is working!");
}else if(pulsado==botonNegro) {
System.out.println("Black is working!");
setBackground(Color.BLACK);
}else {
System.out.println("Gray is working!");
setBackground(Color.DARK_GRAY);
}
}
}
I've tried another 4 different ways but they all seem to lead to the same result of the image not being drown not even if the use hasn't clicked any buttons.
Your paintComponent() method should ALWAYS call super.paintCompnent(g); as the first statement in the method. Then it should draw the image only if the repaint variable is false.
It would be better - and more logically readable - to call that variable paintImage and set it initially to true, then the button listener sets it to false, and the paintComponent() method draws the image only if paintImage is true.

My game is flickering due to my painting directly in JFrame. How do I use JPanel? [duplicate]

I think I need to put some code where the comment is (or maybe use non static method but I am not sure). The main method creates the window and then starts the graphics method. I would like the blue square to flash.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class paintTest extends JPanel{
private static JFrame theWindow = new JFrame("Window");
static boolean blueSqr = false;
public void paint(Graphics g) {
g.setColor(Color.RED);
g.fillRect(10, 10, 10, 10);
if(blueSqr){
g.setColor(Color.BLUE);
g.fillRect(10, 10, 10, 10);
}
}
public static void main(String[] args){
createWindow();
theWindow.getContentPane().add(new paintTest());
while(true){
blueSqr = false;
System.out.println("off");
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
blueSqr = true;
// Needs something here
System.out.println("on");
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
}
}
public static void createWindow(){
theWindow.setSize(500, 500);
theWindow.setLocationRelativeTo(null);
theWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theWindow.setVisible(true);
}
}
Any help would be really good.
Use a Swing Timer to call repaint(). Also, override paintComponent() in a JPanel, rather than paint().
Something like this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PaintTest extends JPanel{
boolean blueSqr = false;
PaintTest() {
setPreferredSize(new Dimension(100,25));
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
blueSqr = !blueSqr;
repaint();
}
};
Timer timer = new Timer(1000,al);
timer.start();
}
public void paintComponent(Graphics g) {
Color c = (blueSqr ? Color.BLUE : Color.RED);
g.setColor(c);
g.fillRect(10, 10, 10, 10);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame theWindow = new JFrame("Window");
theWindow.getContentPane().add(new PaintTest());
createWindow(theWindow);
}
});
}
public static void createWindow(JFrame theWindow){
theWindow.pack();
theWindow.setLocationByPlatform(true);
theWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theWindow.setVisible(true);
}
}
There were other improvements I could not be bothered documenting (code speaks louder than words). If you have any questions (check the docs first, then) ask.
your issues are
1) by calling Thread.sleep(int) in the Swing related code, never do that, for delaying in Swing (there are lots of topics about why not use sleep in programing languages ...) use Swing Timer
2) your JPanel doesn't returns any XxxSize
3) for Swing use paintComponent(), only if you have got really important reasons then use method paint() more about repaint and animating Graphics in the 2D Graphics tutorial
4) Swing GUI should be built in the Event Dispatch Thread

Why isn't my animation visible?

So this is my code:
import javax.swing.*;
import java.awt.event.*;
public class Frame {
Draw d = new Draw();
JFrame f1 = new JFrame("Animation 2");
JButton bMoveRight = new JButton(">>>>");
JButton bMoveLeft = new JButton("<<<<");
public Frame() {
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f1.setSize(800, 600);
f1.setVisible(true);
f1.setResizable(false);
f1.setLocationRelativeTo(null);
bMoveRight.setBounds(50, 450, 120, 50);
bMoveLeft.setBounds(600, 450, 120, 50);
f1.add(bMoveRight);
f1.add(bMoveLeft);
f1.add(d);
bMoveRight.addActionListener(new ButtonMoveRight());
bMoveLeft.addActionListener(new ButtonMoveLeft());
}
private class ButtonMoveRight implements ActionListener {
public void actionPerformed(ActionEvent e){
d.animateRight();
}
}
private class ButtonMoveLeft implements ActionListener {
public void actionPerformed(ActionEvent e){
d.animateLeft();
}
}
}
import javax.swing.*;
import java.awt.*;
public class Draw extends JComponent{
int x = 50;
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(x, 150, 200, 100);
}
public void animateLeft(){
try{
while(x != 50){
x--;
repaint();
Thread.sleep(10);
}
} catch(Exception ex){
ex.printStackTrace();
}
}
public void animateRight(){
try{
while(x != 550){
x++;
repaint();
Thread.sleep(10);
}
} catch(Exception ex){
ex.printStackTrace();
}
}
}
Everything works as it should. Except one thing. My animation happens but the problem is it doesn't show. I made another program where there is only animation and it starts right away,but in this one I made buttons to start the animations. What happens is I click the button and nothing happens for 5 seconds (that's the time it needs to get to the other side) and after 5 seconds it appears on the other side of the window. Why won't my animation show?
The Thread.sleep() inside your "ActionListener" callbacks is strongly discouraged. The issue is the following: your code is invoked in the same thread which is main thread for GUI application - it is used to draw your interface.
What you need to do instead of sleep() invocation - you can fire some events with delay and process right way. You have to use something like timer - probably this one https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html

Grapghic doesn't move

I'm trying to make a code that will move a red ball with JButtons (and later add keybinders). There are no problems when I compile and when I run I see the ball but the JButtons won't affect him. I think the problem might be that the ball is drawed only once and then is called again and again without being drawed in the new position but I don't know how to fix that.
1) does anybody know how I can fix that?
2) is there a way to change the shape of a JPanel to a ball? (that would probably be a simpler way to move him)
package il.co.atlantis;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class KeyBinders implements ActionListener {
boolean right=true, left=false, up=false, down=false, inGame=true;
JPanel backgroundPanel, bannerPanel, scorePanel, applePanel;
JLabel currentScoreLabel, highestScoreLabel;
JButton upButton, downButton, rightButton, leftButton;
long millis =System.currentTimeMillis(), millisn =System.currentTimeMillis();
public static final int WID = 10, HEI = 10;
public static int x1 = 100, y1 = 100;
public class MyGraphics extends JComponent {
private static final long serialVersionUID = 1L;
MyGraphics() {
setPreferredSize(new Dimension(700, 500));
}
public void moveRight(){
++x1;
}
public void moveLeft(){
--x1;
}
public void moveUp(){
--y1;
}
public void moveDown(){
++y1;
}
public void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.red);
g.fillOval(x1, y1, WID, HEI);
}
}
public JPanel CreateContentPane (){
JPanel totalGUI = new JPanel();
totalGUI.setLayout(null);
backgroundPanel = new JPanel();
backgroundPanel.setBackground(Color.black);
backgroundPanel.setLocation(100, 10);
backgroundPanel.setSize(700, 500);
totalGUI.add(backgroundPanel);
upButton = new JButton("up");
upButton.setLocation(0,0);
upButton.setSize(50,50);
totalGUI.add(upButton);
downButton = new JButton ("down");
downButton.setLocation(0,50);
downButton.setSize(50,50);
totalGUI.add(downButton);
rightButton = new JButton("right");
rightButton.setLocation(0,100);
rightButton.setSize(50,50);
totalGUI.add(rightButton);
leftButton = new JButton("left");
leftButton.setLocation(0,150);
leftButton.setSize(50,50);
totalGUI.add(leftButton);
MyGraphics tr = new MyGraphics();
tr.setLocation(100, 100);
backgroundPanel.add(tr);
return totalGUI;
}
public void ActionPerformed(ActionEvent h){
if(h.getSource() == upButton) {
--y1;
}
else if(h.getSource() == downButton){
++y1;
}
else if(h.getSource() == leftButton){
--x1;
}
else if(h.getSource() == rightButton){
++x1;
}
}
private static void createAndShowGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("[=] JButton Scores! [=]");
//Create and set up the content pane.
KeyBinders demo = new KeyBinders();
frame.setContentPane(demo.CreateContentPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(280, 190);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public KeyBinders() {
// TODO Auto-generated constructor stub
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
When you invoke action event, actionPerformed() function gets called, as you did. You have change the drawing position too. you need to call Component.repaint() which tells Swing t hat the entire component, whichever one you specified to be repainted , must be updated . So add this function calling in your code. For example:
public void ActionPerformed(ActionEvent h){
if(h.getSource() == upButton) {
--y1;
}
else if(h.getSource() == downButton){
++y1;
}
else if(h.getSource() == leftButton){
--x1;
}
else if(h.getSource() == rightButton){
++x1;
}
repaint();
}
Check the tutorial: Performing Custom Painting.
There's a method called repaint() you should familiarize yourself with.
When called on a component (such as a JFrame) it'll repaint all the components within. Naturally you need to call it if you want your changes to become visible on the screen.
As for custom painting, you shouldn't use a Component at all, rather use the Graphics.fillRect/fillOval etc. methods to just draw what you want.
See here for the custom painting tutorial.

Java function that gets called every frame

I was wondering if there was a function like void draw() which Processing programming language uses that gets called every frame. Or even just a function that loops infinitely when it gets called but only runs through it every time there is a new frame. I heard of something called a runnable in java how do i go about using this? also is there a better way then having a runnable with a delay like a function that is hardcoded to run every frame. Oh and also what is the function call that will allow me to see how much time (in milliseconds preferably) since the application has started running that way i can make my runnables / frame calls much more precise so that the game runs about the same speed on every computer regardless of the frame rate.
Perhaps you need something like this
import java.awt.Graphics;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Repainter extends JPanel {
private Point topLeft;
private int increamentX = 5;
public Repainter() {
topLeft = new Point(100, 100);
}
public void move() {
topLeft.x += increamentX;
if (topLeft.x >= 200 || topLeft.x <= 100) {
increamentX = -increamentX;
}
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(topLeft.x, topLeft.y, 100, 100);
}
public void startAnimation() {
SwingWorker<Object, Object> sw = new SwingWorker<Object, Object>() {
#Override
protected Object doInBackground() throws Exception {
while (true) {
move();
Thread.sleep(100);
}
}
};
sw.execute();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Repaint Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
Repainter repainter = new Repainter();
frame.add(repainter);
repainter.startAnimation();
frame.setVisible(true);
}
});
}
}

Categories

Resources