Add features such as tabs for editing multiple files, new file, open, save, cut, copy and paste to the text editor you learned to code in the first part.






text editor's preview

In the first part you learned how to make a text editor using Java Swing’s libraries.

However there’s one thing we haven’t covered yet: features.

If you followed that tutorial, now you’ve probably got a text editor that works… at least until you start pressing buttons.

You made a complete template for your text editor last time, so now let’s add some functions to it.

Functions such as:

  • Creating a new file
  • Opening a file
  • Saving a file
  • Cutting stuff
  • Copying stuff
  • Pasting stuff

1. The Action and Document Listener


A listener in Java is an object that contains a bunch of functions called when a certain event happens.

A key pressed, a button clicked or a document modified may generate a response from a listener.

All listener classes are defined as abstract.

This means that the class determines all the listener’s functions, but not what they do.

This is why you can’t instance objects directly from an abstract class and even if you could they wouldn’t do anything.

It’s up to you deciding what those functions should do. How?

Creating a new class that implements those functions determined in the abstract class.

Then you can override those to define their behaviour yourself.

Since I created those classes in the same file of the main function, I had to make them static, because a static function can’t call not static functions, classes or variables defined in the same file.

ActionListener

An action listener is called when the user clicks on an element.

I wrote an Actions class that implements the ActionListener class and which assigns a function to each item in the menus.

The s string contains the name of the element that called the action listener, or, in other words, the one with which the user has interacted.

From that, using a switch statement, we can decide what to do.

The first three function are very simple: the get the component (a text editor area) in the current tab and cast it to an Editor object, so that the computer knows that that object belongs to that class and it allows us to use its functions.

The fourth case creates a new Editor object, it assigns a document listener to it and it adds it to the tab container as we saw previously – and that we can use because it’s defined outside any function.

The fifth and sixth cases use two custom function that we’re going to see later – like everything in this post apparently.

DocumentListener

A document listener waits for any change to a document.

If you type a letter in a text area, a document listener is called.

All three functions of this class contain the same code, because I want it to be executed when any type of change happens.

When one of them is called, it gets the Editor object from the current tab and it sets it as not saved, then it changes the title of the tab.

I could have added an asterisk directly, but I prefer see if everything worked.

The three spaces I added at the end of the tab’s name are used to leave some space for the “x” which closes the tab and that I’m going to explain later.

2. The Save and Open functions


The Save and the Open functions are similar, but not in the same way addFileMenu and addEditMenu – explained in the previous post – are.

They both link the text editor with files, but in opposite directions – as you’ve probably expected.

Futhermore, since we want them to remember the last directory opened for a file, they’re more complex than needed for basic working.

But you know, you’re here for some real programming and not for that simple coding that anyone out there can teach.

The Save function

Let’s divide this piece of code in three parts:

  1. Preparation
  2. File choice
  3. Actual saving
Preparation

In the first part we see if there are any open tabs, otherwise there’s nothing to save.

If so, we get the Editor object from the current tab, because we need its directory variable’s value and we’re also going to use it later.

We’re going to use its directory variable’s value to open a file chooser (JFileChooser) – picture below – at the last file’s location.

File chooser

This can be obtained either by a previous saving or when the file is opened, otherwise it remains blank – or any other default value specified in the Editor class file.

File choice

The second part starts with an if statement that does two things:

First, it shows the file chooser created in the previous line (chooser.showSaveDialog(null)), then it checks if the user clicked “Save” (JFileChooser.APPROVE_OPTION).

Yes, the program does stop while the file chooser is open. Yes, even if the function is in another statement.

Now, if the user pressed “Save”, the program gets the choosen directory and set it to a file variable (a variable declared outside any function that can be used everywhere within its file) called directory.

Those lines above check if the user forgot to specify the file’s extension and if so, they set it to “.txt” (a simple text file).

How do they know that the extension is missing? File extensions are separated from file names through a dot, so if no dots mean no extensions.

lastIndexOf('.') looks for the last occurrens of a character or a string in anothe string. If it doesn’t find anything, it returns -1.

The next line sets the Editor object’s directory variable to the newly selected directory, in case it changed.

Then we create a File object, which is used to manage the file at the specified location – or it creates one if it doesn’t exist.

From it we can get the file’s name without much effort and we can set it as the Editor object’s name value, so that we can use it to set the file’s tab’s name later.

Actual saving

The third part begins with a try-catch statement, which prevents the program to crash if an error occurs during the writing of the file.

This article by BeginnersBook explains what a try-catch statement is.

Most of the code in this part is sufficiently commented, but I want you to focus on these things anyway:

  • The difference between FileWriter and BufferedWriter, that is well explained here.
  • The difference of data being in a buffer vs in an actual file, which you would know if you read my article about files in C
  • The line ed.setSaved(true);, which prevents the next line from adding an asterisk to the file’s name in its tab’s heading.
  • The line JOptionPane.showMessageDialog(null, e.getMessage()); that shows a dialog window if an error occured.

The Open function

I think the Open function is a bit more complicated than the Save one, because we have to create a new tab with a new Editor objectas far as that can be considered “complicated”.

On the other hand, however, I’ve already explained a lot of similar thing for the Save function, such as the file chooser.

Therefore I’m going to take into consideration only two parts of code:

  1. Reading file content
  2. Creating a new tab
Reading file content

The key to understand this piece of code is knowing that the readLine() function returns null when the reader reaches the end of a file.

So, we have two String variables, one for storing the whole text and the other to store temporarily each line.

Until the end of the file is reached, a new line is read and added to the first variable.

Creating a new tab

Once the program has read and closed the file, it has to create a new tab, with a new text area and fill it with the content stored in the text string.

In order to do that, you must first create a new Editor object using the file’s name – 1st line.

Then you set the file’s directory and you set it as saved, because we’ve just opened it.

In the fourth line we add a tab as we did in the last post.

Finally, we set the text and the document listener, using another file variable called docListener.

You can see how I created the two listener objects in the main function.

3. Extras


There are two more things I want to point out: close buttons for tabs and “look and feel”.

Let’s start from the simplest.

Look and feel is simply the appereance of a window and its elements.

For example, Windows and Java has two different look and feels, as you can see below.

Windows's vs Java's look and feels

The other piece of code is a class that modifies the default tab heading to add a close button.

I’ve taken the code from esus.com and I’ve modified it so that the program asks if you want to save an usaved file that you’re about to close.

It’s a bit harder to understand since it works with Java AWT – another set of graphic libraries – and we haven’t covered it yet.

All its code is in the CustomTabbedPaneUI class and it can be used by adding this simple line:

Conclusion


I know, I know, even if I divided this tutorial in two parts, they’re both long… but it’s worth it.

We didn’t make the usual simple and useless text editor, but an actual working program – probably better than the classic notepad.

Do you want to learn the basics of programming? It doesn’t matter if you want to code in Java, C++ or whatever, start from here: Learn C programming.

If you have any questions, ask them in a comment and if you liked the article, please share it.

Anyway, the post is finished, have a good day and we will see next week!

From Zephyro it’s all, Bye!

Categories: Learn Java

Leave a Reply

%d bloggers like this: