JTable表格数据展示编辑

wen java案例 2

本文目录导读:

JTable表格数据展示编辑

  1. 基本JTable创建
  2. 使用TableModel实现数据编辑
  3. 单元格编辑器定制
  4. 单元格渲染器定制
  5. 高级功能:多选和排序
  6. 注意事项

我来详细介绍Java Swing中JTable表格的数据展示和编辑功能。

基本JTable创建

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
public class JTableDemo extends JFrame {
    public JTableDemo() {
        setTitle("JTable示例");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 400);
        setLocationRelativeTo(null);
        // 创建表格数据
        String[] columnNames = {"ID", "姓名", "年龄", "性别", "部门"};
        Object[][] data = {
            {1, "张三", 28, "男", "技术部"},
            {2, "李四", 32, "女", "市场部"},
            {3, "王五", 25, "男", "人事部"},
            {4, "赵六", 30, "女", "财务部"}
        };
        // 创建表格
        JTable table = new JTable(data, columnNames);
        // 添加到滚动面板
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane, BorderLayout.CENTER);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new JTableDemo().setVisible(true);
        });
    }
}

使用TableModel实现数据编辑

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
// 自定义数据模型
class Employee {
    private int id;
    private String name;
    private int age;
    private String gender;
    private String department;
    private double salary;
    // 构造器、getter/setter
    public Employee(int id, String name, int age, String gender, String department, double salary) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.department = department;
        this.salary = salary;
    }
    // getter和setter方法
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getGender() { return gender; }
    public void setGender(String gender) { this.gender = gender; }
    public String getDepartment() { return department; }
    public void setDepartment(String department) { this.department = department; }
    public double getSalary() { return salary; }
    public void setSalary(double salary) { this.salary = salary; }
}
// 自定义表格模型
class EmployeeTableModel extends AbstractTableModel {
    private String[] columnNames = {"ID", "姓名", "年龄", "性别", "部门", "薪资"};
    private List<Employee> employees;
    private boolean[] editableColumns = {false, true, true, true, true, true}; // ID列不可编辑
    public EmployeeTableModel(List<Employee> employees) {
        this.employees = employees;
    }
    @Override
    public int getRowCount() {
        return employees.size();
    }
    @Override
    public int getColumnCount() {
        return columnNames.length;
    }
    @Override
    public String getColumnName(int column) {
        return columnNames[column];
    }
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Employee emp = employees.get(rowIndex);
        switch (columnIndex) {
            case 0: return emp.getId();
            case 1: return emp.getName();
            case 2: return emp.getAge();
            case 3: return emp.getGender();
            case 4: return emp.getDepartment();
            case 5: return emp.getSalary();
            default: return null;
        }
    }
    @Override
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
        Employee emp = employees.get(rowIndex);
        switch (columnIndex) {
            case 1: emp.setName((String) value); break;
            case 2: emp.setAge(Integer.parseInt(value.toString())); break;
            case 3: emp.setGender((String) value); break;
            case 4: emp.setDepartment((String) value); break;
            case 5: emp.setSalary(Double.parseDouble(value.toString())); break;
        }
        fireTableCellUpdated(rowIndex, columnIndex);
    }
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return editableColumns[columnIndex];
    }
    // 获取指定行的数据类型
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case 0: return Integer.class;
            case 2: return Integer.class;
            case 5: return Double.class;
            default: return String.class;
        }
    }
    public void addEmployee(Employee emp) {
        employees.add(emp);
        fireTableRowsInserted(employees.size() - 1, employees.size() - 1);
    }
    public void removeEmployee(int row) {
        employees.remove(row);
        fireTableRowsDeleted(row, row);
    }
}
// 使用示例
public class EditableJTableDemo extends JFrame {
    private EmployeeTableModel tableModel;
    private JTable table;
    public EditableJTableDemo() {
        setTitle("可编辑的JTable示例");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 500);
        setLocationRelativeTo(null);
        // 准备初始数据
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee(1, "张三", 28, "男", "技术部", 8000.0));
        employees.add(new Employee(2, "李四", 32, "女", "市场部", 7500.0));
        employees.add(new Employee(3, "王五", 25, "男", "人事部", 6500.0));
        // 创建表格模型和表格
        tableModel = new EmployeeTableModel(employees);
        table = new JTable(tableModel);
        // 设置表格属性
        table.setRowHeight(30);
        table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        table.getTableHeader().setFont(new Font("微软雅黑", Font.BOLD, 14));
        // 设置列宽
        table.getColumnModel().getColumn(0).setPreferredWidth(50);
        table.getColumnModel().getColumn(1).setPreferredWidth(100);
        table.getColumnModel().getColumn(5).setPreferredWidth(100);
        // 滚动面板
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane, BorderLayout.CENTER);
        // 控制面板
        JPanel controlPanel = new JPanel();
        JButton addBtn = new JButton("添加行");
        JButton deleteBtn = new JButton("删除选中行");
        JButton saveBtn = new JButton("保存数据");
        addBtn.addActionListener(e -> addRow());
        deleteBtn.addActionListener(e -> deleteSelectedRow());
        saveBtn.addActionListener(e -> saveData());
        controlPanel.add(addBtn);
        controlPanel.add(deleteBtn);
        controlPanel.add(saveBtn);
        add(controlPanel, BorderLayout.SOUTH);
    }
    private void addRow() {
        int newId = tableModel.getRowCount() + 1;
        Employee emp = new Employee(newId, "新员工", 20, "男", "待分配", 5000.0);
        tableModel.addEmployee(emp);
    }
    private void deleteSelectedRow() {
        int selectedRow = table.getSelectedRow();
        if (selectedRow != -1) {
            int confirmed = JOptionPane.showConfirmDialog(
                this, 
                "确认删除第 " + (selectedRow + 1) + " 行?", 
                "确认删除", 
                JOptionPane.YES_NO_OPTION
            );
            if (confirmed == JOptionPane.YES_OPTION) {
                tableModel.removeEmployee(selectedRow);
            }
        } else {
            JOptionPane.showMessageDialog(this, "请先选择要删除的行");
        }
    }
    private void saveData() {
        // 停止单元格编辑
        if (table.isEditing()) {
            table.getCellEditor().stopCellEditing();
        }
        // 这里可以保存数据到数据库或文件
        JOptionPane.showMessageDialog(this, "数据保存成功!");
        // 打印当前数据
        System.out.println("当前数据:");
        for (int i = 0; i < tableModel.getRowCount(); i++) {
            for (int j = 0; j < tableModel.getColumnCount(); j++) {
                System.out.print(tableModel.getValueAt(i, j) + "\t");
            }
            System.out.println();
        }
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new EditableJTableDemo().setVisible(true);
        });
    }
}

