繁体   English   中英

如何在 JTable 中的级联 JCombobox 选项中进行选择?

[英]How to do a selection in cascade of JCombobox choices in a JTable?

我有一个 JTable,数字 1,2,3 作为第一列,数字作为第二列中的文本,可以使用 JCombobox 进行选择。 例如,1 可以在第 2 列中表示为“1”、ONE、FIRST 或 ONCE。 当我做出选择时,下面行的所有组合框都必须使用相同性质的文本进行级联更新。 因此,如果我选择 ONCE,则下面各行的组合框应更新为 TWICE、THRICE。 如果我选择 FIRST,下面各行的组合框应更新为 SECOND、THIRD。 等等..

起初它看起来像是在工作,但每当我点击 JTable 上的其他位置时,combobox 就会更新为最后一行的值。 例如,如果我在第一行选择 ONCE,首先它会将其他行更新为 TWICE 和 THRICE。 然后,如果我单击任何一行,combobox 选择将在第一行更新为 THRICE。 下次单击时,第二行将更新为 THRICE。

我在这里做错了什么?

combobox 单元格编辑器:

public class NumberChoiceEditor extends DefaultCellEditor {

    private static final long serialVersionUID = 1L;

    private String numberAsText;

    private static final String[][] NUMBERS = { { "1", "ONE", "FIRST", "ONCE" }, { "2", "TWO", "SECOND", "TWICE" }, { "3", "THREE", "THIRD", "THRICE" } };

    public NumberChoiceEditor() {
        super(new JComboBox<>());
    }

    @Override
    public Object getCellEditorValue() {
        return numberAsText;
    }

    @Override
    public Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) {
        if (value instanceof String) {
            numberAsText = (String) value;
        }
        JComboBox<String> numberTextChoice = new JComboBox<>(NUMBERS[row]);
        numberTextChoice.setSelectedItem(numberAsText);
        numberTextChoice.addActionListener(e -> {
            numberAsText = (String) numberTextChoice.getSelectedItem();
            int nextRow = row + 1;
            if (nextRow < NUMBERS.length) {
                String numberText = (String) table.getValueAt(nextRow, 1);
                JComboBox<String> nextRowChoices = (JComboBox<String>) getTableCellEditorComponent(table, numberText, isSelected, nextRow, column);
                nextRowChoices.setSelectedIndex(numberTextChoice.getSelectedIndex());
                table.setValueAt(nextRowChoices.getSelectedItem(), nextRow, 1);
            }
        });
        return numberTextChoice;
    }

}

主要class配车架:

public class NumberTable {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JTable table = new JTable(new Object[][] { { 1, "1" }, { 2, "2" }, { 3, "3" } }, new Object[] { "Number", "Number Text" });
            table.getColumn("Number Text").setCellEditor(new NumberChoiceEditor());
            table.setRowHeight(25);
            JFrame frame = new JFrame("Number Table");
            frame.add(new JScrollPane(table));
            frame.setLocationRelativeTo(null);
            frame.setSize(600, 200);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        });
    }
}

我会使用TableModelListener 当通过JComboBox编辑器更改值时,我会相应地调整TableModel

(代码后的注释。)

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class NumTable implements Runnable, TableModelListener {
    private boolean  adjusting;
    private JFrame  frame;
    private JTable  table;

    @Override
    public void run() {
        createGui();
    }

    @Override
    public void tableChanged(TableModelEvent event) {
        if (!adjusting) {
            adjusting = true;
            int col = event.getColumn();
            if (col == 1) {
                NumChoiceEd editor = (NumChoiceEd) table.getColumnModel().getColumn(1).getCellEditor();
                int row = event.getFirstRow();
                JComboBox<String> combo = editor.getCombo(row);
                if (combo != null) {
                    int ndx = combo.getSelectedIndex();
                    if (ndx >= 0) {
                        int rows = table.getRowCount();
                        for (int i = 0; i < rows; i++) {
                            combo = editor.getCombo(i);
                            String val = combo.getModel().getElementAt(ndx);
                            table.setValueAt(val, i, col);
                        }
                    }
                }
            }
            adjusting = false;
        }
    }

    private void createGui() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(createTable(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JScrollPane createTable() {
        Object[][] data = new Object[][]{{1, "1"}, {2, "2"}, {3, "3"}};
        Object[] columnNames = new Object[]{"Number", "Number Text"};
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        model.addTableModelListener(this);
        table = new JTable(model);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        TableColumnModel tcm = table.getColumnModel();
        TableColumn column = tcm.getColumn(1);
        column.setCellEditor(new NumChoiceEd());
        JScrollPane scrollPane = new JScrollPane(table);
        return scrollPane;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new NumTable());
    }
}

class NumChoiceEd extends DefaultCellEditor {
    private static final long serialVersionUID = 1L;
    private JComboBox<String>  oneCombo;
    private JComboBox<String>  twoCombo;
    private JComboBox<String>  threeCombo;

    public NumChoiceEd() {
        super(new JComboBox<>());
        oneCombo = new JComboBox<>(new String[]{"1", "ONE", "FIRST", "ONCE"});
        twoCombo = new JComboBox<>(new String[]{"2", "TWO", "SECOND", "TWICE"});
        threeCombo = new JComboBox<>(new String[]{"3", "THREE", "THIRD", "THRICE"});
    }

    public JComboBox<String> getCombo(int row) {
        switch (row) {
            case 0:
                return oneCombo;
            case 1:
                return twoCombo;
            case 2:
                return threeCombo;
            default:
                return null;
        }
    }

    @Override
    public Component getTableCellEditorComponent(final JTable table,
                                                 final Object value,
                                                 final boolean isSelected,
                                                 final int row,
                                                 final int column) {
        if (column == 1) {
            switch (row) {
                case 0:
                    return oneCombo;
                case 1:
                    return twoCombo;
                case 2:
                    return threeCombo;
                default:
                    return super.getTableCellEditorComponent(table, value, isSelected, row, column);
            }
        }
        else {
            return super.getTableCellEditorComponent(table, value, isSelected, row, column);
        }
    }
}
  • 我不是在每次调用getTableCellEditorComponent方法时都创建一个新的JComboBox ,而是首先创建所有三个JComboBox并返回相关的一个。
  • 您不需要重写方法getCellEditorValue因为超类方法(在 class DefaultCellEditor中)将返回正确的值。
  • 一旦用户更改了值(并关闭了表格单元格编辑器),就会调用方法tableChanged In that method, I get the index of the value that was selected from the JComboBox and then I go through all the rows in the JTable and get the value at that index in the JComboBox for each row and set the JTable value to that value.
  • 因为我在方法tableChanged中更改了TableModel ,这将导致该方法再次被调用。 为了防止递归调用,我使用了adjusting标志。

在下面的屏幕截图中,我从JComboBox中选择了一个值,但我还没有关闭编辑器。 如果我导航到JTable中的另一个单元格,它将关闭编辑器,然后所有显示的数据都会改变。 请注意,如果您导航到不同行中的Number Text列,您可能看不到更改,因为这将立即打开您导航到的单元格的JComboBox编辑器。

编辑器打开

关闭编辑器后,表格如下面的屏幕截图所示。

编辑关闭

请注意,上述屏幕截图中有很多空白区域,因为JTable的默认尺寸非常大,但显示数据所需的空间(在这种情况下)很小。 使JTable更小(在这种情况下)的一种方法是更改JScrollPane的首选大小。

编辑

针对您在评论中提出的问题,即

是否可以更新 combobox 值更改

对的,这是可能的。 您向每个JComboBox添加一个ActionListener ,它只调用方法stopCellEditing 这是上面的代码,修改为包含ActionListener 唯一的变化是 class NumChoiceEd

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionListener;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class NumTable implements Runnable, TableModelListener {
    private boolean  adjusting;
    private JFrame  frame;
    private JTable  table;

    @Override
    public void run() {
        createGui();
    }

    @Override
    public void tableChanged(TableModelEvent event) {
        if (!adjusting) {
            adjusting = true;
            int col = event.getColumn();
            if (col == 1) {
                NumChoiceEd editor = (NumChoiceEd) table.getColumnModel().getColumn(1).getCellEditor();
                int row = event.getFirstRow();
                JComboBox<String> combo = editor.getCombo(row);
                if (combo != null) {
                    int ndx = combo.getSelectedIndex();
                    if (ndx >= 0) {
                        int rows = table.getRowCount();
                        for (int i = 0; i < rows; i++) {
                            combo = editor.getCombo(i);
                            String val = combo.getModel().getElementAt(ndx);
                            table.setValueAt(val, i, col);
                        }
                    }
                }
            }
            adjusting = false;
        }
    }

    private void createGui() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(createTable(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JScrollPane createTable() {
        Object[][] data = new Object[][]{{1, "1"}, {2, "2"}, {3, "3"}};
        Object[] columnNames = new Object[]{"Number", "Number Text"};
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        model.addTableModelListener(this);
        table = new JTable(model);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        TableColumnModel tcm = table.getColumnModel();
        TableColumn column = tcm.getColumn(1);
        column.setCellEditor(new NumChoiceEd());
        JScrollPane scrollPane = new JScrollPane(table);
        return scrollPane;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new NumTable());
    }
}

class NumChoiceEd extends DefaultCellEditor {
    private static final long serialVersionUID = 1L;
    private JComboBox<String>  oneCombo;
    private JComboBox<String>  twoCombo;
    private JComboBox<String>  threeCombo;

    public NumChoiceEd() {
        super(new JComboBox<>());
        ActionListener al = event -> NumChoiceEd.this.stopCellEditing(); // ADDED THIS LINE
        oneCombo = new JComboBox<>(new String[]{"1", "ONE", "FIRST", "ONCE"});
        oneCombo.addActionListener(al); // ADDED THIS LINE
        twoCombo = new JComboBox<>(new String[]{"2", "TWO", "SECOND", "TWICE"});
        twoCombo.addActionListener(al); // ADDED THIS LINE
        threeCombo = new JComboBox<>(new String[]{"3", "THREE", "THIRD", "THRICE"});
        threeCombo.addActionListener(al); // ADDED THIS LINE
    }

    public JComboBox<String> getCombo(int row) {
        switch (row) {
            case 0:
                return oneCombo;
            case 1:
                return twoCombo;
            case 2:
                return threeCombo;
            default:
                return null;
        }
    }

    @Override
    public Component getTableCellEditorComponent(final JTable table,
                                                 final Object value,
                                                 final boolean isSelected,
                                                 final int row,
                                                 final int column) {
        if (column == 1) {
            switch (row) {
                case 0:
                    return oneCombo;
                case 1:
                    return twoCombo;
                case 2:
                    return threeCombo;
                default:
                    return super.getTableCellEditorComponent(table, value, isSelected, row, column);
            }
        }
        else {
            return super.getTableCellEditorComponent(table, value, isSelected, row, column);
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM