Swing/ListEditor のバックアップ(No.2)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/ListEditor へ行く。
- 1 (2021-01-18 (月) 01:08:25)
- 2 (2021-02-15 (月) 13:35:15)
- 3 (2023-10-05 (木) 07:04:28)
- category: swing folder: ListEditor title: JListのセルに配置したJLabelのテキストを編集する tags: [JList, JTextField, GlassPane] author: aterai pubdate: 2021-01-18T01:08:02+09:00 description: JListのセル内に配置したJLabelのテキストを編集可能にするセルエディタを作成します。 image: https://drive.google.com/uc?id=1X7hqBD35R8ZX4XVDJ0ii4QO6hPgUK_Iz
概要
JList
のセル内に配置したJLabel
のテキストを編集可能にするセルエディタを作成します。
Screenshot
Advertisement
サンプルコード
class EditableList<E extends ListItem> extends JList<E> {
private transient MouseInputAdapter handler;
protected final Container glassPane = new EditorGlassPane();
protected final JTextField editor = new JTextField();
protected final Action startEditing = new AbstractAction() {
@Override public void actionPerformed(ActionEvent e) {
getRootPane().setGlassPane(glassPane);
int idx = getSelectedIndex();
ListItem item = getSelectedValue();
Rectangle rect = getCellBounds(idx, idx);
Point p = SwingUtilities.convertPoint(
EditableList.this, rect.getLocation(), glassPane);
rect.setLocation(p);
int h = editor.getPreferredSize().height;
rect.y = rect.y + rect.height - h - 1;
rect.height = h;
rect.grow(-2, 0);
editor.setBounds(rect);
editor.setText(item.title);
editor.selectAll();
glassPane.add(editor);
glassPane.setVisible(true);
editor.requestFocusInWindow();
}
};
protected final Action cancelEditing = new AbstractAction() {
@Override public void actionPerformed(ActionEvent e) {
glassPane.setVisible(false);
}
};
protected final Action renameTitle = new AbstractAction() {
@Override public void actionPerformed(ActionEvent e) {
ListModel<E> m = getModel();
String title = editor.getText().trim();
if (!title.isEmpty() && m instanceof DefaultListModel<?>) {
@SuppressWarnings("unchecked")
DefaultListModel<ListItem> model = (DefaultListModel<ListItem>) getModel();
int index = getSelectedIndex();
ListItem item = m.getElementAt(index);
model.remove(index);
model.add(index, new ListItem(editor.getText(), item.icon));
setSelectedIndex(index);
}
glassPane.setVisible(false);
}
};
protected EditableList(DefaultListModel<E> model) {
super(model);
editor.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
editor.setHorizontalAlignment(SwingConstants.CENTER);
// editor.setOpaque(false);
// editor.setLineWrap(true);
InputMap im = editor.getInputMap(JComponent.WHEN_FOCUSED);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "rename-title");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel-editing");
ActionMap am = editor.getActionMap();
am.put("rename-title", renameTitle);
am.put("cancel-editing", cancelEditing);
addMouseListener(new MouseAdapter() {
@Override public void mouseClicked(MouseEvent e) {
int idx = getSelectedIndex();
Rectangle rect = getCellBounds(idx, idx);
if (rect == null) {
return;
}
int h = editor.getPreferredSize().height;
rect.y = rect.y + rect.height - h;
rect.height = h;
boolean isDoubleClick = e.getClickCount() >= 2;
if (isDoubleClick && rect.contains(e.getPoint())) {
startEditing.actionPerformed(new ActionEvent(
e.getComponent(), ActionEvent.ACTION_PERFORMED, ""));
}
}
});
getInputMap(JComponent.WHEN_FOCUSED).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "start-editing");
getActionMap().put("start-editing", startEditing);
}
@Override public void updateUI() {
removeMouseListener(handler);
setSelectionForeground(null);
setSelectionBackground(null);
setCellRenderer(null);
super.updateUI();
setLayoutOrientation(JList.HORIZONTAL_WRAP);
getSelectionModel().setSelectionMode(
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
setVisibleRowCount(0);
setFixedCellWidth(56);
setFixedCellHeight(56);
setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
setCellRenderer(new ListItemListCellRenderer<>());
handler = new ClearSelectionListener();
addMouseListener(handler);
}
protected JTextComponent getEditorTextField() {
return editor;
}
private class EditorGlassPane extends JComponent {
protected EditorGlassPane() {
super();
setOpaque(false);
setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
@Override public boolean accept(Component c) {
return Objects.equals(c, getEditorTextField());
}
});
addMouseListener(new MouseAdapter() {
@Override public void mouseClicked(MouseEvent e) {
if (!getEditorTextField().getBounds().contains(e.getPoint())) {
renameTitle.actionPerformed(new ActionEvent(
e.getComponent(), ActionEvent.ACTION_PERFORMED, ""));
}
}
});
}
@Override public void setVisible(boolean flag) {
super.setVisible(flag);
setFocusTraversalPolicyProvider(flag);
setFocusCycleRoot(flag);
}
}
}
View in GitHub: Java, Kotlin解説
- 水平ニュースペーパー・スタイルレイアウトを設定した
JList
でアイテム(セル)のタイトル文字列を編集可能にするJList
デフォルトのセルを垂直方向に1
列に並べたレイアウトでセルを編集可能にする場合はヘッダを非表示にしたJTable
とTableCellEditor
で代用可能
- 選択したセルのタイトル文字列領域がダブルクリックされると
GlassPane
を表示 JTextField
に選択したセルのタイトル文字列を設定GlassPane
にJTextField
を配置してその位置とサイズをセルのタイトル文字列領域と同じになるよう変更JList
上にセルエディタとしてGlassPane
ごと表示JTextField
からフォーカスが移動したらGlassPane
を非表示に設定し、JTextField
のテキストを選択したセルのタイトル文字列に設定