Creating a Simple Journal Application in java

Discover how to Creating a Simple Journal Application in java. This guide covers step-by-step instructions on building a Java Swing-based UI, managing journal entries, and enabling search and tag filtering for an enhanced user experience.

Key Features of the Journal App

  1. User Interface with Java Swing
    Java Swing is a GUI toolkit that allows developers to create interactive user interfaces. It provides a variety of components like buttons, text fields, panels, and lists, which you can use to build a functional and aesthetically pleasing UI. In this app, we will design a clean layout using these components for the journal’s main window.
  2. Journal Entries
    Each journal entry will contain three components:
    • Title: A brief heading summarizing the entry.
    • Content: The main body of the journal entry.
    • Tags: Keywords associated with the entry to categorize it. Tags can be something like “personal,” “work,” or “health,” which helps in sorting and filtering journal entries.
    The entries will be stored in a list, and each entry will be represented by an object. This makes it easy to manipulate, display, and store the data.
  3. Adding New Entries
    Users can enter the title, content, and tags (comma-separated) in input fields. Once they click the “Add Entry” button, the app will create a new journal entry object and add it to the list. The new entry will be displayed in the UI list, and the data will be saved to a file.
  4. Searching Journal Entries
    To locate specific journal entries, users can search by title or tag. This search will look through the list of journal entries and display any matches. This feature allows users to quickly find relevant entries without scrolling through a long list.
  5. Editing and Deleting Entries
    Users can edit or delete entries. If an entry needs modification, the user can select it from the list, and the app will load the title, content, and tags into the input fields. After editing, the entry is updated in the list and the file. If an entry is no longer needed, the user can delete it, and the app will remove it from both the UI and the file.
  6. Exporting Entries
    Users can export their journal entries to a text file, making it easy to back up or share their data. The entries will be written to the file in a readable format, with each entry separated by a dashed line for clarity.
  7. Filtering Entries by Tags
    The app provides a feature to filter journal entries based on tags. If a user wants to view only entries related to a specific topic, they can select a tag from a dropdown menu. This helps organize the entries and makes it easier to find entries about particular subjects.
Creating a Simple Journal Application in java

You can get the code of Creating a Journal App with Export and Import Capabilities in Java from my GitHub repository

Or you can also get the code of Building a Personal Journal App in Java with Swing by Downloading the Zip File

How the App Works

1. User Interface (UI) Components

The UI is built using Swing components like JFrame, JPanel, JTextField, JTextArea, JList, and JButton. These components are arranged within panels to provide a clear and intuitive layout.

  • Main Window (JFrame): The main window contains all the components, including a form for adding entries, a list for displaying entries, and buttons for interacting with the app.
  • Text Fields and Text Area: These are used for entering the title, content, and tags of a new journal entry.
  • Buttons: Each button triggers an action, such as adding a new entry, searching, or exporting data.
  • JList: This is used to display the list of journal entries. It provides an interactive way to view and select entries.
  • JComboBox (Dropdown): A dropdown menu allows users to filter entries by tags, providing an easy way to view specific categories of entries.

2. Data Model

Each journal entry is represented by an instance of the JournalEntry class, which contains:

  • Title: A string to hold the title of the journal entry.
  • Content: A string to hold the main content of the entry.
  • Tags: A set of strings that represent tags associated with the entry.

This class encapsulates the data for each journal entry and provides a method to display the entry in a readable format.

The journal entries are stored in a List<JournalEntry>. This list is updated whenever a user adds, edits, or deletes an entry.

3. Saving and Loading Entries

The journal entries are saved to a file (journal.txt) for persistence. Every time an entry is added, edited, or deleted, the list of entries is saved back to the file.

  • Saving: When journal entries are saved, each entry’s title, content, and tags are written to the file, with a separator line (-----) between entries.
  • Loading: On app startup, the app reads the file and loads the entries into memory. This ensures that journal entries persist between sessions.

4. Developing a Journal App with Add, Edit, and Delete Features

  • Adding Entries: When the “Add Entry” button is clicked, the app checks if the title and content are empty. If not, it creates a new JournalEntry object, adds it to the list, and saves it to the file.
  • Searching Entries: The search function prompts the user for a keyword. It then searches through all entries and checks if the keyword appears in the title or any of the tags. Matching entries are displayed in a popup.
  • Editing Entries: If an entry is selected, its title, content, and tags are loaded into the input fields. After editing, the app updates the entry in the list and saves it to the file.
  • Deleting Entries: When a user selects an entry and clicks the “Delete Entry” button, the app removes the entry from the list and the file.
  • Exporting Entries: Users can export their journal entries to a text file. The file is created using a BufferedWriter, and each entry is written in a readable format.
Creating a Simple Journal Application in java

5. Filtering by Tags

The tag filter dropdown allows users to view only entries that match a selected tag. The app collects all unique tags from the entries and populates the dropdown. When a tag is selected, the app filters the list to show only entries with that tag.

Benefits of This App

  • Data Persistence: Journal entries are stored in a file, which allows data to be persistent even after the app is closed. This ensures that users don’t lose their journal entries between sessions.
  • Organization: By categorizing entries with tags, users can quickly find entries related to specific topics. The filtering feature makes it easy to sort entries by tags.
  • User-Friendly Interface: The use of Swing components ensures a clean and easy-to-use interface that is familiar to most desktop application users.
  • Backup and Sharing: The export feature enables users to back up their data or share it with others. It’s a simple yet powerful way to ensure journal data is never lost.

Conclusion of Building a Personal Journal App in Java with Swing

Creating a Simple Journal Application in java is a rewarding project that can teach you how to use Swing components, manage data with classes and collections, and handle file I/O operations. By adding features like searching, editing, deleting, and filtering entries, you are creating a Journal App with Export and Import Capabilities in Java and an app that allows users to interact with their journal in meaningful ways. The ability to export entries provides an added layer of usefulness by ensuring that users can back up their data or share their reflections.

Source code of Creating a Simple Journal Application in java

The code for Creating a Simple Journal Application in Java uses Swing to allow users to add, edit, delete, and search journal entries with titles, content, and tags. Entries are stored in a file (journal.txt) for persistence and can be filtered by tags or exported. The intuitive GUI features fields for input, a list to display entries, and buttons for actions, offering a user-friendly journaling experience.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;

class JournalEntry {
    private String title;
    private String content;
    private Set<String> tags;

    public JournalEntry(String title, String content, Set<String> tags) {
        this.title = title;
        this.content = content;
        this.tags = tags;
    }

    public String getTitle() {
        return title;
    }

    public String getContent() {
        return content;
    }

    public Set<String> getTags() {
        return tags;
    }