单元格编辑器定制

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.text.NumberFormat;
// 自定义单元格编辑器
public class CustomCellEditorDemo extends JFrame {
    public CustomCellEditorDemo() {
        setTitle("自定义单元格编辑器");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 400);
        setLocationRelativeTo(null);
        // 创建表格数据
        String[] columnNames = {"姓名", "年龄", "性别", "城市", "评分"};
        Object[][] data = {
            {"张三", 28, "男", "北京", 85.5},
            {"李四", 32, "女", "上海", 92.3},
            {"王五", 25, "男", "广州", 78.0}
        };
        JTable table = new JTable(data, columnNames);
        // 为性别列设置下拉框编辑器
        JComboBox<String> genderCombo = new JComboBox<>(new String[]{"男", "女"});
        TableColumn genderColumn = table.getColumnModel().getColumn(2);
        genderColumn.setCellEditor(new DefaultCellEditor(genderCombo));
        // 为年龄列设置数字限制
        TableColumn ageColumn = table.getColumnModel().getColumn(1);
        ageColumn.setCellEditor(new DefaultCellEditor(new JTextField()) {
            @Override
            public boolean stopCellEditing() {
                try {
                    String value = (String) getCellEditorValue();
                    int age = Integer.parseInt(value);
                    if (age < 0 || age > 150) {
                        throw new NumberFormatException();
                    }
                    return super.stopCellEditing();
                } catch (NumberFormatException e) {
                    JOptionPane.showMessageDialog(
                        CustomCellEditorDemo.this,
                        "请输入有效的年龄 (0-150)",
                        "输入错误",
                        JOptionPane.ERROR_MESSAGE
                    );
                    return false;
                }
            }
        });
        // 为城市列设置自动完成文本框
        JTextField cityField = new JTextField();
        TableColumn cityColumn = table.getColumnModel().getColumn(3);
        cityColumn.setCellEditor(new DefaultCellEditor(cityField));
        // 设置表格属性
        table.setRowHeight(30);
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new CustomCellEditorDemo().setVisible(true);
        });
    }
}

单元格渲染器定制

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
// 自定义单元格渲染器
public class CustomCellRendererDemo extends JFrame {
    public CustomCellRendererDemo() {
        setTitle("自定义单元格渲染器");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(600, 400);
        setLocationRelativeTo(null);
        // 创建表格数据
        String[] columnNames = {"姓名", "年龄", "性别", "成绩", "状态"};
        Object[][] data = {
            {"张三", 28, "男", 85, "及格"},
            {"李四", 32, "女", 45, "不及格"},
            {"王五", 25, "男", 92, "优秀"},
            {"赵六", 30, "女", 60, "及格"},
            {"钱七", 27, "男", 38, "不及格"}
        };
        JTable table = new JTable(data, columnNames);
        // 自定义成绩列渲染器
        TableColumn scoreColumn = table.getColumnModel().getColumn(3);
        scoreColumn.setCellRenderer(new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                    boolean isSelected, boolean hasFocus, int row, int column) {
                Component c = super.getTableCellRendererComponent(
                    table, value, isSelected, hasFocus, row, column);
                int score = (int) value;
                if (score >= 90) {
                    c.setBackground(new Color(144, 238, 144)); // 浅绿色
                    c.setForeground(Color.BLACK);
                } else if (score >= 60) {
                    c.setBackground(new Color(255, 255, 224)); // 浅黄色
                    c.setForeground(Color.BLACK);
                } else {
                    c.setBackground(new Color(255, 182, 193)); // 浅红色
                    c.setForeground(Color.RED);
                }
                if (isSelected) {
                    c.setBackground(c.getBackground().darker());
                }
                setHorizontalAlignment(CENTER);
                return c;
            }
        });
        // 自定义状态列渲染器
        TableColumn statusColumn = table.getColumnModel().getColumn(4);
        statusColumn.setCellRenderer(new StatusCellRenderer());
        // 自定义性别列显示
        TableColumn genderColumn = table.getColumnModel().getColumn(2);
        genderColumn.setCellRenderer(new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                    boolean isSelected, boolean hasFocus, int row, int column) {
                Component c = super.getTableCellRendererComponent(
                    table, value, isSelected, hasFocus, row, column);
                String gender = (String) value;
                if ("男".equals(gender)) {
                    setIcon(new ImageIcon("male_icon.png")); // 使用图标
                    setText("♂ " + gender);
                } else {
                    setIcon(new ImageIcon("female_icon.png"));
                    setText("♀ " + gender);
                }
                setHorizontalAlignment(CENTER);
                return c;
            }
        });
        // 交替行颜色
        table.setRowHeight(30);
        table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        // 设置表格外观
        table.setShowGrid(true);
        table.setGridColor(Color.LIGHT_GRAY);
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
    }
    // 自定义状态渲染器
    class StatusCellRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
            Component c = super.getTableCellRendererComponent(
                table, value, isSelected, hasFocus, row, column);
            String status = (String) value;
            switch (status) {
                case "优秀":
                    setBackground(new Color(0, 128, 0));
                    setForeground(Color.WHITE);
                    break;
                case "及格":
                    setBackground(new Color(255, 165, 0));
                    setForeground(Color.BLACK);
                    break;
                case "不及格":
                    setBackground(new Color(255, 0, 0));
                    setForeground(Color.WHITE);
                    break;
            }
            if (isSelected) {
                setBackground(setBackground.getDarker());
            }
            setHorizontalAlignment(CENTER);
            setFont(getFont().deriveFont(Font.BOLD));
            return c;
        }
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new CustomCellRendererDemo().setVisible(true);
        });
    }
}

高级功能:多选和排序

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.util.Comparator;
public class AdvancedJTableDemo extends JFrame {
    public AdvancedJTableDemo() {
        setTitle("高级JTable功能");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 500);
        setLocationRelativeTo(null);
        String[] columnNames = {"编号", "姓名", "年龄", "薪资", "入职日期"};
        Object[][] data = {
            {1, "张三", 28, 8000.0, "2023-01-15"},
            {2, "李四", 32, 9500.0, "2022-06-20"},
            {3, "王五", 25, 7000.0, "2024-03-01"},
            {4, "赵六", 30, 8800.0, "2023-09-10"}
        };
        DefaultTableModel model = new DefaultTableModel(data, columnNames) {
            @Override
            public Class<?> getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }
            @Override
            public boolean isCellEditable(int row, int column) {
                return column > 0; // 除了编号都可以编辑
            }
        };
        JTable table = new JTable(model);
        // 启用自动排序
        table.setAutoCreateRowSorter(true);
        // 设置选择模式
        table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        // 设置列宽
        table.getColumnModel().getColumn(0).setPreferredWidth(60);
        table.getColumnModel().getColumn(1).setPreferredWidth(100);
        table.getColumnModel().getColumn(2).setPreferredWidth(60);
        table.getColumnModel().getColumn(3).setPreferredWidth(100);
        table.getColumnModel().getColumn(4).setPreferredWidth(120);
        // 自定义排序器(按年龄排序时特殊处理)
        TableRowSorter<TableModel> sorter = new TableRowSorter<>(model);
        sorter.setComparator(2, (Integer o1, Integer o2) -> o1.compareTo(o2));
        table.setRowSorter(sorter);
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane, BorderLayout.CENTER);
        // 添加选择监听
        table.getSelectionModel().addListSelectionListener(e -> {
            if (!e.getValueIsAdjusting()) {
                int[] selectedRows = table.getSelectedRows();
                if (selectedRows.length > 0) {
                    StringBuilder sb = new StringBuilder("选中的行: ");
                    for (int row : selectedRows) {
                        int modelRow = table.convertRowIndexToModel(row);
                        sb.append("行").append(modelRow + 1).append(" ");
                    }
                    System.out.println(sb.toString());
                }
            }
        });
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new AdvancedJTableDemo().setVisible(true);
        });
    }
}

注意事项

  1. 性能优化:大数据量时使用虚拟模式
  2. 线程安全:Swing组件操作应在EDT线程中进行
  3. 数据验证:在setValueAt()中进行数据验证
  4. 模型-视图分离:尽量使用TableModel而非直接操作数据

这些示例涵盖了JTable的展示、编辑、自定义渲染和高级功能,可以根据具体需求进行调整和扩展。

抱歉,评论功能暂时关闭!