Java GUI

  1. Zeller Pascal
  2. Zeller Java
  3. validDate Revisited – Python
  4. validDate Revisited – Java
  5. Java GUI
  6. GUI – Refinements – ComboBoxes
  7. GUI – Refinements – Error Messages
  8. GUI Refinements – Focus
  9. GUI Refinements – Today

The Final step is to create the GUI, I have sketched out my plan by hand. My initial plan is on the left, I plan to have 3 text input boxes, a large calculate button and an output box. The window will not be too big and I will fix the width and height, so that it cannot be resized by the user. To create the GUI, I will need 8 variables, 3 for the labels, 3 for the text input boxes, 1 for the button and one for the output box. The initial code is as follows:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GUI extends JFrame implements ActionListener
{
    private JLabel labelDay = new JLabel("Day");
    private JLabel labelMonth = new JLabel("Month");
    private JLabel labelYear = new JLabel("Year");
    private JTextField textFieldDay = new JTextField(2);
    private JTextField textFieldMonth = new JTextField(2);
    private JTextField textFieldYear = new JTextField(4);
    private JButton buttonCalculate = new JButton("Calc");
    private JLabel labelOutput = new JLabel();
    
    public GUI()
    {
        // GUI layout code goes here.
    }
    
    @Override
   public void actionPerformed(ActionEvent evt) {
       //code for buttonCalculate goes here.
   }
}

In the above code notice we have imported the java.awt library, and the java.awt.event.* library. We have told the GUI class to extend Frame from the awt library and implement ActionListener from the event library. I have also inported javax.swing library as this provides elements such as JTextField which can be customised better. I have also set the @Override flag on actionPerformed method ready to implement buttonCalculate. Next we need to work on the GUI() method to create the layout. i am going to say that each square on the plan represents 20 pixels, there for the size of the window will be:

\begin{aligned}
   width &= 20 \times 15 = 300 \text{ pixels}\\
   height &= 20 \times 12 = 240 \text{ pixels}
\end{aligned}

I can also use the layout to set out the bounds of each element. Java elements positions are from the top left corner of the block so each positions is as follows and are set as x-axis, y-axis, width, height:

x-Axisy-AxisWidthHeight
labelDay2006040
labelMonth10006040
labelYear180010040
textFieldDay20406040
textFieldMonth100406040
textFieldYear180406040
buttonCalculate2010026040
labelOutPut2016026040
positions of all the elements in the frame

I have also decided that all the labels will have a black background and white text and be centre aligned the Java code is as follows:

public GUI()
    {
        //set top label bounds
        labelDay.setBounds(20,0,60,40);
        labelMonth.setBounds(100,0,60,40);
        labelYear.setBounds(180,0,100,40);
        
        //set text field bounds
        textFieldDay.setBounds(20,40,60,40);
        textFieldMonth.setBounds(100,40,60,40);
        textFieldYear.setBounds(180,40,100,40);
        
        //set Button bounds
        buttonCalculate.setBounds(20,100,260,40);
        
        //set output label bounds
        labelOutput.setBounds(20,160,260,40);
        
        //format Labels
        labelDay.setForeground(Color.WHITE);
        labelDay.setOpaque(true);
        labelDay.setBackground(Color.BLACK);
        labelDay.setHorizontalAlignment(JLabel.CENTER);
        labelMonth.setForeground(Color.WHITE);
        labelMonth.setOpaque(true);
        labelMonth.setBackground(Color.BLACK);
        labelMonth.setHorizontalAlignment(JLabel.CENTER);
        labelYear.setForeground(Color.WHITE);
        labelYear.setOpaque(true);
        labelYear.setBackground(Color.BLACK);
        labelYear.setHorizontalAlignment(JLabel.CENTER);
        labelOutput.setForeground(Color.WHITE);
        labelOutput.setOpaque(true);
        labelOutput.setBackground(Color.BLACK);
        labelOutput.setHorizontalAlignment(JLabel.CENTER);
        
        //format TextFields
        textFieldDay.setHorizontalAlignment(JTextField.CENTER);
        textFieldMonth.setHorizontalAlignment(JTextField.CENTER);
        textFieldYear.setHorizontalAlignment(JTextField.CENTER);
        
        //add all the elements to the JFrame
        add(labelDay);
        add(labelMonth);
        add(labelYear);
        add(textFieldDay);
        add(textFieldMonth);
        add(textFieldYear);
        add(buttonCalculate);
        add(labelOutput);
              
        setTitle("Zeller"); 
        setLayout(null);
        setSize(300, 240);
        setVisible(true);
    }

