使用JCombobox编辑器的JTable:处理鼠标点击

时间:2015-12-15 08:46:20

标签: java swing combobox jtable tablecelleditor

我有一个带有JCombobox编辑器的JTable用于特定列。

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;

public class TablePanel extends JPanel {

    public TablePanel() {
        JTable table = new JTable(new MyTableModel());
        setComboboxColumn(table.getColumnModel().getColumn(1));
        add(new JScrollPane(table));
    }

    public void setComboboxColumn(TableColumn cbColumn) {
        JComboBox<String> comboBox = new JComboBox<>();
        comboBox.addItem("Item 1");
        comboBox.addItem("Item 2");
        comboBox.addItem("Item 3");
        cbColumn.setCellEditor(new DefaultCellEditor(comboBox));
    }

    private static class MyTableModel extends AbstractTableModel {

        private String[] columnNames = {"Normal cell", "Combobox cell"};
        private Object[][] data = {
                {"Cell 1", "Item 2"},
                {"Cell 2", "Item 1"},
                {"Cell 3", "Item 1"},
                {"Cell 4", "Item 3"},
        };

        @Override
        public int getColumnCount() {
            return columnNames.length;
        }
        @Override
        public int getRowCount() {
            return data.length;
        }
        @Override
        public String getColumnName(int col) {
            return columnNames[col];
        }
        @Override
        public Object getValueAt(int row, int col) {
            return data[row][col];
        }
        @Override
        public Class getColumnClass(int c) {
            return getValueAt(0, c).getClass();
        }
        @Override
        public boolean isCellEditable(int row, int col) {
            return true;
        }
        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            data[rowIndex][columnIndex] = aValue;
        }
    }

    public static void main(String[] args) {

        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("TablePanel");
                frame.getContentPane().add(new TablePanel());
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

现在发生了什么:

  • 当我第一次在该列的单元格上单击时,组合框弹出窗口会立即显示。
  • 如果我点击同一列的其他单元格,组合框会显示但弹出窗口仍然关闭。
  • 如果我点击其他单元格然后再返回该列的单元格,则组合框弹出窗口会立即显示。

我想要的是什么:

  • 首先点击该列的单元格:组合框显示,但弹出列表仍然关闭。
  • 再次点击同一单元格:弹出列表显示。

我知道我可以使用cellEditor.setClickCountToStart(2),但在这种情况下,必须在第一次点击之后的短时间内执行第二次点击,我希望避免此限制。

1 个答案:

答案 0 :(得分:1)

来自BasicComboPopup.Handler#mousePressed(...)

public void mousePressed(MouseEvent e) {
  if (e.getSource() == list) {
    return;
  }
  if (!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled())
    return;
  //...
  togglePopup();
}

您可以使用AncestorListener

  • 首次点击该列的单元格combobox.isEnabled()==false时,请勿显示弹出窗口,稍后AncestorListener#ancestorAdded()拨打combobox.setEnabled(true)
  • 再次点击相同的单元格:combobox.isEnabled()==true,弹出窗口显示。
  • 如果点击其他单元格:AncestorListener#ancestorRemoved()请致电combobox.setEnabled(false)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;

public class ComboBoxCellEditorTogglePopupTest {
  private JComboBox<String> makeComboBox() {
    JComboBox<String> combobox = new JComboBox<>();
    combobox.addItem("Item 1");
    combobox.addItem("Item 2");
    combobox.addItem("Item 3");
    return combobox;
  }
  public JComponent makeUI() {
    String[] columnNames = {"Default", "setEnabled", "String"};
    Object[][] data = {
      {"Item 1", "Item 1", "aaa"}, {"Item 2", "Item 3", "bbb"}
    };
    JTable table = new JTable(new DefaultTableModel(data, columnNames));
    table.setRowHeight(20);

    table.getColumnModel().getColumn(0).setCellEditor(
        new DefaultCellEditor(makeComboBox()));

    final JComboBox<String> combobox = makeComboBox();
    combobox.setEnabled(false);
    combobox.addAncestorListener(new AncestorListener() {
      @Override public void ancestorAdded(AncestorEvent e) {
        System.out.println("ancestorAdded");
        EventQueue.invokeLater(new Runnable() {
          @Override public void run() {
            combobox.setEnabled(true);
          }
        });
      }
      @Override public void ancestorRemoved(AncestorEvent e) {
        System.out.println("ancestorRemoved");
        combobox.setEnabled(false);
      }
      @Override public void ancestorMoved(AncestorEvent e) {}
    });
    table.getColumnModel().getColumn(1).setCellEditor(
        new DefaultCellEditor(combobox));

    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(table));
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new ComboBoxCellEditorTogglePopupTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}