I'm trying to implement a GUI employee manager on Jswing where data is stored on a text file that I treat as my database and I created a GUI interface to interact with it.
Upon opening up the program, I'm able to use the remove feature and it works fine. But once I click the search button (table searches for values and only displays the values I searched for), and then when I try to remove something, it throws the error you see below.
This is the error I'm getting once I search for something:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 2 >= 2
at java.base/java.util.Vector.elementAt(Vector.java:466)
at java.desktop/javax.swing.table.DefaultTableModel.getValueAt(DefaultTableModel.java:660)
at java.desktop/javax.swing.JTable.getValueAt(JTable.java:2763)
at java.desktop/javax.swing.JTable.prepareRenderer(JTable.java:5780)
at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2210)
at java.desktop/javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2112)
at java.desktop/javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1908)
at java.desktop/javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:842)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1119)
at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5311)
at java.desktop/javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:246)
at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1337)
at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5259)
at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5069)
at
------------------EDIT----------------------
Here is my minimal reproducible code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import javax.swing.JTable;
import java.io.IOException; // Import the IOException class to handle errors
import java.io.File; // Import the File class
import java.io.FileNotFoundException; // Import this class to handle errors
import javax.swing.table.DefaultTableModel;
import java.io.FileWriter;
import javax.swing.event.*;
import javax.swing.table.*;
class UserManager extends JFrame implements ActionListener {
// Initializing class variables
private JTextField firstNameField, lastNameField, salaryField, textField;
private JButton addButton, removeButton, sortButton, button;
private JList<Employee> userList;
private ArrayList<Employee> users;
private JTable j;
private DefaultTableModel model;
private JTextField searchField;
/*****************************************
/*Name: UserManager (constructor)
/*Method Description: Constructor class that runs once upon creation of the object. Creates the frame of the GUI app. Pulls from the database and displays it on the GUI interface.
/*Method Inputs/Outputs: Outputs the GUI frame of the app.
******************************************/
public UserManager() {
setTitle("Employee Manager");
setSize(400, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// Initializing and binding action items
firstNameField = new JTextField(20);
lastNameField = new JTextField(20);
salaryField = new JTextField(20);
searchField = new JTextField(20);
addButton = new JButton("Add");
addButton.addActionListener(this);
removeButton = new JButton("Remove");
removeButton.addActionListener(this);
sortButton = new JButton("Sort Salary");
sortButton.addActionListener(this);
// Pulling data from text file database upon start up
ArrayList<ArrayList<String>> databaseData = ReadFile();
users = new ArrayList<Employee>();
// Adding existing databaseData to users
try {
if (databaseData.size() > 0) {
for (int i = 0; i < databaseData.size(); i++) {
Employee user = new Employee(databaseData.get(i).get(0), databaseData.get(i).get(1), Integer.valueOf(databaseData.get(i).get(2)));
users.add(user);
}
}
}
catch (NumberFormatException nfe) {
nfe.printStackTrace();
JOptionPane.showMessageDialog(this, "Internal System Error", "Error", JOptionPane.ERROR_MESSAGE);
}
// Creating the list of users
userList = new JList<Employee>(users.toArray(new Employee[0]));
// Setting up the JPanels
JPanel firstNamePanel = new JPanel();
firstNamePanel.add(new JLabel("First Name:"));
firstNamePanel.add(firstNameField);
JPanel lastNamePanel = new JPanel();
lastNamePanel.add(new JLabel("Last Name:"));
lastNamePanel.add(lastNameField);
JPanel salaryPanel = new JPanel();
salaryPanel.add(new JLabel("Salary:"));
salaryPanel.add(salaryField);
JPanel buttonPanel = new JPanel();
buttonPanel.add(addButton);
buttonPanel.add(removeButton);
buttonPanel.add(sortButton);
JPanel searchPanel = new JPanel();
// Converting 2D arraylist to normal 2D array for JTable
String[][] data = databaseData.stream().map(u -> u.toArray(new String[0])).toArray(String[][]::new);
// Initializing column names of JTable
String[] columnNames = { "FName", "LName", "Salary" };
// Initialize the JTable and TableModel
model = new DefaultTableModel(data, columnNames);
j = new JTable(model);
j.setBounds(1000, 1000, 900, 900);
// adding it to JScrollPane
JScrollPane table = new JScrollPane(j);
JLabel label = new JLabel("Search: ");
textField = new JTextField(20);
button = new JButton("Go");
searchPanel.add(label);
searchPanel.add(textField);
searchPanel.add(button);
button.addActionListener(this);
// Creating main panel and adding JPanels to it
JPanel mainPanel = new JPanel(new GridLayout(6, 2));
mainPanel.add(firstNamePanel);
mainPanel.add(lastNamePanel);
mainPanel.add(salaryPanel);
mainPanel.add(buttonPanel);
mainPanel.add(searchPanel);
mainPanel.add(table);
add(mainPanel);
}
/*****************************************
/*Method Name: actionPerformed
/*Method Description: Performs functions depending on what action is called. Adds users to the table and db if add button is clicked and removes users from the table and db if remove button is clicked.
/*Method Inputs/Outputs: Refreshes the table and outputs the new array with the updates.
******************************************/
public void actionPerformed(ActionEvent e) {
// "Add" button is clicked
if (e.getSource() == addButton) {
// Initializing and setting variables
String firstName = firstNameField.getText();
String lastName = lastNameField.getText();
int salary = 0;
// Checks to see if salary entered is an integer
try {
salary = Integer.parseInt(salaryField.getText());
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this, "Please enter a valid salary", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
// Error check to see if full name and age is entered
if (!firstName.equals("") && !lastName.equals("")) {
Employee user = new Employee(firstName, lastName, salary);
// Add the user to the arraylist
users.add(user);
// Creating new array with new information
String[] newEmployeeArr = {firstName, lastName, String.valueOf(salary)};
// Add new user to GUI
model.addRow(newEmployeeArr);
// Update user list
updateList(users);
// Resetting input fields
firstNameField.setText("");
lastNameField.setText("");
salaryField.setText("");
}
else {
JOptionPane.showMessageDialog(this, "Please enter a valid full name", "Error", JOptionPane.ERROR_MESSAGE);
}
}
// "Remove" button is clicked
else if (e.getSource() == removeButton) {
try {
if(j.getSelectedRow() != -1) {
// remove selected row from the model
String value = j.getValueAt(j.getSelectedRow(), 0).toString();
String value1 = j.getValueAt(j.getSelectedRow(), 1).toString();
String value2 = j.getValueAt(j.getSelectedRow(), 2).toString();
System.out.println(j.getSelectedRow() + " " + value + value1 + value2);
// Accounting for if the table was sorted and looking to see where the removed var is in the model
model.removeRow(removeUserFromTable(value, value1));
// finds the index of the user to remove
int selectedIndex = removeUser(value, value1, Integer.valueOf(value2));
// Error checks to see if valid user
if (selectedIndex != -1) {
// Remove the selected employee from the users arraylist
users.remove(selectedIndex);
JOptionPane.showMessageDialog(null, "Selected row deleted successfully");
// Update the list
updateList(users);
// Clear inputs
firstNameField.setText("");
lastNameField.setText("");
salaryField.setText("");
}
}
else {
JOptionPane.showMessageDialog(this, "Employee not selected.", "Error", JOptionPane.ERROR_MESSAGE);
}
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this, "Select a valid row.", "Error", JOptionPane.ERROR_MESSAGE);
}
}
// "Sort" button is clicked
else if (e.getSource() == sortButton) {
BubbleSort();
}
// "Go" button is clicked to search
else if (e.getSource() == button) {
// Creating a searching tool
TableRowSorter<TableModel> sorter = new TableRowSorter<>(model);
j.setRowSorter(sorter);
String text = textField.getText();
if (text.length() == 0) {
sorter.setRowFilter(null);
} else {
sorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
}
}
}
/*****************************************
/*Method Name: updateList
/*Method Description: Performs the update depending on what operation was made. Updates all lists inside the class and saves the change to the database.
/*Method Inputs/Outputs: The new list with the updated list is inputted and an updated database text file is the output.
******************************************/
private void updateList(ArrayList<Employee> u) {
userList.setListData(u.toArray(new Employee[0]));
// Log update to console
System.out.println("Updating Database");
// Overwriting db.txt file with new information
try {
// Making changes to the existed db.txt file
FileWriter fw = new FileWriter("db.txt", false);
// Loop through each student and write to the text file
for (int i = 0; i < u.size(); i++) {
// Re-writing the database file with the updates list
fw.write(toString(u.get(i).getFirstName(), u.get(i).getLastName(), u.get(i).getSalary()));
}
fw.close();
}
catch (IOException io) {
JOptionPane.showMessageDialog(this, "Internal System Error", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
}
/*****************************************
/*Method Name: removeUser
/*Method Description: Searches for the selected user in the users arraylist and finds the index if the user exists
/*Method Inputs/Outputs: The users arraylist and inputted user information is inputted and then outputs where the user is located in the array.
******************************************/
private int removeUser(String firstName, String lastName, int salary) {
// Loops through users arraylist
for (int i = 0; i < users.size(); i++) {
// If the user exists in the database, remove them
if (users.get(i).getFirstName().equals(firstName) && users.get(i).getLastName().equals(lastName) && users.get(i).getSalary() == salary) {
return i;
}
}
// No user by the name and salary was found
return -1;
}
/*****************************************
/*Method Name: removeUserFromTable
/*Method Description: Searches for the selected user in the table model and finds the index if the user exists
/*Method Inputs/Outputs: The user information is inputted and then outputs where the user is located in the model that controls the GUI table.
******************************************/
private int removeUserFromTable(String firstName, String lastName) {
int ind = 0;
for (int i = 0; i < model.getRowCount(); i++){
if (model.getValueAt(i, 0).toString().equals(firstName) && model.getValueAt(i, 1).toString().equals(lastName)) {
ind = i;
break;
}
}
return ind;
}
/*****************************************
/*Method Name: toString
/*Method Description: Converts three variables into one long string varaible
/*Method Inputs/Outputs: The user information is inputted and the string that contains all three variables is outputted.
******************************************/
public String toString(String firstName, String lastName, int salary) {
return firstName + ", " + lastName + ", " + salary + "\n";
}
/*****************************************
/*Method Name: BubbleSort
/*Method Description: Performs bubble sort on the employees by salary and then updates the jtable
/*Method Inputs/Outputs: No inputs or outputs, the JTable is updated
******************************************/
public void BubbleSort() {
try {
// Array to hold a copy of the users list
ArrayList<Employee> tempUsers = new ArrayList<Employee>();
// Adding all the initial users to the new array to perform bubble sort
for (int i =0; i < users.size(); i++) {
tempUsers.add(users.get(i));
}
// Performing bubble sort
for (int i = 0; i < users.size() - 1; i++) {
// Looping through indexes
for (int j = 0; j < users.size() - 1; j++) {
// Comapare the salaries of each indiviual and see if the previous is bigger than the next
if (users.get(j).getSalary() > users.get(j+1).getSalary()) {
// Initializing a temp employee to hold value before switching
Employee temp = users.get(j);
// Swap the employees
users.set(j, users.get(j+1));
users.set(j+1,temp);
}
}
}
int[] selection = j.getSelectedRows();
System.out.println(Arrays.toString(j.getSelectedRows()));
for (int i = 0; i < selection.length; i++) {
selection[i] = j.convertRowIndexToModel(selection[i]);
System.out.println(selection[i]);
}
// Setting the jtable model to the sorted model
j.setModel(model);
}
catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(this, "Not Enough Users", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
}
/*****************************************
/*Method Name: ReadFile
/*Method Description: Reads the db textfile and stores the values in a 2d arraylist for manipulation.
/*Method Inputs/Outputs: The 2d arraylist with all the db information is outputted
******************************************/
public static ArrayList<ArrayList<String>> ReadFile() {
try {
// Choose db.txt file to look at
File myObj = new File("db.txt");
// Create scanner object
Scanner myReader = new Scanner(myObj);
// Create 2d list array to hold all the single list arrays of single information
ArrayList<ArrayList<String>> combinedArr = new ArrayList<ArrayList<String>>();
// While the file reader is still reading lines in the text
while (myReader.hasNextLine()) {
// Read strings of text in txt file
String data = myReader.nextLine();
// Get user information into an array
ArrayList<String> temp = GetInfo(data);
// Add the person and their salary to the combined array that holds everyones
combinedArr.add(temp);
}
// Close file once there are no more lines to read
myReader.close();
return combinedArr;
}
catch (FileNotFoundException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
// Return invalid list string with nothing if error
ArrayList<ArrayList<String>> Invalid = new ArrayList<ArrayList<String>>();
return Invalid;
}
/*****************************************
/*Method Name: GetInfo
/*Method Description: Takes in a string of data and parses the three variables in it which are separated by commas
/*Method Inputs/Outputs: The data string that needs to be parsed is inputted and arraylist containuing the data from the string is outputted.
******************************************/
public static ArrayList<String> GetInfo(String data) {
String first = "";
String last = "";
String sal = "";
// System.out.println(data[0])
for (int i = 0; i < data.length(); i++) {
if (data.charAt(i) == ',') {
// Start from 2 indexes after the first occurance of the comma
for (int j = i+2; j < data.length(); j++) {
if (data.charAt(j) == ',') {
// Start from 2 indexes after the occurance of the comma
for (int n = j+2; n < data.length(); n++) {
sal += data.charAt(n);
}
break;
}
last += data.charAt(j);
}
break;
}
first += data.charAt(i);
}
// Initializing package array to send all values
ArrayList<String> arr = new ArrayList<String>();
arr.add(first);
arr.add(last);
arr.add(sal);
return arr;
}
/*****************************************
/*Method Name: main
/*Method Description: Runs the GUI frame
/*Method Inputs/Outputs: Ouputs the GUI
******************************************/
public static void main(String[] args) {
UserManager frame = new UserManager();
frame.setVisible(true);
}
}
class Employee {
// Initalizing variables
private String firstName;
private String lastName;
private int salary;
public Employee(String firstName, String lastName, int salary) {
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getSalary() {
return salary;
}
}
Instead of trying to treat your data and model as two seperate things, you should be wrapping your model around your data and allow to manage it, for example...
public class EmployeeTableModel extends AbstractTableModel {
private List<Employee> employees;
private String[] columnNames = {"FName", "LName", "Salary"};
private Class[] columnClasses = {String.class, String.class, Integer.class};
public EmployeeTableModel(List<Employee> employees) {
this.employees = employees;
}
public List<Employee> getEmployees() {
return employees;
}
public String[] getColumnNames() {
return columnNames;
}
public Class[] getColumnClasses() {
return columnClasses;
}
@Override
public int getRowCount() {
return getEmployees().size();
}
@Override
public int getColumnCount() {
return getColumnNames().length;
}
@Override
public String getColumnName(int column) {
return getColumnNames()[column];
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return getColumnClasses()[columnIndex];
}
public void sortBySalary() {
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
// This is decending...
return o2.getSalary() - o1.getSalary();
// This is acending
//return o1.getSalary() - o2.getSalary();
}
});
// You could use
//fireTableRowsUpdated(0, getRowCount() - 1);
// But this will work just fine and will force a complete
// redraw of the table
fireTableDataChanged();
}
public void sortByFirstName() {
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getFirstName().compareTo(o2.getFirstName());
}
});
fireTableDataChanged();
}
public void sortByLastName() {
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getLastName().compareTo(o2.getLastName());
}
});
fireTableDataChanged();
}
public void add(Employee employee) {
int rowCount = getRowCount();
getEmployees().add(employee);
fireTableRowsInserted(rowCount, rowCount);
}
public void delete(Employee employee) {
List<Employee> employees = getEmployees();
for (int index = 0; index < employees.size(); index++) {
if (employees.get(index).equals(employee)) {
employees.remove(index);
fireTableRowsDeleted(index, index);
break;
}
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Employee employee = getEmployees().get(rowIndex);
switch (columnIndex) {
case 0:
return employee.getFirstName();
case 1:
return employee.getLastName();
case 2:
return employee.getSalary();
}
throw new ArrayIndexOutOfBoundsException(rowIndex + "x" + columnIndex + " is out of bounds");
}
}
This is a pretty basic concept of a custom TableModel
. It takes in a List
of Employee
s and provides the core implementation of the TableModel
but also provides some helper methods, like add
and delete
which will trigger the appropriate events to allow a JTable
to update itself.
You could easily back this with a "database manager" instead, so that sort/delete/add/update actions would all be delegated to it and those updates could be made to the "database" values as well, but I'm going to leave that up to you to figure out.
Now, I separated your BubbleSort
into it's own, self contained and re-usable class...
public class BubbleSort {
public static <T> void sort(List<T> list, Comparator<? super T> comparator) {
// Performing bubble sort
for (int i = 0; i < list.size() - 1; i++) {
// Looping through indexes
for (int j = 0; j < list.size() - 1; j++) {
// Comapare the salaries of each indiviual and see if the previous is bigger than the next
if (comparator.compare(list.get(j), list.get(j + 1)) > 0) {
// Initializing a temp employee to hold value before switching
T temp = list.get(j);
// Swap the employees
list.set(j, list.get(j + 1));
list.set(j + 1, temp);
}
}
}
}
}
The only constraint is that you need to pass in a Comparator
which is used to compare the two values in order to determine if they should be swapped. "But why do this?" I hear you ask, because it's self contained and re-usable.
So, you want to sort by the salary right? Do you want to sort in ascending...
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getSalary() - o2.getSalary();
}
});
or decending order?
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o2.getSalary() - o1.getSalary();
}
});
Surprisingly, you can now do both, without much of an effort. But wait, what if you want to sort by the first name?!
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getFirstName().compareTo(o2.getFirstName());
}
});
or last name?!
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getLastName().compareTo(o2.getLastName());
}
});
See, re-usable.
You could even come with some combination of those, first name and salary, sure, doable, just write a new Comparator
. Want to sort some other type of value, sure, so long as you supply a compatible Comparator
, not a problem.
I've not bothered with your "database", as it's really not part of the problem, instead, I've focused on getting the table model and sorting to work together (and deleting, because you know, why not).
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import javax.swing.*;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import javax.swing.border.EmptyBorder;
import javax.swing.table.*;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private EmployeeTableModel employeeTableModel;
private JTable table;
public MainPane() {
Random rnd = new Random();
List<Employee> employees = new ArrayList<>(
Arrays.asList(
new Employee[]{
new Employee("Alesha", "Golden", rnd.nextInt(999) + 1),
new Employee("Gerald", "Guerrero", rnd.nextInt(999) + 1),
new Employee("Georgina", "Delacruz", rnd.nextInt(999) + 1),
new Employee("Michael", "Delgado", rnd.nextInt(999) + 1),
new Employee("Aysha", "Zimmerman", rnd.nextInt(999) + 1),
new Employee("Yahya", "Moreno", rnd.nextInt(999) + 1),
new Employee("Max", "Reyes", rnd.nextInt(999) + 1),
new Employee("Julia", "Salinas", rnd.nextInt(999) + 1),
new Employee("Aleeza", "Flores", rnd.nextInt(999) + 1),
new Employee("Milton", "Frye", rnd.nextInt(999) + 1),}
)
);
employeeTableModel = new EmployeeTableModel(employees);
table = new JTable(employeeTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table));
JButton sortBySalaryButton = new JButton("Sort by Salary");
sortBySalaryButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
employeeTableModel.sortBySalary();
}
});
JButton sortByFirstNameButton = new JButton("Sort by First name");
sortByFirstNameButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
employeeTableModel.sortByFirstName();
}
});
JButton sortLastNameButton = new JButton("Sort by Last name");
sortLastNameButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
employeeTableModel.sortByLastName();
}
});
// I'd normally use a SelectionListener to monitor
// changes to the table in order to enable/disable this
// button, but that's beyond the scope
JButton deleteButton = new JButton("Delete");
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = table.getSelectedRow();
if (selectedRow < 0) {
return;
}
Employee employee = employeeTableModel.getEmployeeAt(selectedRow);
employeeTableModel.delete(employee);
}
});
JPanel actionPane = new JPanel(new GridBagLayout());
actionPane.setBorder(new EmptyBorder(8, 8, 8, 8));
actionPane.add(sortBySalaryButton);
actionPane.add(sortByFirstNameButton);
actionPane.add(sortLastNameButton);
actionPane.add(deleteButton);
add(actionPane, BorderLayout.SOUTH);
}
}
class Employee {
// Initalizing variables
private String firstName;
private String lastName;
private int salary;
public Employee(String firstName, String lastName, int salary) {
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getSalary() {
return salary;
}
@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + Objects.hashCode(this.firstName);
hash = 59 * hash + Objects.hashCode(this.lastName);
hash = 59 * hash + this.salary;
return hash;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Employee)) {
return false;
}
Employee other = (Employee) obj;
return getFirstName().equals(other.getFirstName())
&& getLastName().equals(other.getLastName())
&& getSalary() == other.getSalary();
}
}
public class EmployeeTableModel extends AbstractTableModel {
private List<Employee> employees;
private String[] columnNames = {"FName", "LName", "Salary"};
private Class[] columnClasses = {String.class, String.class, Integer.class};
public EmployeeTableModel(List<Employee> employees) {
this.employees = employees;
}
public List<Employee> getEmployees() {
return employees;
}
public String[] getColumnNames() {
return columnNames;
}
public Class[] getColumnClasses() {
return columnClasses;
}
public Employee getEmployeeAt(int row) {
return getEmployees().get(row);
}
@Override
public int getRowCount() {
return getEmployees().size();
}
@Override
public int getColumnCount() {
return getColumnNames().length;
}
@Override
public String getColumnName(int column) {
return getColumnNames()[column];
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return getColumnClasses()[columnIndex];
}
public void sortBySalary() {
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
// This is decending...
return o2.getSalary() - o1.getSalary();
// This is acending
//return o1.getSalary() - o2.getSalary();
}
});
// You could use
//fireTableRowsUpdated(0, getRowCount() - 1);
// But this will work just fine and will force a complete
// redraw of the table
fireTableDataChanged();
}
public void sortByFirstName() {
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getFirstName().compareTo(o2.getFirstName());
}
});
fireTableDataChanged();
}
public void sortByLastName() {
BubbleSort.sort(getEmployees(), new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
return o1.getLastName().compareTo(o2.getLastName());
}
});
fireTableDataChanged();
}
public void add(Employee employee) {
int rowCount = getRowCount();
getEmployees().add(employee);
fireTableRowsInserted(rowCount, rowCount);
}
public void delete(Employee employee) {
List<Employee> employees = getEmployees();
for (int index = 0; index < employees.size(); index++) {
if (employees.get(index).equals(employee)) {
employees.remove(index);
fireTableRowsDeleted(index, index);
break;
}
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Employee employee = getEmployees().get(rowIndex);
switch (columnIndex) {
case 0:
return employee.getFirstName();
case 1:
return employee.getLastName();
case 2:
return employee.getSalary();
}
throw new ArrayIndexOutOfBoundsException(rowIndex + "x" + columnIndex + " is out of bounds");
}
}
public class BubbleSort {
public static <T> void sort(List<T> list, Comparator<? super T> comparator) {
// Performing bubble sort
for (int i = 0; i < list.size() - 1; i++) {
// Looping through indexes
for (int j = 0; j < list.size() - 1; j++) {
// Comapare the salaries of each indiviual and see if the previous is bigger than the next
if (comparator.compare(list.get(j), list.get(j + 1)) > 0) {
// Initializing a temp employee to hold value before switching
T temp = list.get(j);
// Swap the employees
list.set(j, list.get(j + 1));
list.set(j + 1, temp);
}
}
}
}
}
}