david bautista
david bautista

Reputation: 11

How can i create a timer that counts up using swing

I want to create a timer that counts up. Due to my game using swing components I want to use swing components for this task as well.

I also want the Timer to be repainted onto a JLabel. It should stop the timer when the player collides with the finish JLabel

when I try to print out the timer on a JLabel I get this issue: javax.swing.Timer@42cc41de

This class is the gamepane class.It is where all the components of the game are created. The walls are created here. The collisions is a for loop using an index. the walls are in an array. This is a cut down version of my game which only contains 6 walls. I usually have 49. I also cut down on some unnecessary classes such as one that is used for files and another that has my second maze in it.

import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.time.Duration;
import java.time.Instant;

/**
 * demonstrates basic animation using a timer, an action listener, and a key
 * listener demonstrates basic collisions between rectangular objects
 * 
 * @author 602052004
 */

public class GamePane extends JPanel implements ActionListener, KeyListener {// *change
                                                                                // GamePane
                                                                                // to
                                                                                // GamePane
    // This is were the game screen is made and the player is created.

    static final long serialVersionUID = 1L;

    private Duration timeOutDuration = Duration.ofSeconds(5);
    private Instant startTime; // Set this when you're ready to start the timer


    JLabel player = new JLabel();
    JLabel finish = new JLabel();
    JLabel instructions = new JLabel(
            "The controls for this game will be using the WASD keys. W is going up, A is going to the left, S is going down and, D is going right.");
    JFrame gameFrame;
    int playerSpeed = 4;
    int FPS = 40;

    // This array holds my Jlabels for the walls.I used it so that i can have a
    // for loop with an index for the labels.
    JLabel[] walls = new JLabel[6];//this is cut down from 49-6
    {

        walls[0] = new JLabel();
        walls[1] = new JLabel();
        walls[2] = new JLabel();
        walls[3] = new JLabel();
        walls[4] = new JLabel();
        walls[5] = new JLabel();

    }
    private final Set<Integer> keys = new HashSet<>();

    // The keys set holds the keys being pressed

