Learning Java in 2020 – Beginner – How to program a basic text editor

Overview reference

Problem

Goal

Create a very basic text editor without text formatting features. It should provide a text field where a text can be given and a button to save the text input as a file. Before saving the file, the user should provide the file name via the command line. After which, the file is saved automatically in the current directory.

Pseudo-code

  • Display Text Field with save button
  • Keep reference of text field
  • Listen to button click event
  • If button was clicked, take text field reference and extract typed in value
  • Create a new file object
  • Add content
  • Request file name from user
  • Save new file with provided file name

Solution

Variables in a class

      JFrame frame;
	JTextArea area;
	JButton button;
	static String default_filename = "default.txt";

Instance variables

These types of variables are created when the instance of the class is created. In the case above, the instance variables are frame, area and button. These variables may have different values/references in different objects and are destroyed once the object is destroyed.

Class variables

Unlike instance variables which rely on their objects for existence, these static variables live as long as the program itself lives. Their value/ reference is the same even across the instances of the class.

Class Constructors

This function or method is called when an instance of a class is created. One can use this method to initialize the instance variables, which were already declared in the class. Unlike javascript, where the constructor method is literally called “constructor”,in Java the constructor method is named exactly like the class. Based on this reference, this method types cannot return a value.

TextEditor() {
		frame = new JFrame();
		area = new JTextArea();
		button = new JButton("save as text file");
		
		area.setBounds(0,0, 800, 700);
		button.setBounds(800 - 300, 800 - 80, 200, 50);
	
		button.addActionListener(this);
		frame.add(area);
		frame.add(button);
		frame.setSize(800, 800);
		frame.setLayout(null);
		frame.setVisible(true);
	}

Class implements interfaces

It took me a while to grasp the concept of interfaces, because they look like classes lacking body. I like to understand interfaces as architectural blueprint / design of an estate, while a class the actual physical estate. The houses within this estates are the objects or instances of the class. With the design or interface, the requirements or/and attributes of the estates are defined.Although in reality, how a design/interface is implemented may slightly differ, however on the foundation level the estates look exactly alike. Read more here. The text editor class implements the interface called Actionlistener. Here is a wonderful tutorial on using this interface.

public class TextEditor implements ActionListener {}

This is what the interface looks like :

public interface ActionListener extends EventListener {

    /**
     * Invoked when an action occurs.
     * @param e the event to be processed
     */
    public void actionPerformed(ActionEvent e);

}

If you read the reference given above, you should be aware that methods declared in an interface should have functionality in the class that implements that interface. Therefore, the method “actionPerformed” will be given the following functionality in our class “textEditor”:

public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		String text = area.getText();
		frame.dispose();
		frame.setVisible(false);
		System.out.println("type in the name of your text file below: ");
		Scanner sc = new Scanner(System.in);
		String filename  =sc.nextLine();
		if(filename.length() == 0 || filename.indexOf(".txt") < 0) {
			filename += default_filename;
		}
		System.out.println(filename);
		try {
			BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
			writer.write(text);
			writer.close();
			System.exit(0);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}

In the constructor, the program was “instructed” to listen to whatever the user does to the button. Namely:

button.addActionListener(this);

Once the button has been clicked, since the object implements the ActionListener interface, the actionPerformed method will be called. Based on the pseudo-code, the input value extraction, filename definition and file storing logic should happen in the actionPerfomed method block.

Writing stuff

After countless blog posts and stackoverflow-ing, I decided to go with this solution.

try {
			BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
			writer.write(text);
			writer.close();
			System.exit(0);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

FileWriter

According to this, FileWriter class is used for creating character files ( what that means, I honestly do not know.). But it does what I want, so I’ll take it.

FileWriter(String fileName)

This constructor takes the argument of type String. This argument will be used for defining the name of the file.

Note: Up until this point, I never thought there could exist more than one constructor in a class. I guess we will learn about that as the complexity of this series increases.

BufferedWriter

After I create the file, (new File(String filename)), my input value has to be added to the file right ? To add the user’s text or strings or series of characters, this class will be used.

new BufferedWriter(Writer out)

The constructor takes in an argument of type Writer. I know, the object that was passed in the actionPerformed method was not of type Writer but FileWriter. Or was it ? Yes, if you read the FileWriter documentation, you should see the inheritance “tree”.

Class FileWriter
      java.lang.Object
          java.io.Writer
            java.io.OutputStreamWriter
                java.io.FileWriter

Based on the tree, the FileWriter, indirectly, inherits the class Writer. Hence, it is indirectly of typeWriter. Consequently, our example is still valid. YEA!

Following writing the user’s input value using the write method and “saving” the file with the close method of BufferedWriter, the program is closed with System.exit.

How does one handle if the file already exists or something bad happened to the file during the writing process ? Exceptions.

Exceptions

Try block

When the possibility of a code throwing an error exists, place it within the try block. That way the program pays extra attention to problems that may occur. Ref.

Catch block

In case a code within the try block swings an exception, the catch block directly close to it( immediately after) will handle it. Luckily the catch block takes an argument which provides detailed explanation of the error; where and why it happened. The error can be logged or depending on the severity of the error, the program itself could be shut down with System.exit by the programmer. I find it interesting that one can append multiple catch blocks after a try block based on the Exception/Error type. Something lacking in javascript.

try {

} catch (IndexOutOfBoundsException e) {
    System.err.println("IndexOutOfBoundsException: " + e.getMessage());
} catch (IOException e) {
    System.err.println("Caught IOException: " + e.getMessage());
}

Note: just in case the term “block” is confusing you, it simply means the contents within { }.

IOException

Class IOException
      java.lang.Object
          java.lang.Throwable
               java.lang.Exception
                  java.io.IOException

All errors related to input /output operations e.g. writing a file, creating a file, saving a file etc.

printStackTrace

All exceptions that inherit the class Throwable have the public method printStackTrace. This method prints out details of the exception origin. So pretty informative and useful for debugging.

Trigger Action

public static void main(String[] args) {
		// TODO Auto-generated method stub
		new TextEditor();
	}

Run Program

C:<path>\com.learnjava\src\com\learnjava\beginner>java TextEditor.java
type in the name of your text file below:
hello.txt
hello.txt
A simple text editor with a button
A simple text editor with a button

The program created a hello.txt file in C:\com.learnjava\src\com\learnjava\beginner with content “ Hey there friend, what doing?”.

Question

How would you use another text field to get the file name from the user, instead of the command line ?

Links