So I was trying to understand using a Gui in Java and did so by making a little guess the number game. It compiles correctly, however when I run the program it just shows the frame with "Congratulations you win!" at the top. My main question is why the dialog boxes aren't popping up at all and what I should do to fix that. On a related note, when I had the code as JOptionPane.showInputDialog(this,"Play again? Y/N") I got the error message "non-static variable this cannot be referenced from a static context." My secondary, and much less important question, is how to make the message be in the center of the box vertically as well as horizontally.
import javax.swing.*;
import java.awt.*;
import java.util.Scanner;
public class RandomNumberGame{
public static JLabel higherThan;
public static JPanel tooHigh;
public static JLabel lowerThan;
public static JPanel tooLow;
public static JPanel exactlyCorrect;
public static JLabel correctAnswer;
public static JFrame guiFrame;
public static void main(String[] args){
RandomFun();
}
public static void RandomFun()
{
Scanner input=new Scanner(System.in);
guiFrame = new JFrame();
guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
guiFrame.setTitle("Fun Games!");
guiFrame.setSize(500,500);
guiFrame.setLocationRelativeTo(null);
guiFrame.setVisible(true);
final JPanel tooHigh = new JPanel();
higherThan = new JLabel("Too High!");
final JPanel tooLow = new JPanel();
lowerThan = new JLabel("Too Low!");
final JPanel exactlyCorrect = new JPanel();
correctAnswer = new JLabel("Congratulations, you won!");
tooHigh.add(higherThan);
tooLow.add(lowerThan);
exactlyCorrect.add(correctAnswer);
guiFrame.add(tooHigh, BorderLayout.CENTER);
guiFrame.add(tooLow, BorderLayout.CENTER);
guiFrame.add(exactlyCorrect, BorderLayout.CENTER);
}
public static void GuessNumber(){
String again;
String lastGuess = "0";
boolean moreGame=true;
int lastGuessInt = Integer.parseInt(lastGuess.toString());
int winner = (int) (Math.random()*999+1);
while(moreGame){
lastGuess = JOptionPane.showInputDialog("Guess a Number");
if(winner < lastGuessInt){
tooHigh.setVisible(true);
tooLow.setVisible(false);
exactlyCorrect.setVisible(false);
}
else if(winner > lastGuessInt){
tooHigh.setVisible(false);
tooLow.setVisible(true);
exactlyCorrect.setVisible(false);
}
else{
tooHigh.setVisible(false);
tooLow.setVisible(false);
exactlyCorrect.setVisible(true);
moreGame=false;
}
}
again = JOptionPane.showInputDialog("Play again? Y/N");
switch(again){
case "y": case "Y":
GuessNumber();
break;
case "n": case "N":
System.exit(0);
break;
}
}
}
Why the "mis-behavior":
Your main method calls RandomFun()
And RandomFun() then creates a JFrame and displays.
It adds 3 JPanels all in the BorderLayout.CENTER position!
Thus only the last JPanel will show because it will cover all the previously added JPanels as per BorderLayout's documented behavior.
Thus your code is behaving exactly as you'd expect it to.
Other issues include a gross over-use of the static modifier, calling setVisible(true) on the JFrame before adding all components, setting the size of the JFrame, creating a method, GuessNumber() that is never called by viable running code, code not adhering to Java naming conventinons (methods and fields should begin with a lower-case letter, classes with an upper-case letter),...
If I were in your shoes, I'd put the GUI coding to the side as I'd first want to concentrate on learning Java basics, including avoiding all static methods and fields and instead creating true OOPs-compliant classes, since this understanding is critical prior to delving into GUI coding. Just a few weeks of study should be enough to get you strong enough to then try some Swing coding.
My attempt to create a guessing game program:
import java.awt.BorderLayout;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
import javax.swing.text.JTextComponent;
#SuppressWarnings("serial")
public class RandomNumberGame2 extends JPanel {
private static final int LOW = 0;
private static final int HIGH = 100;
public static final String START_GAME = "Please guess the random number between "
+ LOW + " and " + HIGH;
public static final String TO_HIGH = "Your guess is too high. Please try again";
public static final String TO_LOW = "Your guess is too low. Please try again";
public static final String CONGRATS_YOU_WIN = "Congratulations, you win!!!";
private Random random = new Random();
private int randomNumber; // holds the randomly selected number
private JTextField inputField = new JTextField(5); // where user enters guess
private JButton submitButton = new JButton(new SubmitAction("Submit", KeyEvent.VK_S));
private JButton resetButton = new JButton(new ResetAction("Reset", KeyEvent.VK_R));
private JLabel statusLabel = new JLabel(START_GAME, SwingConstants.CENTER);
public RandomNumberGame2() {
// so field will select all when gains focus
inputField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
JTextComponent textComp = (JTextComponent) e.getSource();
textComp.selectAll();
}
});
// so input field will submit number if enter is pressed
inputField.addActionListener(submitButton.getAction());
JPanel centerPanel = new JPanel(); // uses flow layout by default
centerPanel.add(new JLabel("Enter number here:"));
centerPanel.add(inputField);
centerPanel.add(submitButton);
centerPanel.add(resetButton);
setLayout(new BorderLayout());
add(statusLabel, BorderLayout.PAGE_START);
add(centerPanel, BorderLayout.CENTER);
resetGame();
}
public void resetGame() {
randomNumber = random.nextInt(HIGH - LOW) + LOW;
inputField.setText("");
statusLabel.setText(START_GAME);
inputField.requestFocusInWindow();
inputField.selectAll();
}
private class SubmitAction extends AbstractAction {
public SubmitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
try {
int input = Integer.parseInt(inputField.getText().trim());
if (input > randomNumber) {
statusLabel.setText(TO_HIGH);
} else if (input < randomNumber) {
statusLabel.setText(TO_LOW);
} else {
statusLabel.setText(CONGRATS_YOU_WIN);
}
inputField.requestFocusInWindow();
inputField.selectAll();
} catch (NumberFormatException e1) {
JOptionPane.showMessageDialog(RandomNumberGame2.this,
"Please enter only integer data", "Non-numeric Data Error",
JOptionPane.ERROR_MESSAGE);
inputField.setText("");
}
}
}
private class ResetAction extends AbstractAction {
public ResetAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
resetGame();
}
}
private static void createAndShowGui() {
RandomNumberGame2 mainPanel = new RandomNumberGame2();
JFrame frame = new JFrame("Fun Games 2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
Is there a way or method in which we can add placeholder in j text field. I want to add placeholder "Enter Your Number" in field but how can I do this. I check all methods but didn't working.
Code:
public class Loop extends JFrame{
private JTextField t1;
public L(){
getContentPane().setLayout(null);
t1=new JTextField();
t1.setBounds(27,50,47,28);
getContentPane().add(t1);
setSize(400,400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
}
Main:
public class Main {
public static void main(String[] args) {
L object = new L();
}
}
Check out Text Prompt for a flexible solution.
You can control when prompt is displayed (always, focus gained or focus lost). You can also customize the style of the text.
Here is an example of which you can you inspire
package TinyOS;
import java.awt.*;
import javax.swing.*;
import javax.swing.text.Document;
#SuppressWarnings("serial")
public class PlaceholderTextField extends JTextField {
public static void main(final String[] args) {
final PlaceholderTextField tf = new PlaceholderTextField ("");
tf.setColumns(20);
tf.setPlaceholder("Here is a placeHolder!");
final Font f = tf.getFont();
tf.setFont(new Font(f.getName(), f.getStyle(), 30));
JOptionPane.showMessageDialog(null, tf);
}
private String placeholder;
public PlaceholderTextField () {
}
public PlaceholderTextField (
final Document pDoc,
final String pText,
final int pColumns)
{
super(pDoc, pText, pColumns);
}
public PlaceholderTextField (final int pColumns) {
super(pColumns);
}
}
I hope that can help you
This code should work, it listen on first click and removes the text
public class Loop extends JFrame{
private JTextField t1;
private boolean clicked = false;
public L(){
getContentPane().setLayout(null);
t1=new JTextField();
t1.setText("Enter Your Number");
t1.addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent e){
if(!clicked){
clicked=true;
t1.setText("");
}
}
}
t1.setBounds(27,50,47,28);
getContentPane().add(t1);
setSize(400,400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
}
Maybe better solution exists
Note - not tested
EDIT (how the boolean clicked works)
when you call method mousePressed(MouseEvent) at the first time, the clicked variable is false, by declaration:
private boolean clicked = false;
So the if body is executed (because !clicked = !false = true)
in the if body, the clicked variable is set to true, so if condition will be then false: (because !clicked = !true = false)
This solves the problem of running code just once.
Here is my code
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Login
{
static BufferedReader dataIn = new BufferedReader(new InputStreamReader(System.in));
static String a, b, c;
static int d, z, f, g, h, i, k;
public static void Login()
{
JFrame frame = new JFrame("Login");
JButton button1 = new JButton("Login");
JLabel label1 = new JLabel("Username: ");
JLabel label2 = new JLabel("Pin: ");
JTextField txt1 = new JTextField(8);
JPasswordField pass1 = new JPasswordField(8);
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JPanel FormPanel = new JPanel();
txt1.setBackground(Color.white);
pass1.setBackground(Color.white);
panel1.add(label1);
panel1.add(txt1);
panel2.add(label2);
panel2.add(pass1);
FormPanel.setLayout(new GridLayout(3,8));
FormPanel.add(panel1);
FormPanel.add(panel2);
FormPanel.add(button1);
pass1.getDocument().addDocumentListener(new DocumentListener()
{
public void changedUpdate(DocumentEvent e)
{
changed();
}
public void removeUpdate(DocumentEvent e)
{
changed();
}
public void insertUpdate(DocumentEvent e)
{
changed();
}
public void changed()
{
if (pass1.getText().equals(""))
{
button1.setEnabled(false);
}
else
{
button1.setEnabled(true);
}
}
});
txt1.getDocument().addDocumentListener(new DocumentListener()
{
public void changedUpdate(DocumentEvent e)
{
changed();
}
public void removeUpdate(DocumentEvent e)
{
changed();
}
public void insertUpdate(DocumentEvent e)
{
changed();
}
public void changed()
{
if (txt1.getText().equals(""))
{
button1.setEnabled(false);
}
else
{
button1.setEnabled(true);
}
}
});
button1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
frame.hide();
Body a = new Body();
a.Body();
}
});
button1.setActionCommand("Open");
frame.setContentPane(FormPanel);
frame.setSize(8,9);
frame.pack();
frame.show();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
}
}
and my Body.java is
try
{
do
{
System.out.print("Working time (hours): ");
a=dataIn.readLine();
e=Integer.parseInt(a);
k=e;
if(k<8)
{
System.out.print("\nYou have worked undertime");
g=e * 30;
h=g * 500;
i=h-200;
System.out.print("\nYour payment (per month) is: " +i);
}
if(k>8)
{
System.out.print("\nYou have worked overtime");
g=e*30;
h=g*500;
i=h+200;
System.out.print("\nYour payment (per month) is: " +i);
}
if(k==8)
{
System.out.print("\nYou have worked ontime");
g=e*30;
h=g*500;
System.out.print("\nYour payment (per month) is: " +h);
}
System.out.print("\n\nPress 0 to logout: ");
c=dataIn.readLine();
d=Integer.parseInt(c);
}while(d!=0);
}
catch(Exception j)
{
System.out.print("\nYou probably need to work for more than an hour to start earning");
}
of course I have import java.io.*; and BufferedReader dataIn = new BufferedReader(<arguments>); but when ever I call the body.java that opens in terminal it won't ask for user inputs, but when I try to execute the body.java it asks for user inputs...
I need help right now...
You ask:
okay.. then please tell me how can I do some simple calculations in full GUI?
Again you'll want to avoid trying to mix GUI with console programs since they interact with the user in two very dissimilar ways, and the console can lock up the GUI if you're not careful. Instead consider going all console or all GUI.
If you go all GUI, one possible solution is to create a GUI that is similar to what you're already doing with user name and PIN number:
Give your GUI JTextFields for the user to input his data.
Add a "Calculate" JButton
In the button's ActionListener, extract the data from the JTextFields, convert any Strings to numbers that need converting, calculate your value and display it in another JTextField or JLabel.
Other side recommendations:
Don't call deprecated methods since they're deprecated for a good reason. Instead the Java API will usually tell you what alternatives to use.
Avoid over-use of static variables and methods, since this leads to rigid code that is difficult to test or enhance.
Try to give your variables names that have meaning so that your code becomes "self-commenting".
Your log-in window should be a modal dialog of some type, such as a modal JDialog, not a JFrame, since
Closing it will not close the entire GUI
It will prevent interacting with the main GUI until it has been fully dealt with.
I am using a gui with JTextFields to collect some information and then a JButton that takes that infomration and writes it to a file, sets the gui visibility to false, and then uses Runnable to create an instance of another JFrame from a different class to display a slideshow.
I would like to access some of the information for the JTextFields from the new JFrame slideshow. I have tried creating an object of the previous class with accessor methods, but the values keep coming back null (I know that I have done this correctly).
I'm worried that when the accessor methods go to check what the variables equal the JTextFields appear null to the new JFrame.
Below is the sscce that shows this problem.
package accessmain;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class AccessMain extends JFrame implements ActionListener
{
private static final int FRAMEWIDTH = 800;
private static final int FRAMEHEIGHT = 300;
private JPanel mainPanel;
private PrintWriter outputStream = null;
private JTextField subjectNumberText;
private String subjectNumberString;
public static void main(String[] args)
{
AccessMain gui = new AccessMain();
gui.setVisible(true);
}
public AccessMain()
{
super("Self Paced Slideshow");
setSize(FRAMEWIDTH, FRAMEHEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
//Begin Main Content Panel
mainPanel = new JPanel();
mainPanel.setBorder(new EmptyBorder(0,10,0,10));
mainPanel.setLayout(new GridLayout(7, 2));
mainPanel.setBackground(Color.WHITE);
add(mainPanel, BorderLayout.CENTER);
mainPanel.add(new JLabel("Subject Number: "));
subjectNumberText = new JTextField(30);
mainPanel.add(subjectNumberText);
mainPanel.add(new JLabel(""));
JButton launch = new JButton("Begin Slideshow");
launch.addActionListener(this);
mainPanel.add(launch);
//End Main Content Panel
}
#Override
public void actionPerformed(ActionEvent e)
{
String actionCommand = e.getActionCommand();
if(actionCommand.equals("Begin Slideshow"))
{
subjectNumberString = subjectNumberText.getText();
if(!(subjectNumberString.equals("")))
{
System.out.println(getSubjectNumber());
this.setVisible(false);
writeFile();
outputStream.println("Subject Number:\t" + subjectNumberString);
outputStream.close();
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
AccessClass testClass = new AccessClass();
testClass.setVisible(true);
}
});
}
else
{
//Add warning dialogue here later
}
}
}
private void writeFile()
{
try
{
outputStream = new PrintWriter(new FileOutputStream(subjectNumberString + ".txt", false));
}
catch(FileNotFoundException e)
{
System.out.println("Cannot find file " + subjectNumberString + ".txt or it could not be opened.");
System.exit(0);
}
}
public String getSubjectNumber()
{
return subjectNumberString;
}
}
And then creating a barebones class to show the loss of data:
package accessmain;
import javax.swing.*;
import java.awt.*;
public class AccessClass extends JFrame
{
AccessMain experiment = new AccessMain();
String subjectNumber = experiment.getSubjectNumber();
public AccessClass()
{
System.out.println(subjectNumber);
}
}
Hardcoding the accessor method with "test" like this:
public String getSubjectNumber()
{
return "test";
}
Running this method as below in the new JFrame:
SelfPaceMain experiment = new SelfPaceMain();
private String subjectNumber = experiment.getSubjectNumber();
System.out.println(subjectNumber);
Does cause the system to print "test". So the accessor methods seem to be working. However, trying to access the values from the JTextFields doesn't seem to work.
I would read the information from the file I create, but without being able to pass the subjectNumber (which is used as the name of the file), I can't tell the new class what file to open.
Is there a good way to pass data from JTextFields to other classes?
pass the argument 'AccessMain' or 'JTextField' to the second class:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
AccessClass testClass = new AccessClass(AccessMain.this); //fixed this
testClass.setVisible(true);
}
});
Then reading the value of 'subjectNumber'(JTextField value) from the 'AccessMain' or 'JTextField' in the second class:
public class AccessClass extends JFrame
{
final AccessMain experiment;
public AccessClass(AccessMain experiment)
{
this.experiment = experiment;
}
public String getSubjectNumber(){
return experiment.getSubjectNumber();
}
}
Also, you should try Observer pattern.
A simple demo of Observalbe and Observer
Observable and Observer Objects
I am creating a simple console application in which I can use keyboard arrow keys as an input like a typical remote of a toy. When I press arrow up the console will print the output text "UP" or if I press arrow down it will print "down".
I want to press the arrow key only once, i.e. I am not needed to press enter afterwards to accept my input. I want the input to be accepted automatically on pressing the arrow key.
I already tried some code but this is still not happening and I still need to press enter to accept my input. If you have any idea how I can achieve this as simple as possible, I would really appreciate it.
This sample code will helps you to get the Left Arrow Key Event. You can refer this,
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Test2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 50;
private Timer leftKeyTimer = new Timer(TIMER_DELAY , new TimerListener());
public Test2() {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition );
ActionMap actionMap = getActionMap();
String leftDownKey = "Left Down";
String leftUpKey = "Left Up";
KeyStroke leftDown = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , 0, false);
KeyStroke leftUp = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT , 0, true);
inputMap.put(leftDown, leftDownKey);
inputMap.put(leftUp, leftUpKey);
actionMap.put(leftDownKey, new LeftKeyAction(false));
actionMap.put(leftUpKey, new LeftKeyAction(true));
leftKeyTimer.setActionCommand("Left Key");
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class LeftKeyAction extends AbstractAction {
private boolean onKeyRelease;
public LeftKeyAction(boolean onKeyRelease) {
this.onKeyRelease = onKeyRelease;
}
#Override
public void actionPerformed(ActionEvent e) {
if (onKeyRelease) {
if (leftKeyTimer != null && leftKeyTimer.isRunning()) {
leftKeyTimer.stop();
}
} else {
if (leftKeyTimer != null && !leftKeyTimer.isRunning()) {
leftKeyTimer.start();
}
}
}
}
private class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent actEvt) {
System.out.println(actEvt.getActionCommand());
}
}
private static void createAndShowGui() {
Test2 mainPanel = new Test2();
JFrame frame = new JFrame("Test2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
This is actually a surprisingly complicated problem.
If you want a true console app (no GUI elements) you have to sacrifice portability.
Most consoles are line buffered by default, so Java won't get any input until enter is pressed. Most can be switched to a character mode, but there is no OS independent way to do this. For more information see http://www.darkcoding.net/software/non-blocking-console-io-is-not-possible/
I've got a "status" JLabel in one class (named Welcome) and the timer in another one (named Timer). Right now, the first one displays the word "status" and the second one should be doing the countdown. The way I would like it to be, but don't know how to - display 10, 9, 8, 7 ... 0 (and go to the next window then). My attempts so far:
// class Welcome
setLayout(new BorderLayout());
JPanel area = new JPanel();
JLabel status = new JLabel("status");
area.setBackground(Color.darkGray);
Font font2 = new Font("SansSerif", Font.BOLD, 25);
status.setFont(font2);
status.setForeground(Color.green);
area.add(status, BorderLayout.EAST); // can I put it in the bottom-right corner?
this.add(area);
and the timer:
public class Timer implements Runnable {
// public void runThread() {
// new Thread(this).start();
// }
public void setText(final String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setText(text); // link to status here I guess
}
});
}
public void run() {
for (int i = 10; i > 0; i--) {
// set the label
final String text = "(" + i + ") seconds left";
setText(text);
// // sleep for 1 second
// try {
// Thread.currentThread();
// Thread.sleep(1000);
// } catch (Exception ex) {
// }
}
// go to the next window
UsedBefore window2 = new UsedBefore();
window2.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// runThread();
}
} // end class
I agree that you should consider using a "Java" Timer as per Anh Pham, but in actuality, there are several Timer classes available, and for your purposes a Swing Timer not a java.util.Timer as suggested by Anh would suit your purposes best.
As for your problem, it's really nothing more than a simple problem of references. Give the class with the label a public method, say setCountDownLabelText(String text), and then call that method from the class that holds the timer. You'll need to have a reference of the GUI class with the timer JLabel in the other class.
For example:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Welcome extends JPanel {
private static final String INTRO = "intro";
private static final String USED_BEFORE = "used before";
private CardLayout cardLayout = new CardLayout();
private JLabel countDownLabel = new JLabel("", SwingConstants.CENTER);
public Welcome() {
JPanel introSouthPanel = new JPanel();
introSouthPanel.add(new JLabel("Status:"));
introSouthPanel.add(countDownLabel);
JPanel introPanel = new JPanel();
introPanel.setPreferredSize(new Dimension(400, 300));
introPanel.setLayout(new BorderLayout());
introPanel.add(new JLabel("WELCOME", SwingConstants.CENTER), BorderLayout.CENTER);
introPanel.add(introSouthPanel, BorderLayout.SOUTH);
JPanel usedBeforePanel = new JPanel(new BorderLayout());
usedBeforePanel.setBackground(Color.pink);
usedBeforePanel.add(new JLabel("Used Before", SwingConstants.CENTER));
setLayout(cardLayout);
add(introPanel, INTRO);
add(usedBeforePanel, USED_BEFORE);
new HurdlerTimer(this).start();
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Welcome");
frame.getContentPane().add(new Welcome());
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();
}
});
}
public void setCountDownLabelText(String text) {
countDownLabel.setText(text);
}
public void showNextPanel() {
cardLayout.next(this);
}
}
class HurdlerTimer {
private static final int TIMER_PERIOD = 1000;
protected static final int MAX_COUNT = 10;
private Welcome welcome; // holds a reference to the Welcome class
private int count;
public HurdlerTimer(Welcome welcome) {
this.welcome = welcome; // initializes the reference to the Welcome class.
String text = "(" + (MAX_COUNT - count) + ") seconds left";
welcome.setCountDownLabelText(text);
}
public void start() {
new Timer(TIMER_PERIOD, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (count < MAX_COUNT) {
count++;
String text = "(" + (MAX_COUNT - count) + ") seconds left";
welcome.setCountDownLabelText(text); // uses the reference to Welcome
} else {
((Timer) e.getSource()).stop();
welcome.showNextPanel();
}
}
}).start();
}
}
Since you're using Swing you should use the javax.swing.Timer, not the java.util.Timer. You can set the timer to fire at 1 second (1000 ms) intervals and have your listener do the updating. Since Swing updates must take place in the event dispatch thread your listener is the perfect place for status.setText.
there's already a Timer class in java: http://www.exampledepot.com/egs/java.util/ScheduleRepeat.html
Why not put the setText method in the welcome class and just do 'status.setText(text)'?
And you might try BorderLayout.SOUTH or .PAGE END or .LINE END to get the timer in the lower right corner