Java Swing Basics

One of the hardest things about Java is working with Swing, which is the basic Java library for creating window GUI programs. Java isn’t particularly suited for GUI, but getting a basic GUI going with swing isn’t all that difficult and makes it a lot easier and still way easier than android programming.

The code in older books like Java programming for dummies won’t compile now in a lot of cases without major modification and so it can be frustrating to learn this stuff. Luckily you have the master Jeremiah Embs to show you a few things.

First thing; you are going to have to use a feature of Java called extends, which is basically used to make a copy of a class so you can add to it without retyping the whole thing over again.

Second thing; because of the specific way the Eclipse program manages things for you you’ll have to do things in a specific way to get your code to compile if you use an extension. Eclipse is great, but it is demanding.

First select File-New-Java Project and give the project a name, a single word with capital first words are best like “JavaWindowsProgram” options should be use default location, use an execution environment JRE: JavaSe-1.8 probably, project layout create separate folders, add working sets none, and click finish…

Then in the navigator go to the project folder you just made open up the arrow drop down, right click and go to new class, put in the same name you used for the project which was JavaWindowsProgram, and click public static void main(string[] args) which will add this line for you automatically. The rest of the options should be source JavaWindowsProgram/src, package blank, enclosing type blank, modifiers public, generate comments no, stubs inherited abstract methods, interfaces none, but here’s the thing… where it says superclass default is Java.lang.Object, click browse and change to JFrame, which will change the entry to javax.swing.JFrame. You’ll want to do this with every class we add. That JFrame superclass is important. Then click finish.

Okay, you’ll notice an import javax.swing.JFrame was added automatically and in the class declaration the words extends JFrame have been added. What that means is our class is a copy of JFrame class which is a fundamental part of Java so our class will act like JFrame but without us having to add a lot of code ourselves. Everything we do to it now will just add onto that so we are basically making a customized version of the JFrame class ourselves.

In the main method add this line…

BasicWindow w = new BasicWindow();

it won’t do anything and you’ll have an error. Click on the error and click create class BasicWindow, change the superclass to JFrame also and click finish. Make the code look like…

import javax.swing.JFrame;
import javax.swing.JPanel;

