Automatic add new row at the end of table

Automatic add new row at the end of table

ต้องการสร้าง JTable สำหรับ กรอกข้อมูล โดย

  • ไม่ต้องมีปุ่ม เพื่อ add new row,
  • ใช้วิธี detect ว่ามีการใส่ข้อมูลที่ row ว่างท้ายตารางหรือไม่ ถ้ามีให้เพิ่ม row ใหม่หลังจากนั้น
  • ถ้ามีการลบข้อมูลจนกลายเป็น row ว่าง ก็ให้ลบ row ว่างนั้นทิ้งไป
  • สร้าง table ด้วย TableModel
  • ให้มี column ที่แก้ไขได้ด้วย drowdown list
  • ให้ column ที่เหลือแก้ไขด้วย Text Field
  • เวลาแก้ไข เพียง click ที่ cell นั้นครั้งเดียวก็สามารถเข้า edit mode ได้เลย
  • สร้างเป็น JPanel เพื่อจะได้ Add ไปในตำแหน่งที่ต้องการ น่าจะดีกว่าสร้างเป็น JTable เพราะมันยังมีในส่วนของ TableModel ซึ่งอาจจะมีการใช้งานสลับกันไปมาได้ ดังนั้นมี container ซักอันครอบมันทั้งคู่ น่าจะดีกว่า – และ JPanel น่าจะดีที่สุด
tablePanel = new DrillTablePanel();
placeHolderPanel.add(tablePanel, BorderLayout.CENTER);
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;

/**
 *
 * @author Thada
 */
public class DrillTablePanel extends JPanel {
    
    private JTable table;
    private DefaultTableModel tableModel;

    public DrillTablePanel() {
        // ตั้งค่า Layout ของ Panel นี้
        super(new BorderLayout());

        // 1. กำหนดชื่อคอลัมน์และสร้าง TableModel
        String[] columnNames = {"Id", "Column Id", "Drill Type", "Quantity"};
        tableModel = new DefaultTableModel(columnNames, 0);

        // 2. สร้าง JTable
        table = new JTable(tableModel);
        table.setRowHeight(30);
        // 3. เรียกใช้เมธอดตั้งค่าต่างๆ ทั้งหมด
        addEmptyRow();
        setupCategoryColumn();
        setSingleClickEditing();
        setupTableModelListener();
        applyStyles();

        // 4. สร้าง JScrollPane และใส่ตารางเข้าไป
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setBorder(BorderFactory.createLineBorder(new Color(200, 200, 200)));

        // 5. เพิ่ม scrollPane เข้าไปใน Panel นี้
        this.add(scrollPane, BorderLayout.CENTER);
    }

    // --- Public methods (เผื่อคลาสข้างนอกต้องการข้อมูล) ---
    public JTable getTable() {
        return table;
    }

    public DefaultTableModel getTableModel() {
        return tableModel;
    }


    // --- Private helper methods (Logic ทั้งหมดถูกซ่อนไว้ที่นี่) ---

    private void applyStyles() {
        // จัดข้อความกึ่งกลาง
        DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
        centerRenderer.setHorizontalAlignment(JLabel.CENTER);

        TableColumnModel columnModel = table.getColumnModel();
        for (int i = 0; i < columnModel.getColumnCount(); i++) {
            columnModel.getColumn(i).setCellRenderer(centerRenderer);
        }

        // ตั้งค่าสีพื้นหลังและ Grid
        table.setBackground(new Color(245, 245, 245));
        table.setShowGrid(true);
        table.setGridColor(new Color(220, 220, 220));
    }

    private void addEmptyRow() {
        tableModel.addRow(new Object[tableModel.getColumnCount()]);
    }
    
    private void setupCategoryColumn() {
        TableColumn categoryColumn = table.getColumnModel().getColumn(2);
        String[] categories = {"", "Mechanical", "Laser", "Back Drill"};
        JComboBox<String> comboBox = new JComboBox<>(categories);
        categoryColumn.setCellEditor(new DefaultCellEditor(comboBox));
    }

    private void setSingleClickEditing() {
        DefaultCellEditor singleClickEditor = new DefaultCellEditor(new JTextField());
        singleClickEditor.setClickCountToStart(1);

        for (int i = 0; i < table.getColumnCount(); i++) {
            if (i != 2) {
                table.getColumnModel().getColumn(i).setCellEditor(singleClickEditor);
            }
        }
        ((DefaultCellEditor) table.getColumnModel().getColumn(2).getCellEditor()).setClickCountToStart(1);
    }
    
    private boolean isRowEmpty(int rowIndex) {
        for (int i = 0; i < tableModel.getColumnCount(); i++) {
            Object value = tableModel.getValueAt(rowIndex, i);
            if (value != null && !value.toString().trim().isEmpty()) {
                return false;
            }
        }
        return true;
    }

    private void setupTableModelListener() {
        tableModel.addTableModelListener(e -> {
            if (e.getType() != TableModelEvent.UPDATE) return;

            SwingUtilities.invokeLater(() -> {
                int row = e.getFirstRow();
                if (row >= tableModel.getRowCount()) return;

                if (row == tableModel.getRowCount() - 1) {
                    if (!isRowEmpty(row)) addEmptyRow();
                } else {
                    if (isRowEmpty(row)) {
                        int choice = JOptionPane.showConfirmDialog(
                                this, // อ้างอิงถึง Panel นี้
                                "Drill Information is empty, Do you want to remove row",
                                "Remove Row?",
                                JOptionPane.YES_NO_OPTION);
                        if (choice == JOptionPane.YES_OPTION) {
                            tableModel.removeRow(row);
                        }
                    }
                }
            });
        });
    }
}