andrew lopez
andrew lopez

Reputation: 3

Printing numbers using Jframe/textfields

How would one use the WindowBuilder in eclipse to print numbers from a for loop into a textfield, I have made the for loop for a counter to begin when clicked start (counts up to 60). I just am wondering how would you make it show up in a different textfield when i.e I click start. If that explanation wasn't so clear, in other words I am making a Stop-watch and when you click start it prints up to 60 in the eclipse console. I want those numbers to show up in the JTextfield in the window when I click start. Any help is appreciated :)

here is the page of code, I hope you guys (or girls) can help me :) (this is what I attempted to do.

package com.racecar484.user;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.SwingConstants;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JTable;

public class StopWatch extends ForLoopTesting {

    private JFrame frmStopWatchPro;
    private JTextField txtClickMeTo;
    private JButton Terminate;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    StopWatch window = new StopWatch();
                    window.frmStopWatchPro.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public StopWatch() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     * @param i 
     */



    private void initialize(String i) {
        frmStopWatchPro = new JFrame();
        frmStopWatchPro.getContentPane().setBackground(new Color(255, 127, 80));
        frmStopWatchPro.setTitle("Stop Watch Pro");
        frmStopWatchPro.setBounds(100, 100, 450, 300);
        frmStopWatchPro.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmStopWatchPro.getContentPane().setLayout(null);

        txtClickMeTo = new JTextField();
        for(int i1 = 0; i1 < 60; i1++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }

        txtClickMeTo.setText(i);
        txtClickMeTo.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent arg0) {

            System.out.println("Oh my god this worked!");

            }
        });
        txtClickMeTo.setEditable(false);
        txtClickMeTo.setBounds(19, 24, 300, 58);
        frmStopWatchPro.getContentPane().add(txtClickMeTo);
        txtClickMeTo.setColumns(10);

        JButton btnNewButton = new JButton("Start");
        btnNewButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("Stop-Watch activated.");
                for(int i = 0; i < 60; i++){
                    System.out.println(i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        });
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
            }
        });
        btnNewButton.setBounds(53, 121, 108, 40);
        frmStopWatchPro.getContentPane().add(btnNewButton);

        JButton btnStop = new JButton("Stop");
        btnStop.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
            String Meow = "hey";
                System.out.println("Stop-Watch stopped.");
            }
        });
        btnStop.setBounds(211, 121, 108, 40);
        frmStopWatchPro.getContentPane().add(btnStop);

        Terminate = new JButton("Terminate");
        Terminate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {

            frmStopWatchPro.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                System.out.println("Closing Application.");
            System.exit(0);
            }
        });
        Terminate.setBounds(329, 0, 105, 261);
        frmStopWatchPro.getContentPane().add(Terminate);

        JLabel lblonlyOneThat = new JLabel("(Only one that actually works without console ->)");
        lblonlyOneThat.setBounds(53, 211, 266, 39);
        frmStopWatchPro.getContentPane().add(lblonlyOneThat);

        JLabel lblStopWatchPro = new JLabel("Stop Watch Pro V.1- made by Andrew Lopez ");
        lblStopWatchPro.setBounds(53, 187, 257, 29);
        frmStopWatchPro.getContentPane().add(lblStopWatchPro);
    }
}

Upvotes: 0

Views: 1999

Answers (2)

Sweeper
Sweeper

Reputation: 271625

Your understanding of the Java swing framework is somewhat limited in my opinion. You have two major problems. And one of them you already described in your question. The other is that you don't know how to make timer.

At the moment you are using Thread.sleep(1000) to kind of "wait" for 1 second. But you put it in the initialize method. Why do you want to wait for 60 seconds when the window initializes? That makes no sense to me.

I see that you have another Thread.sleep(1000) in the on click listener for the start button. That makes sense, but you didn't set the txtClickMeTo's text.

It should be like this:

for(int i = 0; i < 60; i++){
    System.out.println(i);
    try {
        Thread.sleep(1000);
        txtClickMeTo.setText(Integer.toString(i));
     } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
}

You also need to mark txtClickMeTo as final if you do this.

final JTextField txtClickMeTo = new JTextField();

This way, the start button would be working perfectly.

But what about the stop button? why does it not work when I start the timer?

This is because Thread.sleep causes blocking. The method blocks the thread from continueing on so the user interactions can only be responded to after the 60 seconds.

As a result, Thread.sleep is not recommended for swing applications. What you use instead is javax.swing.Timer. It's very user-friendly. It provides a lot of convenient methods for you to use to implement your stop button.

Here is the documentation for that: https://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html

And here is a tutorial for that: https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html

EDIT:

I'll show you the code for using a swing timer to meet the requirement.

First you'll need to create one (of course!)

Timer t = new Timer(1000, new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // blah blah blah
    }
});

In this code, 1000 means that the timer will fire every 1000 milliseconds, or 1 second. And the second parameter is the action that needs to be performed when the timer fires, in this case, you should set the text of txtClickMeTo to some number.

Of course, you need to keep track of what the number should be, so make a variable to store that:

int secondsElapsed = 0;

And you basically just set the text of the JTextField to secondsElasped and increment it.

Upvotes: 1

MadProgrammer
MadProgrammer

Reputation: 347214

Swing is single threaded, meaning that if you do anything which blocks the Event Dispatching Thread, like running a loop, using Thread.sleep or some other long running process, the UI won't be updated (and no new events will be processed).

Swing is also not thread safe, this mean you should never update the UI from any thread other than the EDT

Start by having a look at Concurrency in Swing for more details.

The question is then, how can you fix it? You could use a Thread and SwingUtilities.invokeLater, but that's kind of messy. You could use a SwingWorker, but that's kind of heavy handed for the problem. The best solution would be to use a Swing Timer, which calls a registered callback (ActionListener) at regular intervals from within the EDT, making it safe to update the UI from within.

Have a look at How to use Swing Timers for some more details.

And for an example...

import java.awt.EventQueue;
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.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class StopWatch {

    public static void main(String[] args) {
        new StopWatch();
    }

    public StopWatch() {
        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 TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTextField field;
        private Timer timer;
        private int counter;

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            field = new JTextField(4);
            add(field, gbc);

            JButton btn = new JButton("Start");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (timer.isRunning()) {
                        timer.stop();
                        btn.setText("Start");
                    } else {
                        counter = 0;
                        timer.start();
                        field.setText(Integer.toString(counter));
                        btn.setText("Stop");
                    }
                }
            });
            add(btn, gbc);

            timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    counter++;
                    if (counter >= 60) {
                        timer.stop();
                        btn.setText("Start");
                    }
                    field.setText(Integer.toString(counter));
                }
            });

        }

    }

}

Cavet: This is a simple example. Swing Timer only guarantees that it will call the ActionListener AFTER the prescribed delay, this makes it slightly inaccurate (in the order of milliseconds). A more "appropriate" solution would be to use a comparison between the time the Timer was started and the time the ActionListener was notified

You may also want to have a look at How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listeners for more appropriate mechanism for working with buttons

Upvotes: 1

Related Questions