Inheriting From A Control in Java

I am sure we all love Java Swing. It is not quite as thrilling as the swings we use to play on at the park, but it sure makes our Java applications come alive with a nice rich GUI. We are familiar with the JButton to make buttons, JTextFields to make textboxes and perhaps you have even ventured into using JTables. But maybe some of these controls have not gone far enough for you. Maybe you want to crack the whip on these controls and give them some extra super powers so they can go out and fight crime on the streets of DIC. We will grant the JTextArea control the power of file handling right here on the Programming Underground!

For our little example we are going to have two class files. One is going to be our new class called “myTextBox” which is going to extend from a JTextArea control, but given a few extra functions to handle reading from and saving to a file. The second class is going to be simply a driver program (the main program which will use and test our new class).

What would a control like this be useful for? Well, have you ever thought of making a text editor that was tabbed so you could open multiple text documents at once? Maybe you have had experience with a program like TextPad or Notepad++. Instead of having to keep track of an array of files and which files are associated with which JTextArea controls used for editing them, using a class like this we can directly tie the file to the textarea editing it. Then it is just a matter of calling our method “Open” on the textarea to load a file into the control and calling “Save” on the textarea control to save its contents back to file. Very very handy.

Our control for all intents and purposes is an actual JTextArea control. It is a child of that control type. It just has a few added methods and a read only property. It will have the Open() method, to open a file and load its contents into the control, and a Save() method to take what is in the control and write it to its corresponding file. The property called getFileName() will simply provide the name of the file associated with that textarea control. Nice little property that you could use in a loop to know all the currently loaded files by iterating through the textarea controls you have open.

Here is what our control looks like….

import javax.swing.*;
import java.io.*;

// Our class extends the functionality of JTextArea
public class myTextBox extends JTextArea {
	private String aFileName;
	
	// Constructor (default parameterless)
	public myTextBox() {
		super();
		aFileName = "";
		setLineWrap(true);
	}
	
	// Constructor (parameterized)
	public myTextBox(String fileName) {
		super();
		if (fileName != null) {
			// File name was specified, so try and open it.
			Open(fileName);
		}
		setLineWrap(true);
	}
	
	// Opens a specified file name. This can be called from a constructor or from a direct call to the method "Open" on our control.
	public void Open(String fileName) {
		if (fileName != "") {
			
			aFileName = fileName;
			
			File f = new File(aFileName);
			
			// Does this file actually exist before we attempt to read it?
			if (f.exists()) {
				// Try catch in case we have an error opening or reading the file.
				try {
					BufferedReader buffRead = new BufferedReader(new FileReader(f));
					
					String line = "";
					
					// Clear the textbox before reading in a  new file.
					this.setText("");
					
					// Line by line we read from the text file and append that string to the textbox.
					while ((line = buffRead.readLine()) != null) {
						this.append(line);
					}
					buffRead.close();
				}
				catch (IOException ex) {
					JOptionPane.showMessageDialog(null,"Error reading file!", "File IO Error", JOptionPane.ERROR_MESSAGE);
				}
			}
			else { 
				JOptionPane.showMessageDialog(null, "File does not exist!", "File Not Found", JOptionPane.ERROR_MESSAGE);
			}
		}
	}
	
	// Save what is in this control to the file specified in aFileName (saving it back to the file we opened).
	public void Save() {
		if (aFileName != null) {
			// Make sure we try catch here in case we have an error opening or saving the file.
			try {
				BufferedWriter buffWrite = new BufferedWriter(new FileWriter(aFileName));
				
				// Get what text is in the control and write it to the file. Then close it and tell the user the save is complete.
				buffWrite.write(this.getText());
				buffWrite.close();
				JOptionPane.showMessageDialog(null, "Save complete!", "Save Complete", JOptionPane.INFORMATION_MESSAGE);
			}
			catch (Exception ex) {
				JOptionPane.showMessageDialog(null, "Error saving file!", "File Save Error", JOptionPane.ERROR_MESSAGE);
			}
		}
	}
	
	// Returns the file currently associated with this control.
	public String getFileName() {
		return aFileName;
	}
}

