簡體   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