JPopupMenuがキー入力で開く位置を選択セル基準に変更する
Total: 87
, Today: 1
, Yesterday: 1
Posted by aterai at
Last-modified:
Summary
JTable
やJTree
に設定したJPopupMenu
がキー入力で開く場合、その表示位置が選択セル基準になるよう設定します。
Screenshot

Advertisement
Source Code Examples
class PopupLocationTable extends JTable {
private static final List<Integer> IGNORE_KEYS = Arrays.asList(
KeyEvent.VK_F1, KeyEvent.VK_F2, KeyEvent.VK_F3,
KeyEvent.VK_F4, KeyEvent.VK_F5, KeyEvent.VK_F6,
KeyEvent.VK_F7, KeyEvent.VK_F8, KeyEvent.VK_F9,
KeyEvent.VK_F10, KeyEvent.VK_F11, KeyEvent.VK_F12,
KeyEvent.VK_F13, KeyEvent.VK_F14, KeyEvent.VK_F15,
KeyEvent.VK_F16, KeyEvent.VK_F17, KeyEvent.VK_F18,
KeyEvent.VK_F19, KeyEvent.VK_F20, KeyEvent.VK_F21,
KeyEvent.VK_F22, KeyEvent.VK_F23, KeyEvent.VK_CONTEXT_MENU);
protected PopupLocationTable(int numRows, int numColumns) {
super(numRows, numColumns);
}
@Override public Point getPopupLocation(MouseEvent e) {
Rectangle r = getLeadSelectionCellRect();
boolean b = e == null && !r.isEmpty();
return b ? getKeyPopupLocation(r) : super.getPopupLocation(e);
}
@Override public boolean editCellAt(int row, int column, EventObject e) {
return !isIgnoreKeys(e) && super.editCellAt(row, column, e);
}
private Point getKeyPopupLocation(Rectangle r) {
double px = getCellSelectionEnabled()
? r.getMaxX()
: getBounds().getCenterX();
return new Point((int) px, (int) r.getMaxY());
}
private Rectangle getLeadSelectionCellRect() {
int row = getSelectionModel().getLeadSelectionIndex();
int col = getColumnModel().getSelectionModel().getLeadSelectionIndex();
return getCellRect(row, col, false);
}
private static boolean isIgnoreKeys(EventObject e) {
return e instanceof KeyEvent &&
IGNORE_KEYS.contains(((KeyEvent) e).getKeyCode());
}
}
final class TablePopupMenu extends JPopupMenu {
/* default */ TablePopupMenu() {
super();
JMenuItem check = new JCheckBoxMenuItem("setCellSelectionEnabled", true);
add(check).addActionListener(e -> {
boolean b = ((JCheckBoxMenuItem) e.getSource()).isSelected();
JTable table = (JTable) getInvoker();
table.setCellSelectionEnabled(b);
table.setRowSelectionAllowed(true);
});
add("clearSelectionAndLeadAnchor").addActionListener(e -> {
JTable table = (JTable) getInvoker();
clearSelectionAndLeadAnchor(table);
});
}
private static void clearSelectionAndLeadAnchor(JTable table) {
ListSelectionModel selectionModel = table.getSelectionModel();
ListSelectionModel colSelectionModel = table.getColumnModel().getSelectionModel();
selectionModel.setValueIsAdjusting(true);
colSelectionModel.setValueIsAdjusting(true);
table.clearSelection();
selectionModel.setAnchorSelectionIndex(-1);
selectionModel.setLeadSelectionIndex(-1);
colSelectionModel.setAnchorSelectionIndex(-1);
colSelectionModel.setLeadSelectionIndex(-1);
selectionModel.setValueIsAdjusting(false);
colSelectionModel.setValueIsAdjusting(false);
}
@Override public void show(Component c, int x, int y) {
if (c instanceof JTable) {
super.show(c, x, y);
}
}
}
View in GitHub: Java, KotlinDescription
JTable
上:- デフォルトの
JTable
でContextMenuキー(アプリケーションキー)やShift+F10キー入力でJPopupMenu
を開くと、セル選択状態に関係なく常にJTable
の中央にJPopupMenu
の左上が来るよう配置される - キー入力によるセル編集が可能な状態では、ContextMenuキー入力で
JPopupMenu
のオープンとセルの編集開始が同時に発生してしまう
- デフォルトの
JTable
下:JTable#getPopupLocation(MouseEvent)
をオーバーライドしてContextMenuキー入力でJPopupMenu
を開く場合はリード選択セルを基準になるよう設定- JPopupMenuをキー入力で開く場合の表示位置を調整する
JTable#getCellSelectionEnabled()
がtrue
でセル選択可能の場合はリード選択セルの右下がJPopupMenu
の左上となるよう配置JTable#getRowSelectionAllowed()
がtrue
で行選択可能の場合はリード選択行の左下中央下がJPopupMenu
の左上となるよう配置- リード選択セルが存在しない(
JTable#getCellRect(row, col, ...)
が空領域)場合はデフォルトのJTable
の中央がJPopupMenu
の左上となるよう配置
JTable#editCellAt(...)
をオーバーライドしてContextMenuキーやF1~F12キーなどでセルの編集を開始しないよう設定
JTree
上:- デフォルトの
JTree
でContextMenuキー(アプリケーションキー)やShift+F10キー入力でJPopupMenu
を開くと、セル選択状態に関係なく常にJTree
の中央にJPopupMenu
の左上となるよう配置される
- デフォルトの
JTree
下:JTree#getPopupLocation(MouseEvent)
をオーバーライドしてContextMenuキー入力でJPopupMenu
を開く場合はリード選択セルを基準になるよう設定- リード選択セルが存在する場合はその右下が
JPopupMenu
の左上となるよう配置 - リード選択セルが存在しない場合はデフォルトの
JTree
の中央がJPopupMenu
の左上となるよう配置
- リード選択セルが存在する場合はその右下が