0

everyone. I have 4 classes; FrameViewerOne is where I run the application, FrameBuilderOne contains most of the code, including binary search and many other things, Person class implements comparable and I override it with compareTo() method, and my TimerLockout class is where I switch to with a window that is supposed to populate, lock the user out for 15 seconds, and show the countdown as the timer ticks. This is supposed to occur after 3 incorrect attempts from the user. When the timer reaches 0 seconds, I want it to close the TimerLockout class and reopen(setVisible) the original frame. Unfortunately, my code compiles but I can't get the timer to populate. Thank you for your time and any help/suggestions would be greatly appreciated!

Here are the instructions: 1) Use of a "counter" to allow the user 3 failed attempts. 2) If the user fails three times to input the correct information, then the system will lockout for 15 seconds. 2.1) You should show a countdown window by seconds only, not the entire system time.

//FRAMEVIEWERONE CLASS
import javax.swing.JFrame;//The Frame class is part of the javax.swing package.Swing is the nickname for the gui onterface library in java.
import java.io.*;
public class FrameViewerOne
{
   public static void main(String[] args)throws IOException{//This is a warning to the compiler that we are throwing an exception! Proper syntax is to have this AFTER the method header.
   {
      JFrame Frame1 = new FrameBuilderOne();
      Frame1.setVisible(true);
      Frame1.setSize(200,300);
      Frame1.setTitle("Lab One GUI");
      Frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//This adds the x button on the top right. If you omit this step, the program will keep running even after you close the frame.
   }
  }
}

//FRAMEBUILDERONE CLASS
import javax.swing.*;//The asterik(*) tells Java to import everything that is being used in the package.
import java.awt.event.*;//Has the ActionEvent and KeyEvent. awt: Abstract Window Toolkit
import java.awt.event.ActionListener;
import java.util.*;//This does not have an asterik because I am only importing a specific tool (Scanner) from the java package,util. Scanner is the namespace of the package
import java.io.*; //Always use IOException when working with files. FileNotFoundException is a specific IO Exception. Exceptions are objects.
import javax.swing.BoxLayout;
import javax.swing.JPasswordField;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;

public class FrameBuilderOne extends JFrame{
  private JButton loginBtn, exitBtn;
  private JPanel newPanel, userNamePanel, passWordPanel, studentIdPanel, buttonPanel;
  private JTextField usernameTextField;
  private JPasswordField passwordTextField;
  private JTextField studentIdTextField;
  private JLabel usernameLabel, passwordLabel, studentIdLabel;
  ArrayList<Person> personAry;
  private int attempts;

  public FrameBuilderOne()//Constructor
  {
    createPanel();//Method Call
    personAry = checkInfo(new File("USERDATA.txt"));
    Collections.sort(personAry);
  } 

  private void createPanel()//Actual Method being called
  {
    newPanel = new JPanel();//The reserve word, new, denotes that a constructor method is being called
    newPanel.setBorder(new EtchedBorder());
    newPanel.setBorder(new TitledBorder(new EtchedBorder()));
    newPanel.setLayout(new BoxLayout(newPanel, BoxLayout.Y_AXIS));

    userNamePanel = new JPanel();
    usernameLabel = new JLabel("Username:");
    userNamePanel.add(usernameLabel);

    usernameTextField = new JTextField(10);
    userNamePanel.add(usernameTextField);

    newPanel.add(userNamePanel);

    passWordPanel = new JPanel();
    passwordLabel = new JLabel("Password:");
    passWordPanel.add(passwordLabel);

    passwordTextField = new JPasswordField(10);
    passWordPanel.add(passwordTextField);

    newPanel.add(passWordPanel);
    passwordTextField.setEchoChar('*');

    studentIdPanel = new JPanel();
    studentIdLabel = new JLabel("Student ID:");
    studentIdPanel.add(studentIdLabel);
    studentIdTextField = new JTextField(10);
    studentIdPanel.add(studentIdTextField);

    newPanel.add(studentIdPanel);

    buttonPanel = new JPanel();
    loginBtn = new JButton("Login");
    buttonPanel.add(loginBtn);

    exitBtn = new JButton("Exit");
    buttonPanel.add(exitBtn);

    newPanel.add(buttonPanel);

    ActionListener LoginListener = new ButtonsListen();//Create One Method since since both login and exit buttons share the same/similar task. 
    loginBtn.addActionListener(LoginListener);
    exitBtn.addActionListener(LoginListener);

    add(newPanel);
  }