    public static void main(String[] args) {
        // Open the GUI window
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                // Create a new object and
                // run its go() method
                new GamePane().go();
            }
        });
    }

    GamePane() {
        // Run the parent class constructor
        super();
        // Allow the panel to get focus
        setFocusable(true);
        // Don't let keys change the focus

    }

    protected void go() {
        setLayout(new CardLayout());
        // Setup the window
        gameFrame = new JFrame();
        // Add this panel to the window
        gameFrame.setLayout(new CardLayout());
        gameFrame.add(this, "main");
        gameFrame.setContentPane(this);

        // Set's the window properties
        gameFrame.setTitle("main");
        gameFrame.setSize(800, 600);
        gameFrame.setLocationRelativeTo(null);
        gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        gameFrame.setVisible(true);
        gameFrame.add(new ButtonPane(gameFrame), "buttons");
        // Creates the new JPanel that will hold the game.
        JPanel gamestage = new JPanel();
        gamestage.setBackground(Color.darkGray);
        gameFrame.add(gamestage, "game");
        gamestage.setLayout(null);
        // *Move the setup of the player and the timer under the walls
        // Get a sample of collisions going so that i can do it over the weekend
        // Setup the movable box
        player.setBounds(25, 25, 20, 20);
        player.setVisible(true);
        player.setBackground(Color.red);
        // Opaque makes the background visible
        player.setOpaque(true);

        // Setup the key listener
        addKeyListener(this);
        // Null layout allows moving objects!!!
        gamestage.add(player);
        // Set the timer
        Timer tm = new Timer(1000 / FPS, this);
        tm.start();
        Timer gameTimer = new Timer(1000 / 30, this);
        gameTimer.start();
        System.out.println(gameTimer);
        walls[0].setBounds(10, 15, 10, 480);// left height
        walls[0].setVisible(true);
        walls[0].setBackground(Color.white);
        walls[0].setOpaque(true);
        gamestage.add(walls[0]);

        walls[1].setBounds(10, 10, 490, 10);// top width
        walls[1].setVisible(true);
        walls[1].setBackground(Color.white);
        walls[1].setOpaque(true);
        gamestage.add(walls[1]);

        walls[39].setBounds(490, 10, 10, 480);// Right width
        walls[39].setVisible(true);
        walls[39].setBackground(Color.white);
        walls[39].setOpaque(true);
        gamestage.add(walls[39]);

        // wall3.setBounds(x, y, width, height);
        walls[2].setBounds(10, 100, 100, 10);
        walls[2].setVisible(true);
        walls[2].setBackground(Color.white);
        walls[2].setOpaque(true);
        gamestage.add(walls[2]);

        walls[3].setBounds(100, 60, 10, 40);
        walls[3].setVisible(true);
        walls[3].setBackground(Color.white);
        walls[3].setOpaque(true);
        gamestage.add(walls[3]);

        walls[4].setBounds(70, 60, 35, 10);
        walls[4].setVisible(true);
        walls[4].setBackground(Color.white);
        walls[4].setOpaque(true);
        gamestage.add(walls[4]);


        finish.setBounds(30, 455, 20, 20); // *make the game change to the main
                                            // screen when finished
                                            // Add a timer
        finish.setVisible(true);
        finish.setBackground(Color.LIGHT_GRAY);
        finish.setOpaque(true);
        gamestage.add(finish);

        instructions.setVisible(true);
        instructions.setOpaque(true);
        instructions.setBounds(510, 10, 265, 525);
        instructions.setBackground(Color.GRAY);
        instructions.setForeground(Color.white);
        gamestage.add(instructions);

    }

    /**
     * Check if two JLabel objects are touching &
     * 
     * @param a
     *            The first JLabel
     * @param b
     *            The second JLabel
     * @return true if the JLabels are touching
     */
    public boolean areColliding(JLabel a, JLabel b) {
        return a.getBounds().intersects(b.getBounds());
    }

    /**
     * this method makes the player move. It takes the players speed and subtracts
     * or adds the player speed to the current position of the player. It also
     * figures out were the player is at currently as well. This method also
     * contains a for loop which is used to see if the player is colliding with the
     * walls
     * 
     * @param arg0
     */
    @Override
    public void actionPerformed(ActionEvent arg0) {
        // Move up if W is pressed
        if (keys.contains(KeyEvent.VK_W)) {
            player.setLocation(player.getX(), player.getY() - playerSpeed);
        }
        // Move right if D is pressed
        if (keys.contains(KeyEvent.VK_D)) {
            player.setLocation(player.getX() + playerSpeed, player.getY());
        }
        // Move down if S is pressed
        if (keys.contains(KeyEvent.VK_S)) {
            player.setLocation(player.getX(), player.getY() + playerSpeed);
        }
        // Move left if A is pressed
        if (keys.contains(KeyEvent.VK_A)) {
            player.setLocation(player.getX() - playerSpeed, player.getY());
        }

        for (int i = 0; i < walls.length; i++) {
            if (areColliding(walls[i], player)) { // Reposition the target
                int newX = (int) (25);// This is the new location of the player in the X axis once it hits a wall
                int newY = (int) (25);// this is the new location of the player in the Y axis once it hits a wall
                player.setLocation(newX, newY);// Sets the location of the player once the new X and Y location is set

            }
        }

        if (areColliding(finish, player)) {// to change the pane when you fimish the game
            // Reposition the target
            int newX = 25;
            int newY = 25;
            player.setLocation(newX, newY);
            CardLayout layout = (CardLayout) gameFrame.getContentPane().getLayout();
            layout.show(gameFrame.getContentPane(), "buttons");
        }

        if (startTime != null) {
            Duration runningTime = Duration.between(startTime, Instant.now());
            Duration timeRemainig = timeOutDuration.minus(runningTime);
            if (timeRemainig.isNegative() || timeRemainig.isZero()) {
                // Time has run out...
                 startTime = null; // stop the timer
                 System.out.println("finish");
            } else {
                // Update the UI
                repaint();
            }
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        // Add the key to the list
        // of pressed keys
        if (!keys.contains(e.getKeyCode())) {
            keys.add(e.getKeyCode());
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // Remove the key from the
        // list of pressed keys
        keys.remove((Integer) e.getKeyCode());
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }


}

This is the button pane which contains the Button and the action listener. It also changes the screens for me.

/**
 * This pane contains the button and sets up the button pane
 */
import java.awt.CardLayout;
import java.awt.Color;
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.JPanel;

public class ButtonPane extends JPanel {

    private JButton startBTN;// Calls the JButton
    JFrame game;

    public ButtonPane(JFrame g) {
        game = g;
        setLayout(new GridBagLayout());
        setBackground(Color.gray);// Sets the menu stages color blue
        startBTN = new JButton("Start");// Creates a new button
        add(startBTN);// Adds the button on the startStage



        startBTN.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (game.getContentPane().getLayout() instanceof CardLayout) {
                    CardLayout layout = (CardLayout) getParent().getLayout();
                    layout.show(game.getContentPane(), "game");

                }
            }
        });
    }

}

Upvotes: 0

Views: 319

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

when I try to print out the timer on a JLabel I get this issue: javax.swing.Timer@42cc41de

Timer doesn't carry any "time" information, it is simply responsible for scheduling the call back at regular intervals on the Event Dispatching Thread.

In order to print either the running or remaining time, you need to format the Duration according to your needs.

So, in this block, you need to actually update the label with some information, calling repaint will simply paint the state as it is.

if (startTime != null) {
    Duration runningTime = Duration.between(startTime, Instant.now());
    Duration timeRemainig = timeOutDuration.minus(runningTime);
    if (timeRemainig.isNegative() || timeRemainig.isZero()) {
        // Time has run out...
         startTime = null; // stop the timer
         System.out.println("finish");
    } else {
        // Update the UI
        //repaint();
        // Format the duration and update the label...
    }
}

As described in How could I add a refreshing timer to a JLabel using swing components, you can generate a String of the Duration by using something like...

long hours = timeRemainig.toHours();
long mins = timeRemainig.minusHours(hours).toMinutes();

// Or if you're lucky enough to be using Java 9+
//String formatted = String.format("%dhrs %02dmins", duration.toHours(), duration.toMinutesPart());
String formatted = String.format("%dhrs %02dmins", hours, mins);

Then you set the text of the label accordingly

// Sorry can't identify your count down label...
countDownLabel.setText(formatted);

Also, you really, really, really, only need a single Timer

Upvotes: 2

Related Questions