Want a real-world Java project that teaches Swing, file I/O, table management, and more? Build this beautiful Java Expense Tracker and manage your daily spending like a pro!
๐ง What You’ll Build
โ
Add daily expenses (amount, category, note)
โ
View them in a table
โ
See total expense by category
โ
Export all entries to CSV
โ
100% Java, beginner-friendly, no frameworks!
๐ป Let’s Build: ExpenseTracker.java
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class ExpenseTracker extends JFrame {
private DefaultTableModel tableModel;
private JTable expenseTable;
private JTextField amountField, noteField;
private JComboBox<String> categoryBox;
public ExpenseTracker() {
setTitle("๐ธ Expense Tracker");
setSize(700, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
// Top panel for input
JPanel inputPanel = new JPanel(new GridLayout(2, 4, 10, 10));
amountField = new JTextField();
noteField = new JTextField();
categoryBox = new JComboBox<>(new String[]{"Food", "Transport", "Bills", "Entertainment", "Other"});
JButton addButton = new JButton("Add Expense");
inputPanel.add(new JLabel("Amount:"));
inputPanel.add(new JLabel("Category:"));
inputPanel.add(new JLabel("Note:"));
inputPanel.add(new JLabel(""));
inputPanel.add(amountField);
inputPanel.add(categoryBox);
inputPanel.add(noteField);
inputPanel.add(addButton);
// Table for expenses
tableModel = new DefaultTableModel(new String[]{"Amount", "Category", "Note", "Date"}, 0);
expenseTable = new JTable(tableModel);
JScrollPane tableScroll = new JScrollPane(expenseTable);
// Buttons
JButton totalButton = new JButton("View Totals");
JButton exportButton = new JButton("Export to CSV");
JPanel buttonPanel = new JPanel();
buttonPanel.add(totalButton);
buttonPanel.add(exportButton);
// Add components to frame
setLayout(new BorderLayout());
add(inputPanel, BorderLayout.NORTH);
add(tableScroll, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
// Action listeners
addButton.addActionListener(e -> addExpense());
totalButton.addActionListener(e -> showTotals());
exportButton.addActionListener(e -> exportToCSV());
setVisible(true);
}
private void addExpense() {
try {
double amount = Double.parseDouble(amountField.getText());
String category = categoryBox.getSelectedItem().toString();
String note = noteField.getText();
String date = new java.util.Date().toString();
tableModel.addRow(new Object[]{amount, category, note, date});
amountField.setText("");
noteField.setText("");
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "Enter a valid amount.");
}
}
private void showTotals() {
Map<String, Double> totals = new HashMap<>();
for (int i = 0; i < tableModel.getRowCount(); i++) {
String category = tableModel.getValueAt(i, 1).toString();
double amount = (double) tableModel.getValueAt(i, 0);
totals.put(category, totals.getOrDefault(category, 0.0) + amount);
}
StringBuilder result = new StringBuilder("Total Expenses by Category:\n");
for (String cat : totals.keySet()) {
result.append(cat).append(": โน").append(totals.get(cat)).append("\n");
}
JOptionPane.showMessageDialog(this, result.toString());
}
private void exportToCSV() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("Save as CSV");
int option = fileChooser.showSaveDialog(this);
if (option == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
try (PrintWriter writer = new PrintWriter(file)) {
// Write header
for (int i = 0; i < tableModel.getColumnCount(); i++) {
writer.print(tableModel.getColumnName(i) + (i < tableModel.getColumnCount() - 1 ? "," : ""));
}
writer.println();
// Write rows
for (int row = 0; row < tableModel.getRowCount(); row++) {
for (int col = 0; col < tableModel.getColumnCount(); col++) {
writer.print(tableModel.getValueAt(row, col) + (col < tableModel.getColumnCount() - 1 ? "," : ""));
}
writer.println();
}
JOptionPane.showMessageDialog(this, "Data exported successfully!");
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Error saving file.");
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(ExpenseTracker::new);
}
}
๐ Code Breakdown
๐ฏ addExpense()
double amount = Double.parseDouble(amountField.getText());
Takes user input and adds a new row to the table with the current timestamp.
๐ showTotals()
Map<String, Double> totals = new HashMap<>();
Loops through table rows, aggregates expenses by category using a map.
๐ exportToCSV()
PrintWriter writer = new PrintWriter(file);
Saves the table data to a
.csv
file you can open in Excel/Google Sheets.
๐งต Table Model
tableModel = new DefaultTableModel(new String[]{"Amount", "Category", "Note", "Date"}, 0);
Core of the data: dynamic table that updates in real time.
โ Extra Challenge Ideas
- Add a monthly filter
- Add a login screen
- Generate charts with JFreeChart
- Add delete/edit functionality for rows
- Save/load data with serialization
๐ก Why This Project is a Game-Changer
- Teaches practical Swing use
- Uses real-world data structures (Map, TableModel)
- Covers file export skills
- Shows date handling and input validation