This results in the following window:

It’s good but it could be better, I think I need to tweak the values in the table a bit. With a bit of tweaking i have managed to reduce the size of the window to a width of 227 pixels and a width of 182 pixels. The new positions of the elements are in the table below:

x-Axisy-AxisWidthHeight
labelDay116040
labelMonth6316040
labelYear125110040
textFieldDay1226040
textFieldMonth63226040
textFieldYear125226040
buttonCalculate16226040
labelOutPut110426040
new positions of all the elements in the frame

The new Java code is as follows:

public GUI()
    {
        //set top label bounds
        labelDay.setBounds(1,1,60,20);
        labelMonth.setBounds(63,1,60,20);
        labelYear.setBounds(125,1,100,20);
        
        //set text field bounds
        textFieldDay.setBounds(1,22,60,40);
        textFieldMonth.setBounds(63,22,60,40);
        textFieldYear.setBounds(125,22,100,40);
        
        //set Button bounds
        buttonCalculate.setBounds(1,62,225,40);
        
        //set output label bounds
        labelOutput.setBounds(1,104,225,40);
        
        //format Labels
        labelDay.setForeground(Color.WHITE);
        labelDay.setOpaque(true);
        labelDay.setBackground(Color.BLACK);
        labelDay.setHorizontalAlignment(JLabel.CENTER);
        labelMonth.setForeground(Color.WHITE);
        labelMonth.setOpaque(true);
        labelMonth.setBackground(Color.BLACK);
        labelMonth.setHorizontalAlignment(JLabel.CENTER);
        labelYear.setForeground(Color.WHITE);
        labelYear.setOpaque(true);
        labelYear.setBackground(Color.BLACK);
        labelYear.setHorizontalAlignment(JLabel.CENTER);
        labelOutput.setForeground(Color.WHITE);
        labelOutput.setOpaque(true);
        labelOutput.setBackground(Color.BLACK);
        labelOutput.setHorizontalAlignment(JLabel.CENTER);
        
        //format TextFields
        textFieldDay.setHorizontalAlignment(JTextField.CENTER);
        textFieldMonth.setHorizontalAlignment(JTextField.CENTER);
        textFieldYear.setHorizontalAlignment(JTextField.CENTER);
        
        //add all the elements to the JFrame
        add(labelDay);
        add(labelMonth);
        add(labelYear);
        add(textFieldDay);
        add(textFieldMonth);
        add(textFieldYear);
        add(buttonCalculate);
        add(labelOutput);
                      
        setTitle("Zeller"); 
        setLayout(null);
        setSize(227,182);
        setVisible(true);
    }

You will notice that clicking the close button does not do anything to get this to work the following code needs to be added to the bottom of the GUI method:

addWindowListener(new WindowAdapter(){
    public void windowClosing(WindowEvent e)
    {
        dispose();
        System.exit(0); //calling the method is a must
    }
});

The next thing i want to add before getting the button to work is to make the window to be fixed and open in the centre of the screen. This is simple two lines of code need to be added after setting the size, the lines are:

setResizable(false);
setLocationRelativeTo(null);

The GUI now looks like this:

I now need to get the button working, to get the button to call the actionPerformed method I need to add a line of code to the GUI method, this line is simply:

buttonCalculate.addActionListener(this);

I now need to simply create a Calc object, get the values in the Day,Month and Year text fields and then set the output label to the result returned from the Calculate method. The finished actionPerformed methods is:

public void actionPerformed(ActionEvent evt) {
       Calc calc = new Calc();
       int inputDay = Integer.parseInt(textFieldDay.getText());
       int inputMonth = Integer.parseInt(textFieldMonth.getText());
       int inputYear = Integer.parseInt(textFieldYear.getText());
       labelOutput.setText(calc.Calculate(inputDay, inputMonth, intputYear));
}

Running the finished project with a valid and invalid date is shown below:

Valid Date
Invalid Date

As we can see the program works, at this point the project is complete although, I can think of several refinements which I would like to add, such as drop down lists for day and month, and that the back ground changes for the output label when an error is encountered, so may revisit this at a later date.