  public ArrayList<Person> checkInfo(File data)
  {
    Scanner userInput;
    ArrayList <Person> loginAry = new ArrayList<Person>();
    try
      {
        userInput = new Scanner(data);//The reason why this isn't System.in is because you aren't taking input from the keyboard. You are scanning the file.
        while (userInput.hasNextLine())
        {
          String finder = userInput.nextLine();
          String [] loginInfo = finder.split(",");//This is a delimeter
          String usernameInfo = loginInfo [0];
          String passwordInfo = loginInfo [1];
          long studentIdInfo = Long.parseLong(loginInfo[2]);

          Person moreInfo = new Person(usernameInfo, passwordInfo, studentIdInfo);
          loginAry.add(moreInfo);
        }
        userInput.close();
    }
    catch (FileNotFoundException e){
    JOptionPane.showMessageDialog(null, "Error" + e.getMessage());
    }
    return loginAry;
  }

  public class Verify
  {
    /** 
     * This method implements the binary search within the personAry which contains the user's attributes.
     * @param Person info - this is the information of the object Person which contains the username, password, and studentID.
     * @return - this method returns true if info within Person is found. This returns it to the other method which displays the appropriate message to the user. 
    */
    public boolean validate(Person info)
    {
      int low = 0;
      int high = personAry.size()-1;
      int mid;
      while(low <= high)
      {
        mid = (low + high) / 2;
        Person middlePerson = personAry.get(mid);
        int position = middlePerson.compareTo(info);
        if(position < 0)
        {
           low = mid + 1; 
        }
        else if(position > 0)
        {
          high = mid - 1;
        }
        else
        {
          return true;
        }
    }
    return false;
  }
 }

  public boolean validatePassword(String passwordSaver)//Check the password minimum, case sensitivity, and number in password 
  {
    int caseCount=0;
    int numCount=0;
    if(passwordSaver.length() < 10)
    {
      JOptionPane.showMessageDialog(null, "Password must have ten characters");
    }
    else if(passwordSaver.length() >= 10)
      for(int i = 0; i < passwordSaver.length(); i++)
      {
        char current = passwordSaver.charAt(i);
        if(Character.isUpperCase(current)) {caseCount++;}
        else if(Character.isDigit(current)){numCount++;}
      }
    if(caseCount == 0)
    {
      JOptionPane.showMessageDialog(null, "Password must have at least one uppercase character");
      return false;
    }
    else if (numCount == 0)
    {
      JOptionPane.showMessageDialog(null, "Password must have at least one uppercase character");
      return false;
    }
    else
    {
      return true;
    }
  }
public void createTimerClass()
{
  this.setVisible(false); 
  TimerLockout Frame2 = new TimerLockout(this);
}

public class ButtonsListen implements ActionListener{
  public void actionPerformed(ActionEvent e){

    if(e.getSource()==loginBtn)
    {
      String username = usernameTextField.getText();
      String id_str = studentIdTextField.getText();
      long number = Long.parseLong(id_str);
      String password;

      char[] passArray = passwordTextField.getPassword();
      password = new String(passArray);//Study this, write it out

      Person txtFieldInfo = new Person(username, password, number);

      Verify verifyLogin = new Verify();

      if (!validatePassword(password))//also tells the user what went wrong
      { 
        attempts++;
        if(attempts == 3)
        {
          createTimerClass();
          attempts = 0;
        }
      }

      if (verifyLogin.validate(txtFieldInfo))
       {
         JOptionPane.showMessageDialog(null, "Login Successful");//JOptionPane is in the swing package. You must include null, before the message you want to display.
       } 

      else
       {
         JOptionPane.showMessageDialog(null,"Invalid Login Information");
       }
    }

    if (e.getSource()==exitBtn)
    {
      JOptionPane.showMessageDialog(null, "Program Shutting Down");
      System.exit(0);
    }
  }
 }
} 

//PERSON CLASS
public class Person implements Comparable <Object>//The Comparable interface automatiically populates an empty CompareTo method behind the scenes. 
{
  private String username;
  private String password;
  private Long StudentID;

  public Person(String User, String Pass, Long ID)
  {
    this.username = User;
    this.password = Pass;
    this.StudentID = ID;
  }
  public int compareTo(Object otherPerson)//Within the CompareTo method, you must pass in an object. This is overriding the empty CompareTo Method.
  {
    Person other = (Person) otherPerson;//You need to cast an object. tempStorage is going to store the username, password, and studentID. 

    if(other.StudentID > this.StudentID)
    {
      return 1;
    }
    else if(other.StudentID < this.StudentID)
    {
      return -1;
    }
    else
    {
      return 0;
    }
  }

  public String getPassword ()
  {
    return this.password;
  }

  public String getUsername()
  {
    return this.username;
  }

  public Long getStudentID()
  {
    return this.StudentID;
  }
}

//TimerLockout Class
import javax.swing.Timer;
import javax.swing.*;
import java.awt.event.*;
import java.awt.event.ActionListener;
public class TimerLockout extends JFrame
{
  private Timer timerLock;
  private final int STARTING_TIME = 15;
  private int currentTime = 15;
  private final int ENDING_TIME = 0;
  private FrameBuilderOne Frame1;
  private JPanel secondPanel;
  private JLabel timerMessage;

  public TimerLockout(FrameBuilderOne previousFrame)
  {
    TimeListener listener = new TimeListener();
    timerLock = new Timer(1000, listener);
    Frame1 = previousFrame;
    createSecondPanel();
  }

  private void createSecondPanel()
  {
    JPanel secondPanel = new JPanel();

    timerMessage = new JLabel("You Are Temporarily Locked Out");
    secondPanel.add(timerMessage);

    ActionListener TimeListener = new TimeListener();
  }

  public class TimeListener implements ActionListener
  {
    public void actionPerformed(ActionEvent t)
    {

      while(currentTime >= STARTING_TIME)
      {
        currentTime--;
      }
      if(ENDING_TIME == 0)
      {
        Frame1.setVisible(true);
        dispose();
      }
    }
  }
}`
  • Your while loop in your `TimerListener` is a bad idea and will cause your UI to become responvie – MadProgrammer Mar 21 '16 at 05:53
  • I don't understand how and why it would be a bad idea, could you please explain? I implemented the while loop because I want to decrement the time (15 seconds) by 1 second until it reaches 0 in which it would display the gui for the user to try again. What's should I do to make my code more efficient? I've changed the if statement to –  Mar 21 '16 at 07:00
  • if(currentTime == ENDING_TIME) {...} –  Mar 21 '16 at 07:01
  • The `while` loop execute within in the context of the EDT, while it's running no other events will be processed until the `actionListener` is exited. – MadProgrammer Mar 21 '16 at 07:03
  • I don't understand why the timer window isn't showing after 3 failed login attempts. Do I have to use a Message Dialog? –  Mar 21 '16 at 07:10

2 Answers2

2

I think that the problem is that you never start the timer. And also that secondPanel is not shown anywhere. You instantiate it but you don't add it to any frame.

 public TimerLockout(FrameBuilderOne previousFrame) {
      TimeListener listener = new TimeListener();
      timerLock = new Timer(1000, listener);
      Frame1 = previousFrame;
      createSecondPanel();

      timerLock.start();  // <- START TIMER
 }

 private void createSecondPanel() {
      JPanel secondPanel = new JPanel();

      timerMessage = new JLabel("You Are Temporarily Locked Out");
      secondPanel.add(timerMessage);

      // ActionListener TimeListener = new TimeListener(); ONLY NEED ONE LISTENER
      // we have lost secondPanel. It does not show anywhere
 }
RubioRic
  • 2,442
  • 4
  • 28
  • 35
2

Unfortunately, my code compiles but I can't get the timer to populate

You never actually start the Timer...

public class TimerLockout extends JFrame {
    //...
    public TimerLockout() {
        TimeListener listener = new TimeListener();
        timerLock = new Timer(1000, listener);
        createSecondPanel();
        // This would be helpful
        timerLock.start();
    }

I don't understand why the timer window isn't showing after 3 failed login attempts.

You never make the frame visible...

public void createTimerClass() {
    this.setVisible(false);
    TimerLockout Frame2 = new TimerLockout();
    // ??
}

Maybe something like...

TimerLockout Frame2 = new TimerLockout();
Frame2.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
Frame2.pack();
Frame2.setLocationRelativeTo(null);
Frame2.setVisible(true);

But my TimerLock frame is empty/is really, really small (prediction)

This is because you never actually add secondPanel to TimerLockout

public TimerLockout() {
    TimeListener listener = new TimeListener();
    timerLock = new Timer(1000, listener);
    createSecondPanel();
    add(secondPanel);
    timerLock.start();
}

When TimerLockout throws a NullPointerException?! (prediction)

This is because you're shadowing the secondPanel in the createSecondPanel so the instance field is null when you add it to the frame...

private void createSecondPanel() {
    // Well, there's your problem?!
    //JPanel secondPanel = new JPanel();
    secondPanel = new JPanel();

    timerMessage = new JLabel("You Are Temporarily Locked Out");
    secondPanel.add(timerMessage);
}

My TimerLockout window closes after 1 second?! (prediction)

This is because the logic in your TimeListener is wrong

public class TimeListener implements ActionListener {

    public void actionPerformed(ActionEvent t) {

        System.out.println(">> currentTime = " + currentTime + "; STARTING_TIME = " + STARTING_TIME);
        while (currentTime >= STARTING_TIME) {
            currentTime--;
        }
        System.out.println("<< currentTime = " + currentTime + "; STARTING_TIME = " + STARTING_TIME);
        if (ENDING_TIME == 0) {
            dispose();
        }
    }
}

Let's do some benchmarking

+--------+---------------+-------------+-------------+
| loop   | STARTING_TIME | currentTime | ENDING_TIME |
+--------+---------------+-------------+-------------+
| <init> | 15            | 15          | 0           |
+--------+---------------+-------------+-------------+
| 1      | 15            | 15          | 0           |
+--------+---------------+-------------+-------------+
| 2      | 15            | 14          | 0           |
+--------+---------------+-------------+-------------+
| 3      | 15            | 14          | 0           |
+--------+---------------+-------------+-------------+

Wait, what? Why is currentTime longer updating? Because once currentTime is no longer >= STARTING_TIME, it is never decrement ... besides, the first time the Timer calls the ActionListener, you'll dispose the frame (without stopping the Timer) because ENDING_TIME is always 0

Instead, it should more like...

public class TimeListener implements ActionListener {

    public void actionPerformed(ActionEvent t) {
        currentTime--;
        if (currentTime <= ENDING_TIME) {
            dispose();
            timer.stop();
        }
    }
}

A simpler solution would be to simply use a modal JDialog instead of JFrame for the TimerLockOut class, this will mean you no longer need to juggle the visibility state of the main window, as the dialog will prevent you from interacting with the child windows until it's disposed

Another option is to use the JLayer/JXLayer API and generate a "locked" effect, for example and example or you could set up a glassPane which consumes the mouse events, for example

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thank you so much. I wish I had a mentor like you. For Frame2.pack();--what does that do? Also, what does setLocationRelativeTo(null); do? Why is the parameter null? Is it similar to when you use JOptionPaneShowMessageDialog(null, parameter)? –  Mar 21 '16 at 08:16
  • [`pack`](https://docs.oracle.com/javase/8/docs/api/java/awt/Window.html#pack--) *"Causes this Window to be sized to fit the preferred size and layouts of its subcomponents. The resulting width and height of the window are automatically enlarged if either of dimensions is less than the minimum size as specified by the previous call to the setMinimumSize method."* – MadProgrammer Mar 21 '16 at 08:19
  • `setLocationRelativeTo(null);` is a trick, in that, when `null`, the API uses the screen device and will, based on the current size of the window, center it in the screen – MadProgrammer Mar 21 '16 at 08:20
  • `JOptionPane.showMessageDialog(null...` is kind of the same thing, it provides context for the API to position the window, but also to know which window it should be blocking – MadProgrammer Mar 21 '16 at 08:30
  • That's a very nice trick. I'd rather use the pack method over the setSize method. I'm trying to display the timer in a Message Dialog and have it display the timer ticking, starting from 15 seconds, and ending at 0 seconds. –  Mar 21 '16 at 08:45
  • Generally, the updated ActionListener I suggested should be capable of setting the text of a JLabel using the currentTime, just beware that Timer only guarantees "at least" timing (so it's not exact), but we're talking milliseconds so I doubt it'd be a massive issue – MadProgrammer Mar 21 '16 at 09:32
  • public class TimeListener implements ActionListener { public void actionPerformed(ActionEvent t) { currentTime--; remainingTime = currentTime; JOptionPane.showMessageDialog(null, "Time Remaining: " + remainingTime); if(currentTime <= ENDING_TIME) { dispose(); timerLock.stop(); –  Mar 21 '16 at 09:51
  • I created a global variable (private int remainingTime) and then am setting remainingTime = currentTime; Unfortunately, I keep getting a separate dialog as currentTime is decremented. I want to have it where it is one dialog box and is counting down the seconds in real time in one box. I have no idea how to do this and can not locate how to do so –  Mar 21 '16 at 09:54
  • Well, assuming you still have `TimerLockout` window, it should have both `JLabel`s (the message and the remaining time), I'd just use the `currentTime` value, as it's what you're updating anyway and set the text one of the labels accordingly – MadProgrammer Mar 21 '16 at 10:23
  • So I have two JLabels; timerMessage and remainingTime. Within the ActionListener, I decrement currentTime. Next, I did remaingTime.setText("" + currentTime);. After that, I have the message dialog with the parameters set to (null, "Lockout Time Remaining: " + remainingTime); The dialog isn't even popping up. –  Mar 21 '16 at 10:56
  • When initializing remaingTime within my secondPanel, I left the parameter blank (remainingTime = new JLabel(""); –  Mar 21 '16 at 10:57
  • Why have a message dialog? – MadProgrammer Mar 21 '16 at 20:26
  • Thanks. I solved it. I'm going to post a java problem I'm having regarding linked list and a list iterator. I'm on the last part –  Mar 27 '16 at 22:34