public class BasicWindow extends JFrame {
JPanel panel1 = new BasicPanel();

BasicWindow(){
this.setSize(500, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle(“A Java Window”);
this.setLocationRelativeTo(null);

this.add(panel1);

this.setVisible(true);
//((BasicPanel) panel1).changetext(“My Text”);

}
}

And then click on the error for the line which says “JPanel panel1 = new BasicPanel();” and add that class too and MAKE SURE you set the superclass to JPanel not JFrame.

Change the code to…

import javax.swing.JLabel;
import javax.swing.JPanel;

public class BasicPanel extends JPanel {

static JLabel label2 = new JLabel(“”);

public BasicPanel(){
JLabel label1 = new JLabel(“Basic Window Program”);
this.add(label1);

this.add(label2);
}

public void changetext(String s){
label2.setText(s);
}
}

Okay you can run it now. You’ll get a message about java or java applet, choose java.

Now I’ll explain the code.

JFrame is for making basic windows in Java so from now on we’ll call our window a JFrame.

Our root class has to extend JFrame class so we can make use of its methods directly in our root class if we want to or customize it, but that part is not necessary in the root class, because we create another class called BasicWindow which is what we absolutely need. But you never know, it might be useful later on to have our root class extend JFrame so I had you do it.

Now in the constructor in the BasicWindow class we set certain variables like the size and behavior of the window we are going to show. This is how we customize our JFrame. The line…

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

is very important if you want to be able to close your program so don’t forget it.

To get JFrame to show something other than a blank space we first have to add something called a JPanel to the JFrame. The JPanel is like a blank space within the JFrame to which we can add other things like text or buttons.

So we create a new class called BasicPanel and extend JPanel with it so we can customize our JPanel too.

There we created something called a JLabel which allows us to put some text on the JPanel and we add it to the panel and we created a method for changing the text by passing a String to it. We could change the text at any time within the JPanel right in code, but that’s pretty useless. We need a way to change it from it’s parent, BasicWindow, or BasicWindow’s parent, which is our root class called JavaWindowProgram. Creating this method helps with that.

So go back to your JavaWindowProgram class, the root class and check out the only line. The first one creates a BasicWindow object called w and the one we are going to add does something with it.

Add this line to the main method…

((BasicPanel) w.panel1).changetext(“Success”);

This strange incantation is uses something called casting. We cast w.panel1 as a BasicPanel first.

The reason we use casting here is difficult to explain. Normally casting is used to convert one data type to another. But what we are doing is unwrapping the object (technically here called unboxing) using a casting operator.

See the label we are trying to change the text of is within the panel within the JFrame. And so we have trouble getting access to the property we want to alter. So we made a method to alter it, but we can’t access that method directly from our root class. So the first thing we give the computer in terms of syntax is a parenthesis and within that we put a cast of BasicPanel also within parenthesis.

We are telling Java we want to unwrap the w’s panel1 object and convert it (technically unbox it since it is boxed inside a BasicWindow) temporarily to a BasicPanel so we can use whatever is inside a BasicPanel (the method we want to use inside it) from this portion of the code directly.

By this technique we gain access to the methods within downrange classes within objects. Complex? Yes. But absolutely necessary if we want to control aspects of our windows from the main part of our code. Now we can add buttons and all that to our BasicPanel class or make more types of JPanels for other purposes and add them to the BasicWindow as needed. Just remember to change the import in the JPanel class you made to import javax.swing.*; so it gives you access to all the swing stuff.

Adding a button the code should look like…

import javax.swing.*;

public class BasicPanel extends JPanel {

static JLabel label2 = new JLabel(“”);
static JButton button1 = new JButton(“Click”);

public BasicPanel(){
JLabel label1 = new JLabel(“Basic Window Program”);
this.add(label1);

this.add(label2);
this.add(button1);
}

public void changetext(String s){
label2.setText(s);
}
}

Now we want to modify our BasicPanel so that it “implements” ActionListener. An implement is a interface, which we won’t get into now, but basically it means that once added our class now requires that certain code be written in order to function properly.

change the class declaration to look like…

public class BasicPanel extends JPanel implements ActionListener{

Now our class requires some new code. In this case we must add a method. We must add the code…

public void actionPerformed(ActionEvent e) {
}

What the ActionEvent e means that when this method is called a special data type called an ActionEvent will be passed into our method and it can be referenced by the name e throughout our method. The letter e is used as a convention because it means an event, but any name would do.

The object e which is an event contains particular information about it including what action triggered it which is called the source. In this case we want it to be a button click.

So the object e can get queried as to its source using one of its methods called getSource like e.getSource would do it, so we write this code into the actionPerformed method…

if (e.getSource() == button1){
button1.setText(“Ouch”);

So now our whole BasicPanel class looks like…
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class BasicPanel extends JPanel implements ActionListener{

static JLabel label2 = new JLabel(“”);
static JButton button1 = new JButton(“Click”);

public BasicPanel(){
JLabel label1 = new JLabel(“Basic Window Program”);
this.add(label1);

this.add(label2);
this.add(button1);
button1.addActionListener(this);
}

public void changetext(String s){
label2.setText(s);
}

@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button1){
button1.setText(“Ouch”);
}

}
}

And it works. Try it out.

Now go back to your root class, JavaWindowProgram and add this line…

((BasicPanel) w.panel1).button1.setText(“Don’t hurt me.”);

And try it out.

See? Not so hard.

Now if you are wondering what the comment @override means that appeared in the BasicPanel class at the method actionPerformed means, it’s just a comment, just it means that the BasicPanel class implementing ActionListener does in fact already have this method, but we are writing it manually to override that basic version with our own and must do so in order to make the implementation valid.