JTable#

Lecture Code Explanation#

This code creates a graphical user interface (GUI) application that displays and allows editing of a sample data table. Here’s a breakdown of the code:

Class and Variables:

  • The code defines a class Frame1 that extends javax.swing.JFrame. This means it creates a window with a frame border.

  • Several variables are declared to store data used throughout the program:

    • RNG: A Random object for generating random data.

    • Rows and Cols: Integers specifying the number of rows and columns in the data table.

    • mySampleData: A 2D String array to hold the sample data.

    • model: A DefaultTableModel object used as the data model for the JTable.

    • myTable: A JTable object representing the data table.

    • ALinputFields: An ArrayList of JTextField objects used for adding new records.

    • myColNames: An array of Strings containing the column names for the table.

    • City_Array: An array of Strings containing city names used in the program.

    • Several other variables are used to store UI layout properties and references to UI components.

Data Creation:

  • The CreateSampleData method generates random sample data. It populates the mySampleData array with first names, last names, cities, salaries, and unique IDs.

GUI Setup:

  • The initComponents method (generated by the GUI builder) initializes the Swing components used in the frame.

  • The Frame1 constructor performs most of the application logic:

    • Sets the frame size and location.

    • Calls CreateSampleData to generate sample data.

    • Calls setupDataModel to set up the data model for the table.

    • Calls SetUpMyTable to configure and display the JTable.

    • Calls other methods to add functionalities like:

      • A label to display data from a selected row (addDataLabel).

      • A button to delete a selected row (addDeleteButton).

      • A search bar to filter data (addSearch).

      • A checkbox to hide the ID column (hideIDColumn).

      • Input fields and a button to add new records (setupAddRecord).

Table Configuration (SetUpMyTable):

  • This method configures the JTable’s behavior and appearance:

    • Sets the table’s columns to automatically resize.

    • Enables sorting by clicking column headers.

    • Sets the table selection mode to single selection.

    • Attaches listeners to the table for selection changes and cell edits.

    • Makes the table editable.

    • Sets a custom renderer for the salary column to format the numbers.

    • Creates a scroll pane to hold the table and adds it to the frame.

Other Methods:

  • setupDataModel: Creates the data model for the JTable and specifies that all cells are editable.

  • addDataLabel: Creates and configures a label to display data from the selected row.

  • addDeleteButton: Creates and configures a button to delete the selected row. It ensures deletion by ID to avoid errors.

  • addSearch: Creates and configures a search bar to filter the table data based on user input.

  • filterRecords: Filters the table data based on the text entered in the search bar.

  • hideIDColumn: Creates and configures a checkbox to hide the ID column of the table.

  • setupAddRecord: Creates and configures input fields and a button to allow adding new records to the table.

  • SetupCityDropDown: Creates a dropdown menu in the city column to allow users to select pre-defined city names.

  • formatSalary: Sets a custom renderer for the salary column to format the numbers.

  • printArray: Prints the contents of the data model to the console for debugging purposes.

  • jmnuPrintActionPerformed: Handles the action when the “Print” menu item is clicked. It attempts to print the JTable using the default printing functionality.

Overall, this code demonstrates how to create a data table with functionalities like sorting, filtering, editing, adding new records, and basic printing using Swing components in Java.


class NumberTableCellRenderer#

This code defines a custom table cell renderer class named NumberTableCellRenderer that inherits from DefaultTableCellRenderer. It’s specifically designed to format table cell values as currency.

Here’s a breakdown of the code:

Class Inheritance:

  • The class NumberTableCellRenderer extends DefaultTableCellRenderer. This means it inherits all the functionalities of the default renderer and can override specific methods to customize the rendering behavior.

Constructor (NumberTableCellRenderer):

  • The constructor sets the horizontal alignment of the text in the cell to right-aligned (JLabel.RIGHT). This is commonly used for displaying numeric values.

Method: getTableCellRendererComponent:

  • This is the most important method in a custom cell renderer. It’s called whenever a cell needs to be rendered in the table.

  • It takes several arguments:

    • table: The JTable object.

    • value: The value of the object to be rendered in the cell.

    • isSelected: Whether the cell is currently selected.

    • hasFocus: Whether the cell has focus.

    • row: The row index of the cell.

    • column: The column index of the cell.

  • The method performs the following steps:

    • Tries to format the value as currency:

      • If the value is a Number object, it uses NumberFormat.getNumberInstance().format(value) to format it according to the current locale’s number formatting rules (e.g., commas for thousands separators).

      • If the value is a String, it attempts to parse it as an integer using Integer.parseInt(String.valueOf(value)). Then, it prepends a dollar sign (“$”) and formats the integer value using NumberFormat.getNumberInstance().format(ivalue).

    • Calls the super.getTableCellRendererComponent(...) method. This is important because it retrieves the base renderer component and applies any customizations we made (like setting the alignment) on top of the default behavior.

    • If any exception occurs during formatting (catch (Exception ez)), it returns null. This might indicate an issue with the data type or format, and the cell will likely be left blank.

Summary:

This custom renderer ensures that any numeric values displayed in the table are formatted as currency, improving readability and user experience.

image-20240416152944097

The Code#

/*
Programmer: James Goudy
Project: JTable
Date: April 19, 2024


 */
package j2_jtable_lecture_rev24;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.DefaultTableCellRenderer;
import java.text.NumberFormat;
import javax.swing.JCheckBox;
import javax.swing.RowFilter;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

class NumberTableCellRenderer extends DefaultTableCellRenderer {

    public NumberTableCellRenderer() {
        // Align the text right-justified within the table cell
        setHorizontalAlignment(JLabel.RIGHT);
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {

        try {
            // Check if the value is already a Number object
            if (value instanceof Number) {
                // Use the default number formatter to format the value
                value = NumberFormat.getNumberInstance().format(value);
            } else if (value instanceof String) {
                // If the value is a String, try to parse it to an integer
                int intValue = Integer.parseInt(String.valueOf(value));
                // Prepend a dollar sign ($) and format the integer value
                value = "$" + NumberFormat.getNumberInstance().format(intValue);
            } else {
                // If the value isn't a Number or a parsable String, keep it as is
            }

            // Call the superclass method to set other cell renderer properties
            return super.getTableCellRendererComponent(table, value, isSelected,
                    hasFocus, row, column);
        } catch (Exception exception) {
            // Handle potential exceptions during conversion or formatting
            // (e.g., NumberFormatException if the String cannot be parsed)
            // In this case, return null to indicate an error
            return null;
        }
    }
}

public class Frame1 extends javax.swing.JFrame {

    // Random number generator object
    Random RNG;

    // Define number of rows and columns in the data table
    int Rows = 50;
    int Cols = 5;

    // Create a 2D String array to hold the sample data
    String[][] mySampleData;

    // Default table data model object
    DefaultTableModel model;

    // JTable object representing the data table
    JTable myTable;

    // ArrayList to store JTextField objects used for adding new records
    ArrayList<JTextField> ALinputFields = new ArrayList();

    // Define column names for the table
    String[] myColNames = {
        "First Name", "Last Name", "City", "Salary", "ID"
    };

    // String array containing pre-defined city names
    String[] City_Array = {
        "Kalispell", "Polson", "Whitefish", "Missoula", "Helena",
        "Bozeman", "Chicago", "New York", "Seatle", "Rock Island"
    };

    // Text field for search functionality
    JTextField jtfSearch;

    // ListSelectionModel object to handle table selection
    ListSelectionModel mySelectModel;

    // Label to display data from the selected row
    JLabel jlblData;

    // Define initial Y positions for label components
    int RowLabel = 10;
    int Row1YPos = 40;
    int Row2YPos = 85;
    int Row3Ypos = 115;
    int Row4yYpos = 150;

    // Boolean flag to control ID column visibility
    Boolean showIdCol = true;

    public Frame1() {
        // Initialize Swing components using GUI builder (generated code)
        initComponents();

        // Set frame size and location
        this.setSize(700, 750);
        this.setLocationRelativeTo(null);
        
        // Set Frame Title
        this.setTitle("JTable - Create, Read, Update, Delete");

        // Generate random sample data
        createSampleData();

        // Setup data model for the table
        setupDataModel();

        // Configure and display the JTable
        SetUpMyTable();

        // Add label to display data from selected row
        addDataLabel(300);

        // Add button to delete the selected row
        addDeleteButton();

        // Add search functionality
        addSearch();

        // Add checkbox to hide the ID column
        hideIDColumn();

        // Add functionality to add new records
        setupAddRecord();
    }

    private void setupDataModel() {
        // Define data types for each column
        final Class[] columnClass = new Class[]{
            String.class, String.class,
            String.class, Integer.class, Integer.class
        };

        // Setup the data model with sample data and column names
        model = new DefaultTableModel(mySampleData, myColNames) {
            @Override
            public boolean isCellEditable(int row, int column) {
                // Allow editing all cells
                return true;
            }

            @Override
            public Class<?> getColumnClass(int columnIndex) {
                // Return the corresponding data type for each column
                return columnClass[columnIndex];
            }
        };

        // Create the JTable using the data model
        myTable = new JTable(model);
    }

    private void SetUpMyTable() {

        // Resize the columns automatically to fit their content
        myTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);

        // Enable sorting by clicking column headers
        myTable.setAutoCreateRowSorter(true);

        // Make the table visible and enabled
        myTable.setVisible(true);
        myTable.setEnabled(true);

        // Selection Options
        // ListSelectionModel.MULTIPLE_INTERVAL_SELECTION, 
        // ListSelectionModel.SINGLE_INTERVAL_SELECTION
        // ListSelectionModel.SINGLE_SELECTION
        // Set the selection mode to single selection 
        // (only one row can be selected at a time)
        myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        // Get the ListSelectionModel object associated with the table
        ListSelectionModel mySelectModel = myTable.getSelectionModel();

        // Add a listener for changes in row selection
        mySelectModel.addListSelectionListener(new ListSelectionListener() {

            @Override
            public void valueChanged(ListSelectionEvent e) {

                // Check if the selection change has finished 
                // (prevents firing multiple times)
                if (!e.getValueIsAdjusting()) {
                    int selectedRow = myTable.getSelectedRow();
                    String rowdata = "";

                    // If a row is selected, 
                    //build a string representation of its data
                    if (selectedRow != -1) {
                        for (int c = 0; c < Cols; c++) {
                            rowdata += myTable.getValueAt(selectedRow, c)
                                    .toString() + " ";
                        }
                    }
                    jlblData.setText(rowdata);
                }
            }
        });

        // Add a listener for changes
        // in the table model (for debugging purposes)
        myTable.getModel().addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                // Print the current table data (for testing)
                printArray();
            }
        });

        // Setup a dropdown menu for the "City" column
        setupCityDropDown();

        // Format the "Salary" column to display currency
        formatSalary();

        // Create a scroll pane to hold the table and add it to the frame
        JScrollPane myScrollPane = new JScrollPane(myTable);
        myScrollPane.setLocation(50, Row4yYpos);
        myScrollPane.setVisible(true);
        myScrollPane.setSize(600, 400);
        this.add(myScrollPane);
    }

    private void addDataLabel(int lblWidth) {
        // Create and configure the label to display data from the selected row
        jlblData = new JLabel();
        jlblData.setSize(lblWidth, 25);
        jlblData.setVisible(true);
        jlblData.setLocation(50, Row3Ypos);

        this.add(jlblData);
    }

    private void addDeleteButton() {

        // Define button width and height
        int btnWidth = 150;
        int btnHeight = 25;

        // Create a JButton for deleting the selected row
        JButton btnDelete = new JButton();

        // Set button text and make it visible
        btnDelete.setText("Delete Selected");
        btnDelete.setVisible(true);

        // Set button size and location
        btnDelete.setSize(btnWidth, btnHeight);
        btnDelete.setLocation(50, Row2YPos);

        // Add action listener to handle button clicks
        btnDelete.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {

                    // **Important:** Delete by a key 
                    // instead of selected row index
                    int selectedRow = myTable.getSelectedRow();

                    // Extract the unique key from the selected row 
                    // (assuming column 4 holds the key)
                    String selectedKey = myTable.getValueAt(selectedRow, 4)
                            .toString();

                    System.out.println("Key to be deleted: " + selectedKey);

                    // Loop through all rows in the table model
                    for (int row = 0; row < model.getRowCount(); row++) {
                        String currentKey = model.getValueAt(row, 4).toString();

                        // Compare current row's key with the selected key
                        if (currentKey.equals(selectedKey)) {
                            // If keys match, remove that row from the model
                            model.removeRow(row);
                            break; // Exit the loop after finding a match
                        }
                    }

                } catch (Exception exception) {
                    // Display an error message dialog if something goes wrong
                    JOptionPane.showMessageDialog(null, exception.getMessage());
                }

                // Refresh the table to reflect the changes
                myTable.repaint();
            }
        });

        // Add the button to the frame
        this.add(btnDelete);
    }

    private void addSearch() {

        // Define button width and height
        int btnWidth = 150;
        int btnHeight = 25;

        // Create a label for the search bar
        JLabel lblSearch = new JLabel();
        lblSearch.setText("Search");
        lblSearch.setVisible(true);
        lblSearch.setSize(btnWidth, btnHeight);
        lblSearch.setLocation(50 + btnWidth + 10, Row2YPos);

        // Add the search label to the frame
        this.add(lblSearch);

        try {
            // Create a text field for entering search terms
            jtfSearch = new JTextField();

            // Add a key listener to handle user input in the search bar
            jtfSearch.addKeyListener(new KeyListener() {

                @Override
                public void keyTyped(KeyEvent e) {
                    // Trigger search filtering whenever a key is typed
                    filterRecords();
                    // Request focus back to the search bar for usability
                    jtfSearch.requestFocus();
                }

                @Override
                public void keyPressed(KeyEvent e) {
                    // Not currently used, but reserved for potential key 
                    // press functionality
                    // Example: Handle 'Esc' to clear search
                    if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                        jtfSearch.setText("");
                        filterRecords();
                    }
                }

                @Override
                public void keyReleased(KeyEvent e) {
                    // Not currently used, but reserved 
                    // for potential key release functionality
                }
            });

            // Set the size and location of the search text field
            jtfSearch.setSize((int) (1 * btnWidth), btnHeight);
            jtfSearch.setVisible(true);
            jtfSearch.setLocation(50 + (int) (1.25 * btnWidth) + 20, Row2YPos);

            // Add the search text field to the frame
            this.add(jtfSearch);
        } catch (Exception e) {
            // Handle any potential exceptions 
            // during search component creation (optional)
        }
    }

    private void filterRecords() {

        // Request focus back to the search bar for usability
        jtfSearch.requestFocus();

        // Get the current text from the search bar
        String filterText = jtfSearch.getText();

        // Get the table row sorter object
        TableRowSorter<TableModel> sorter
                = (TableRowSorter) myTable.getRowSorter();

        // Create a regular expression filter based on the search text
        // This filters columns 0, 1, and 2 (adjust based on your search needs)
        sorter.setRowFilter(RowFilter.regexFilter(filterText, 0, 1, 2));

        // Refresh the table to reflect the filtered data
        myTable.repaint();
    }

    private void hideIDColumn() {

        // Define button width and height 
        int btnWidth = 150;
        int btnHeight = 25;

        // Create a checkbox to allow hiding the ID column
        JCheckBox chkHideID = new JCheckBox("Hide ID Column");
        chkHideID.setVisible(true);
        chkHideID.setSize(btnWidth, btnHeight);
        chkHideID.setLocation(420, Row2YPos);  // Adjust location as needed

        // Add action listener to handle checkbox selection changes
        chkHideID.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // Get the table column model
                TableColumnModel colModel = myTable.getColumnModel();

                // Get the column object for the ID column
                TableColumn colID = colModel.getColumn(4);

                // Set the column resizable
                colID.setResizable(true);

                /*
                 * IMPORTANT: Set minimum, maximum, 
                 * and preferred width before calling setWidth
                 * This ensures the column width changes 
                 * are applied correctly.
                 */
                int minWidth = 1;
                int maxWidth = 100;

                if (chkHideID.isSelected()) {
                    // Hide the ID column by setting 
                    // its width to a minimal value
                    colID.setMinWidth(minWidth);
                    colID.setMaxWidth(minWidth);
                    colID.setPreferredWidth(minWidth);
                    colID.setWidth(minWidth);
                } else {
                    // Show the ID column by setting 
                    // its width to a reasonable value
                    colID.setMinWidth(maxWidth);
                    colID.setMaxWidth(maxWidth);
                    colID.setPreferredWidth(maxWidth);
                    colID.setWidth(maxWidth);
                }

                // Refresh the table to reflect the changes
                myTable.repaint();
            }
        });

        // Add the checkbox to the frame
        this.add(chkHideID);
    }

    private void setupAddRecord() {

        // Define label positioning variables (x, y, width, height, spacing)
        int labelX = 50;
        int labelY = RowLabel;
        int labelWidth = 100;
        int labelHeight = 30;
        int labelSpacing = 10;

        // Define text field positioning variables
        int fieldX = 50;
        int fieldY = Row1YPos;
        int fieldWidth = 100;
        int fieldHeight = 30;
        int fieldSpacing = 10;

        // Labels for each input field
        String[] inputLabels = {
            "First Name", "Last Name", "City", "Salary"
        };

        // Create and position labels and text fields for each input
        for (int i = 0; i < inputLabels.length; i++) {
            JLabel label = new JLabel();
            label.setSize(labelWidth, labelHeight);
            label.setText(inputLabels[i]);
            label.setVisible(true);
            label.setLocation(labelX, labelY);

            JTextField inputField = new JTextField();
            inputField.setSize(fieldWidth, fieldHeight);
            // Initially set the text field value to an empty string
            inputField.setText("");
            inputField.setVisible(true);
            inputField.setLocation(fieldX, fieldY);

            // Add the text field to an ArrayList for easier access later
            ALinputFields.add(inputField);

            // Add the label and text field to the frame
            this.add(label);
            this.add(inputField);

            // Update positions for the next label and text field
            fieldX += fieldWidth + fieldSpacing;
            labelX += labelWidth + labelSpacing;
        }

        // Create and position the "Add" button
        JButton btnAdd = new JButton();
        btnAdd.setSize(fieldWidth, fieldHeight);
        btnAdd.setText("Add");
        btnAdd.setVisible(true);
        btnAdd.setLocation(fieldX, fieldY); // Use the last calculated positions

        // Add action listener to handle the "Add" button click
        btnAdd.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                addData();
            }

            private void addData() {
                // Check if the salary field contains a valid double value
                try {
                    Double.valueOf(ALinputFields.get(3).getText());
                } catch (Exception exception) {
                    // Display error message and clear the salary field
                    jlblData.setText("Error: " + exception.getMessage());
                    ALinputFields.get(3).setText("");
                    ALinputFields.get(3).requestFocus();
                    return;  // Exit the method if there's an error
                }

                // Check if all required fields 
                // (first name, last name, city) are filled
                if (ALinputFields.get(0).getText().length() != 0
                        && ALinputFields.get(1).getText().length() != 0
                        && ALinputFields.get(2).getText().length() != 0) {

                    // Create a new object array to hold the data for the new row
                    // Add space for the key
                    Object[] newData = new Object[ALinputFields.size() + 1];

                    // Copy data from text fields into the new data array
                    for (int i = 0; i < ALinputFields.size(); i++) {
                        newData[i] = ALinputFields.get(i).getText();
                    }

                    // Generate a unique key for the new record
                    String key = String.valueOf(ALinputFields.get(0).toString()
                            + ALinputFields.get(1).toString()
                            + ALinputFields.get(2).toString());

                    // Use a combination of hash and random number
                    // This ensures a unique key incase there are duplicate
                    // names and places
                    key = String.valueOf(Math.abs(key.hashCode()
                            + RNG.nextInt()));
                    newData[4] = key;

                    // Add the new row to the table model
                    model.addRow(newData);

                    // Clear all text fields after adding the data
                    for (int i = 0; i < ALinputFields.size(); i++) {
                        ALinputFields.get(i).setText("");
                    }

                    // Display success message
                    jlblData.setText("Record Added");
                }
            }
        });
    }

    private void setupCityDropDown() {

        // Get the "City" column from the table model
        // Assuming "City" is at index 2
        TableColumn cityColumn = myTable.getColumnModel().getColumn(2);

        // Create a combo box with city options
        JComboBox cityCombo = new JComboBox();
        for (int i = 0; i < City_Array.length; i++) {
            // Add each city from the City_Array to the combo box
            cityCombo.addItem(City_Array[i]);
        }

        // Set the cell editor for the "City" column to the combo box
        cityColumn.setCellEditor(new DefaultCellEditor(cityCombo));
        // This allows users to select a city from the dropdown in that column
    }

    private void formatSalary() {

        // Get the "Salary" column from the table model
        // Assuming "Salary" is at index 3
        TableColumn salaryColumn = myTable.getColumnModel().getColumn(3);

        // Set a cell renderer for the "Salary" column 
        // to display numbers in a specific format
        salaryColumn.setCellRenderer(new NumberTableCellRenderer());
        // This class typically formats numbers with commas for thousands separators.

        // **Alternative way to format numbers (commented out):**
        // DecimalFormat df = new DecimalFormat("###,###,###");
        // df.format(111222333);
        // You can use this approach if you need more control 
        // over the formatting (e.g., number of decimal places).
        // This creates a DecimalFormat object with a specific pattern 
        // and then uses it to format a number.
    }

    private void createSampleData() {

        // Declare variables for first name, last name, city, and salary
        String firstName, lastName, city;
        int salary = 0;
        // Create a Random object for generating random values
        RNG = new Random();

        // Define arrays for first names and last names
        String[] firstNameArray = {
            "Bob", "Jim", "Jane", "Jody", "Jill", "Tom", "Steve",
            "Sue", "Sara", "Dave", "Darla", "Deb", "Emily", "Joe",
            "Brian", "Rodney"
        };
        String[] lastNameArray = {
            "Rogers", "Smith", "Rodes",
            "Brady", "Gravey", "Knucles", "Heavers",
            "Harvey", "Brackman", "Graves", "Swanson"
        };

        // Sort the city array (assuming it's already defined)
        // Create a 2D String array to store sample data
        mySampleData = new String[Rows][Cols];

        // Fill the sample data array with random values
        for (int row = 0; row < Rows; row++) {

            // Get random first name, last name, 
            // and city from their respective arrays
            firstName = firstNameArray[RNG.nextInt(firstNameArray.length)];
            lastName = lastNameArray[RNG.nextInt(lastNameArray.length)];
            city = City_Array[RNG.nextInt(City_Array.length)];

            // Generate a random salary between 40,000 and 499,999
            salary = RNG.nextInt(500000) + 40000;

            // Assign values to the corresponding columns 
            // in the sample data array
            mySampleData[row][0] = firstName;
            mySampleData[row][1] = lastName;
            mySampleData[row][2] = city;
            // Convert salary to string
            mySampleData[row][3] = String.valueOf(salary);

            // Generate a unique key for the data row
            String key = String.valueOf(Math.abs(
                    (long) (firstName + lastName + city).hashCode()
                    + RNG.nextInt()));
            mySampleData[row][4] = key;
        }
    }

    /**
     * This method prints the contents of the table model to the console.
     */
    private void printArray() {

        // Loop through all rows and columns of the table model
        for (int row = 0; row < model.getRowCount(); row++) {
            for (int col = 0; col < model.getColumnCount(); col++) {
                // Get the value at the current row and column from the model
                Object value = model.getValueAt(row, col);
                // Print the value with a space separator
                System.out.print(value + " ");
            }
            // Print a new line after each row
            System.out.println("");
        }

        // Print a separator line for readability
        System.out.println("\n---------------\n");
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        jmnuPrint = new javax.swing.JMenuItem();
        jmuQuit = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jMenu1.setText("File");

        jmnuPrint.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P, java.awt.event.InputEvent.CTRL_DOWN_MASK));
        jmnuPrint.setText("Print");
        jmnuPrint.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jmnuPrintActionPerformed(evt);
            }
        });
        jMenu1.add(jmnuPrint);

        jmuQuit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q, java.awt.event.InputEvent.CTRL_DOWN_MASK));
        jmuQuit.setText("Quit");
        jmuQuit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jmuQuitActionPerformed(evt);
            }
        });
        jMenu1.add(jmuQuit);

        jMenuBar1.add(jMenu1);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 565, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 536, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jmnuPrintActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jmnuPrintActionPerformed
    {//GEN-HEADEREND:event_jmnuPrintActionPerformed

        // Create a JFrame window with the title "Printing"
        JFrame myFrame = new JFrame("Printing");

        // Set the frame to always stay on top of other windows
        myFrame.setAlwaysOnTop(true);

        try {
            // Attempt to print the table using the table's print method
            if (!myTable.print()) {
                // Printing was cancelled by the user
                System.err.println("User Cancelled Printing");

                // Display an error message dialog to the user
                JOptionPane.showMessageDialog(myFrame,
                        "User Cancelled Printing",
                        "User Cancelled Printing",
                        JOptionPane.ERROR_MESSAGE);
            }
        } catch (java.awt.print.PrinterException ex) {
            // An exception occurred during printing
            // Display an error message dialog with the exception message
            JOptionPane.showMessageDialog(myFrame,
                    ex.getMessage(),
                    "Printer Error",
                    JOptionPane.ERROR_MESSAGE);
        }


    }//GEN-LAST:event_jmnuPrintActionPerformed

    private void jmuQuitActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_jmuQuitActionPerformed
    {//GEN-HEADEREND:event_jmuQuitActionPerformed
        // Terminate the program with a successful exit code (0)
        System.exit(0);
    }//GEN-LAST:event_jmuQuitActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*
         * Set the Nimbus look and feel
         */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel.
         * For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Frame1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Frame1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Frame1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Frame1.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>
        //</editor-fold>
        //</editor-fold>
        //</editor-fold>
        //</editor-fold>
        //</editor-fold>
        //</editor-fold>
        //</editor-fold>

        /*
         * Create and display the form
         */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Frame1().setVisible(true);
            }
        });
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem jmnuPrint;
    private javax.swing.JMenuItem jmuQuit;
    // End of variables declaration//GEN-END:variables

}

Finished Application#

image-20240419134810913