    @Override
    public String toString() {
        return "Title: " + title + "\nContent: " + content + "\nTags: " + tags + "\n";
    }
}

 class PersonalJournalApp {
    private static final String JOURNAL_FILE = "journal.txt";
    private final List<JournalEntry> journalEntries = new ArrayList<>();
    private final DefaultListModel<String> entryListModel = new DefaultListModel<>();
    private JList<String> entryList;

    private JTextField titleField;
    private JTextArea contentArea;
    private JTextField tagField;
    private JComboBox<String> tagFilterCombo;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                new PersonalJournalApp().initializeApp();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    private void initializeApp() throws IOException {
        loadJournalEntries();
        createAndShowGUI();
    }

    private void createAndShowGUI() {
        JFrame frame = new JFrame("Personal Journal");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(900, 650);
        frame.setLocationRelativeTo(null);
        frame.setLayout(new BorderLayout(10, 10));

        frame.add(createHeaderPanel(), BorderLayout.CENTER);
        frame.add(createButtonPanel(), BorderLayout.SOUTH);
        frame.add(createListPanel(), BorderLayout.WEST);

        frame.setVisible(true);
    }

    private JPanel createHeaderPanel() {
        JPanel headerPanel = new JPanel(new BorderLayout(10, 10));
        headerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        titleField = createTextField("Title", 16);
        headerPanel.add(titleField, BorderLayout.NORTH);

        contentArea = new JTextArea(10, 30);
        contentArea.setLineWrap(true);
        contentArea.setWrapStyleWord(true);
        contentArea.setFont(new Font("Arial", Font.PLAIN, 14));
        contentArea.setBorder(BorderFactory.createTitledBorder("Content"));
        JScrollPane scrollContent = new JScrollPane(contentArea);
        headerPanel.add(scrollContent, BorderLayout.CENTER);

        tagField = createTextField("Tags (comma-separated)", 14);
        headerPanel.add(tagField, BorderLayout.SOUTH);

        return headerPanel;
    }

    private JPanel createButtonPanel() {
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
        buttonPanel.add(createButton("Add Entry", new Color(34, 167, 240), e -> addNewEntry()));

        buttonPanel.add(createButton("Search", new Color(34, 167, 240), e -> searchEntries()));
        buttonPanel.add(createButton("Delete Entry", new Color(192, 57, 43), e -> deleteSelectedEntry()));
        buttonPanel.add(createButton("Edit Entry", new Color(241, 196, 15), e -> editSelectedEntry()));
        buttonPanel.add(createButton("Export Entries", new Color(39, 174, 96), e -> exportEntries()));

        return buttonPanel;
    }

    private JPanel createListPanel() {
        JPanel listPanel = new JPanel(new BorderLayout());
        entryList = new JList<>(entryListModel);
        entryList.setFont(new Font("Arial", Font.PLAIN, 14));
        entryList.setBorder(BorderFactory.createTitledBorder("Journal Entries"));
        JScrollPane scrollList = new JScrollPane(entryList);
        scrollList.setPreferredSize(new Dimension(250, 0));
        listPanel.add(scrollList, BorderLayout.CENTER);

        tagFilterCombo = new JComboBox<>();
        tagFilterCombo.addItem("All");
        populateTagFilter();
        tagFilterCombo.addActionListener(e -> filterByTag());
        listPanel.add(tagFilterCombo, BorderLayout.NORTH);

        return listPanel;
    }

    private JTextField createTextField(String title, int fontSize) {
        JTextField textField = new JTextField();
        textField.setFont(new Font("Arial", Font.PLAIN, fontSize));
        textField.setBorder(BorderFactory.createTitledBorder(title));
        return textField;
    }

    private JButton createButton(String text, Color color, ActionListener actionListener) {
        JButton button = new JButton(text);
        button.setBackground(color);
        button.setForeground(Color.WHITE);
        button.setFont(new Font("Arial", Font.PLAIN, 14));
        button.setFocusPainted(false);
        button.setBorder(BorderFactory.createLineBorder(color, 2, true));
        button.setPreferredSize(new Dimension(120, 35));
        button.addActionListener(actionListener);
        return button;
    }

     private void addNewEntry() {
         String title = titleField.getText().trim();
         String content = contentArea.getText().trim();
         String tagsInput = tagField.getText().trim();

         if (title.isEmpty() || content.isEmpty()) {
             JOptionPane.showMessageDialog(null, "Title and content cannot be empty!");
             return;
         }

         Set<String> tags = new HashSet<>(Arrays.asList(tagsInput.split("\\s*,\\s*")));
         JournalEntry newEntry = new JournalEntry(title, content, tags);

         journalEntries.add(newEntry);
         entryListModel.addElement(title); // Update the list UI
         saveJournalEntries(); // Save to the file

         // Clear the input fields
         titleField.setText("");
         contentArea.setText("");
         tagField.setText("");

         JOptionPane.showMessageDialog(null, "New entry added successfully!");
     }

     private void searchEntries() {
         String query = JOptionPane.showInputDialog("Enter title or tag to search:");
         if (query != null && !query.trim().isEmpty()) {
             boolean found = false;
             for (JournalEntry entry : journalEntries) {
                 if (entry.getTitle().toLowerCase().contains(query.toLowerCase()) ||
                         entry.getTags().stream().anyMatch(tag -> tag.toLowerCase().contains(query.toLowerCase()))) {
                     found = true;
                     JOptionPane.showMessageDialog(null, "Found: " + entry);
                 }
             }
             if (!found) {
                 JOptionPane.showMessageDialog(null, "No entries found matching the search query.");
             }
         }
     }


     private void deleteSelectedEntry() {
        int selectedIndex = entryList.getSelectedIndex();
        if (selectedIndex != -1) {
            journalEntries.remove(selectedIndex);
            entryListModel.remove(selectedIndex);
            saveJournalEntries();
            JOptionPane.showMessageDialog(null, "Entry deleted!");
        } else {
            JOptionPane.showMessageDialog(null, "Please select an entry to delete.");
        }
    }

    private void editSelectedEntry() {
        int selectedIndex = entryList.getSelectedIndex();
        if (selectedIndex != -1) {
            JournalEntry entry = journalEntries.get(selectedIndex);
            titleField.setText(entry.getTitle());
            contentArea.setText(entry.getContent());
            tagField.setText(String.join(", ", entry.getTags()));

            journalEntries.remove(selectedIndex);
            entryListModel.remove(selectedIndex);
        } else {
            JOptionPane.showMessageDialog(null, "Please select an entry to edit.");
        }
    }

    private void exportEntries() {
        JFileChooser fileChooser = new JFileChooser();
        if (fileChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
                for (JournalEntry entry : journalEntries) {
                    writer.write(entry.toString());
                    writer.write("-----\n");
                }
                JOptionPane.showMessageDialog(null, "Entries exported successfully!");
            } catch (IOException e) {
                JOptionPane.showMessageDialog(null, "Error exporting entries: " + e.getMessage());
            }
        }
    }

    private void filterByTag() {
        String selectedTag = (String) tagFilterCombo.getSelectedItem();
        entryListModel.clear();
        if ("All".equals(selectedTag)) {
            journalEntries.forEach(entry -> entryListModel.addElement(entry.getTitle()));
        } else {
            journalEntries.stream()
                    .filter(entry -> entry.getTags().contains(selectedTag))
                    .forEach(entry -> entryListModel.addElement(entry.getTitle()));
        }
    }

    private void populateTagFilter() {
        Set<String> uniqueTags = new HashSet<>();
        journalEntries.forEach(entry -> uniqueTags.addAll(entry.getTags()));
        uniqueTags.forEach(tagFilterCombo::addItem);
    }

    private void saveJournalEntries() {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(JOURNAL_FILE))) {
            for (JournalEntry entry : journalEntries) {
                writer.write(entry.getTitle() + "\n");
                writer.write(entry.getContent() + "\n");
                writer.write(String.join(", ", entry.getTags()) + "\n");
                writer.write("-----\n");
            }
        } catch (IOException e) {
            JOptionPane.showMessageDialog(null, "Error saving entries: " + e.getMessage());
        }
    }

    private void loadJournalEntries() throws IOException {
        File file = new File(JOURNAL_FILE);
        if (file.exists()) {
            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                String title;
                while ((title = reader.readLine()) != null) {
                    String content = reader.readLine();
                    String tagsLine = reader.readLine();
                    Set<String> tags = new HashSet<>(Arrays.asList(tagsLine.split("\\s*,\\s*")));
                    journalEntries.add(new JournalEntry(title, content, tags));
                    entryListModel.addElement(title);
                    reader.readLine(); // Skip the separator line
                }
            }
        }
    }

    private void clearFields() {
        titleField.setText("");
        contentArea.setText("");
        tagField.setText("");
    }
}

Leave a comment