Java Quiz Player

Text Editor using Java Swing

August 5, 2016

1. Overview

This is an example of a text editor using Java Swing API. The editor has the following features:

The finished editor with some edited text looks like this:

GUI image

The Java source code for the finished application can be downloaded from the Download section below.

The editor is built and explained in the following four steps. At each step there are screenshots, code explanation and source code.

2. Build the basic GUI

Build the basic GUI; the editor window with a JFrame and the text editor using a JTextPane. The GUI look and feel is set as Nimbus and the default font for the text editor is set as SansSerif with 18 point size. The JTextPane is associated with a DefaultStyledDocument; this is for editing the styled text (like bold, italic, various fonts and sizes, colors, etc.).

The following code snippet shows the statements used to build the GUI:

frame__ = new JFrame(MAIN_TITLE);
editor__ = new JTextPane();
JScrollPane editorScrollPane = new JScrollPane(editor__);
editor__.setDocument(new DefaultStyledDocument());
frame__.add(editorScrollPane, BorderLayout.CENTER);

In the finished application type in some text; edit text using cut (CTRL-X), copy (CTRL-C) and paste (CTRL-V).

GUI image

2.1. Java source code

Download the Java source code for the example: MyEditor1.java

3. Editing and formatting

Add buttons to the editor window for text edit and formatting; buttons for cut, copy, paste, bold, italic, underline, set color, undo and redo functions.

GUI image

3.1. Cut, copy, paste, bold, italic and underline

The cut, copy and paste edit functions are created from Actions supplied to the JButtons. These actions are defined in the DefaultEditorKit. The bold, italic and underline format actions are defined in the StyledEditorKit.

The following code snippet shows how the cut action button is defined:

JButton cutButton = new JButton(new CutAction());
cutButton.setHideActionText(true);
cutButton.setText("Cut");
cutButton.addActionListener(editButtonActionListener);

The EditButtonActionListener is an ActionListener attached to all the six buttons. After some text is selected in the editor and a button (for example, the cut button) is pressed, the cursor does not return to the editor. The listener's actionPerformed() method has a single statement: editor__.requestFocusInWindow();. This brings the cursor back to the editor where it was previously before the cut button was pressed.

Note that the bold, italic and underline buttons act to toggle their respective attribute on the selected text.

3.2. Set color

The set color button when pressed opens a JColorChooser dialog where a color can be selected. This color is applied to the selected text. The following snippet shows the code from the set color button's ActionListener.actionPerformed() method:

Color newColor = JColorChooser.showDialog(...);
SimpleAttributeSet attr = new SimpleAttributeSet();
StyleConstants.setForeground(attr, newColor);
editor__.setCharacterAttributes(attr, false);

3.3. Undo and redo

The edited text can be undone or redone using the undo and redo functions. The UndoableEditListener is added to the StyledDocument; this listener hears the undoable operations occurring in the document. The operations are added to a UndoManager. The UndoManager manages the list of UndoableEdits, providing a way to undo or redo the appropriate edits.

The listener's undoableEditHappened() method has the following code:

undoMgr__.addEdit(e.getEdit()); // e is the UndoableEditEvent and undoMgr__ is the UndoManager

There are buttons for each of undo and redo actions. One ActionListener is used for both buttons. The listener's constructor takes an argument specifying an undo or redo. The following code snippet shows the actionPerformed() method with the code for undo action:

switch (type) {
    case "UNDO":
        if (! undoMgr__.canUndo()) {
            return; // no edits to undo
        }

        undoMgr__.undo();
    ...

3.4. Java source code

Download the Java source code for the example: MyEditor2.java

4. More text formatting

Add drop-down list boxes to the editor window for the text formatting functions; text alignment, font sizes and font family selection. Add buttons to insert bullets and numbers.

GUI image

Text alignment, font sizes and font family items are listed in individual JComboBoxes. The select action and application of selected item on text is implemented with ItemListener.itemStateChanged() methods. The Actions related to each function are defined in the StyledEditorKit.

4.1. Text alignment

There are four options for the text alignment defined from the StyleConstants: 0 (ALIGN_LEFT), 1 (ALIGN_CENTER), 2 (ALIGN_RIGHT), 3 (ALIGN_JUSTIFIED). The following code snippet shows the statements to apply the alignment option on selected text:

// e is the ItemEvent parameter from the itemStateChanged()
String alignmentStr = (String) e.getItem();
// The first item in the drop-down list is the identifier "Text Align", so reduce the
// selected item index by 1 to get the appropriate StyleConstants value	
int newAlignment = textAlignComboBox__.getSelectedIndex() - 1;
textAlignComboBox__.setAction(new AlignmentAction(alignmentStr, newAlignment));

4.2. Font size

Font sizes from 12 to 30 are listed in a JComboBox for selecting and applying on text. The following code snippet shows the statements to apply the font size option on selected text:

String fontSizeStr = (String) e.getItem();			
int newFontSize = Integer.parseInt(fontSizeStr);
fontSizeComboBox__.setAction(new FontSizeAction(fontSizeStr, newFontSize));

4.3. Font family

The GraphicsEnvironment class describes the collection of Font objects available to a Java application on a particular platform. The font families to be used in the application are listed in the drop-down list box (these are extracted from the available fonts). The following code snippet shows the statements to apply the font family option on selected text:

String fontFamily = (String) e.getItem();
fontFamilyComboBox__.setAction(new FontFamilyAction(fontFamily, fontFamily));

4.4. Bullets and numbering

This is implemented using buttons for inserting bullets and numbers. Also, there are buttons for removing them from the already bulleted or numbered text. The button's ActionListener.actionPerformed() methods implement the code for these functions.

The logic is based on getting the selected text, identifying the paragraph elements, and inserts the bullet or numbers for each paragraph. The following statements show the API used for bulets:

Element paraEle = doc.getParagraphElement(selectionStartPos);
int paraEleStart = paraEle.getStartOffset();
doc.insertString(paraEleStart, BULLET_STR_WITH_SPACE, getParaStartAttributes(paraEleStart));
// doc is the StyledDocument associated with the editor

The paragraph's attributes, like color, are obtained from the start element (Element): doc.getCharacterElement(paraEleStart).getAttributes() returns an AttributeSet. These attributes are applied to the inserted bullets or numbers.

The bullets or numbers are removed from the selected text using similar logic; removes instead of inserting. The following is the code for the bullets:

doc.remove(paraEleStart, BULLET_LENGTH);

4.4.1. Note on key press (Enter, Delete, etc.)

The function following the ENTER key press is implemented with a KeyListener and its keyPressed() and keyReleased() methods. There are two implementations, one for the bulleted list and the other for the numbered list. The key listeners are added to the JTextPane editor.

Also, the key listener class for key press includes Enter, Backspace, Delete and Left-arrow keys. The Enter press is implemented with both the keyPressed and keyReleased methods. The Delete, Backspace and Left key press is implemented within the keyPressed. The numbered para's key listener also includes key press actions (Backspace, Enter and Delete) and paste-insert for the text selected within the numbered paras.

4.5. Java source code

Download the Java source code for the example: MyEditor3.java

5. Insert pictures and save edited text

Add buttons to insert a picture and delete it. Include a file menu and its items for file new, save and open functions.

GUI image

5.1. Insert pictures

The picture is inserted in the editor using the JTextPane.insertComponent() method. The picture insert button's ActionListener.actionPerformed() method opens a JFileChooser. A picture file (JPEG or PNG) is selected and a JButton component is created with the picture as the button's icon. The button is provided with a FocusListener so that when the picture is selected (clicked on) in the editor, its borders are painted highlighting it.

The selected picture can be deleted using the delete picture button. The JButton associated with the picture has a setName() method. When the picture button is created, it is assigned a unique name which is used to identify and delete the picture.

The following code snippet is from the ActionListener.actionPerformed() method of the picture insert button action:

ImageIcon icon = new ImageIcon(pictureFile.toString());			
JButton picButton = new JButton(icon);
picButton.setBorder(new LineBorder(Color.WHITE));
picButton.setMargin(new Insets(0,0,0,0));
picButton.setAlignmentY(.9f);
picButton.setAlignmentX(.9f);
picButton.addFocusListener(new PictureFocusListener());
picButton.setName("PICTURE_ID_" + new Random().nextInt());
editor__.insertComponent(picButton);

5.2. Save and read edited document

The edited text with its formatting and pictures is available as a styled document within the application:

StyledDocument doc = (DefaultStyledDocument) editor__.getDocument();

A File JMenu and its JMenuItems New, Save and Open is created and added to the editor JFrame window. The New action closes any existing document and creates a new one. The Save action allows the document to be saved as a file. The document is saved as a serialized file (i.e., save the styled document as a Java object). The Open action opens an existing (previously saved) serialized document file. Note that the DefaultStyledDocument class implements java.io.Serializable.

The following snippet shows the serialized write and read related code for open and save actions respectively:

// Write StyledDocument to file
DefaultStyledDocument doc = (DefaultStyledDocument) getEditorDocument();
			
try (OutputStream fos = new FileOutputStream(file__);
        ObjectOutputStream oos = new ObjectOutputStream(fos)) {
				
    oos.writeObject(doc);
}
...

// Read StyledDocument from file
StyledDocument doc = null;
	
try (InputStream fis = new FileInputStream(file);
        ObjectInputStream ois = new ObjectInputStream(fis)) {
			
    doc = (DefaultStyledDocument) ois.readObject();
}
...

Note that a file (new or existing) is opened as a StyledDocument within the JTextPane editor. The following listeners (explained earlier) are added to the document after each open: UndoableEditListener and DocumentListener.

5.2.1. Alternate way of saving to a file

There is another way to save the StyledDocument as a file using the EditorKit's API. This is not implemented in this application. When this is used, the saved file can be opened from a MS WordPad application and viewed. It is noticed that some formatting like the text alignment was missing in such case. Also, the pictures inserted in this application cannot be saved or retrieved. The related code is shown here:

// Write to file
StyledDocument doc = getEditorDocument();
RTFEditorKit editorKit = new RTFEditorKit();
int startPos = 0;
int docLen = doc.getLength();
File file = new File("D:\file1.rtf");
			
try (OutputStream out = new FileOutputStream(file)){
				
    editorKit.write(out, doc, startPos, docLen);
}
...
// Read from file
StyledDocument doc = getEditorDocument();
RTFEditorKit editorKit = new javax.swing.text.rtf.RTFEditorKit();
int startPos = 0;
File file = new File("D:\file1.rtf");

try (InputStream in = new FileInputStream(file)) {
			
    editorKit.read(in, doc, startPos);
}
...

6. Download

NOTE: The source code may be compiled with Java SE 7 or 8. JRE 8 is required to run the executable JAR file.

7. Useful Links

Links to Java SE apidocs for the API used to build the GUI:

Return to top