As always the code is well commented to help you step through the process. We start off by extending our new class from an existing JTextArea control. This is a class that has an “is a” relationship with JTextArea. Our textbox IS A type of JTextArea. Next we have two constructors. One is the default parameterless constructor. This constructor does nothing but call the constructor of the JTextArea parent, as well as setting our only member variable aFileName to an empty string.

The other constructor is the one we expect to use most of the time. It takes in a file name, tests to see if it exists, attempts to open it and read its contents into the control. We do this by opening the file using a BufferedReader, looping through its lines and appending each line to the control. When we are done we close the file. We also use this section of code to set our member variable aFileName to the name of the file specified. The file open method is also made public. This is in the event that the user wants to change the file this control is editing, it can simply call the open method again.

To augment this we have also provided a Save() method which will take whatever is in the control, open up the file specified in the aFileName variable and write its contents back to the file. It does this with a BufferedWriter class and writes whatever content is in the control to the file. For the programmer using our class, all they need to do is call the save method on the control instance itself. We demonstrate both the open and save functionality using a simple driver program below…

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

public class testMyTextBox extends JFrame implements ActionListener {
	// Here is a private reference to our new control
	private myTextBox mbox;
	
	// Constructor for this class
	public testMyTextBox() {
		setLayout(new BorderLayout());
		
		// Create an instance of our new control, giving it a file to open and load into it.
		mbox = new myTextBox("c:\\filetest.txt");
		
		// Create a button to activate a save of the contents.
		JButton button = new JButton("Save");
		button.addActionListener(this);
		
		// Add the controls to our JFrame
		add(mbox,BorderLayout.CENTER);
		add(button,BorderLayout.SOUTH);
	}
	
	// Our program starts here. We create our application, set its title size and show it when it is fully loaded.
	// Notice that by creating an instance of our app, the testMyTextBox() constructor is going to fire first
	// Which will load our new control and button onto the form prior to showing the JFrame.
	public static void main(String args[]) {
		testMyTextBox app = new testMyTextBox();
		app.setDefaultCloseOperation(EXIT_ON_CLOSE);
		app.setTitle("My New TextBox");
		app.setSize(300,300);
		app.setVisible(true);
	}
	
	// This is the beauty of our new control. When the user clicks the save button, all we have to do is call our method "Save"
	// on our new control and it will take care of the saving.
	public void actionPerformed(ActionEvent e) {
		mbox.Save();
	}
}

Nothing too fancy about this driver program. This program simply creates a JFrame which we set its title, size, default close operation and adds an instance of our new control to the center of the screen (using a border layout). In addition it adds a simple save button to the bottom. I am sure with a few tweaks you could turn this driver into something that could hold a satellite hostage for…. 1 MILLIONNNNN DOLLARSSSS! I mean… 100 BILLIONNNNN DOLLARSSSS!

The real magic is that we attach an actionListener to the button which will listen for a button click and trigger the save. When that click is received, all we have to do is call “Save” on any myTextBox objects we want to save. Each myTextBox can save to their individual files and all is great. This is encapsulation at its best! The programmer does not have to know a thing about what the control is doing under the hood, just that it can open and save files to and from the control.

If we wanted to get access to the file associated with the myTextBox control, we could have called the mbox.getFileName() method and it would return the file name and path specified in the initial Open() method call. Simple as that.

So look through the code and read the inline comments and I am sure it will make sense to you. Feel free to use this code any way you like and it is in the public domain… like all the code here on the Programming Underground is. Just please, don’t use it to attack some small village in Tibet. They really have enough things to worry about than being fried from a satellite laser shot from space using this program. Enjoy and thanks for reading! 🙂

About The Author

Martyr2 is the founder of the Coders Lexicon and author of the new ebooks "The Programmers Idea Book" and "Diagnosing the Problem" . He has been a programmer for over 20 years. He works for a hot application development company in Vancouver Canada which service some of the biggest tech companies in the world. He has won numerous awards for his mentoring in software development and contributes regularly to several communities around the web. He is an expert in numerous languages including .NET, PHP, C/C++, Java and more.