JListのセルに配置したJLabelのテキストを編集する
Total: 1986
, Today: 1
, Yesterday: 1
Posted by aterai at
Last-modified:
概要
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
で代用可能JFileChooser
(FilePane
)で使用されるListView
はJList
で作成されているが、名前がTree.cellEditor
のJTextField
がファイル名変更用セルエディタとして利用可能
- 選択したセルのタイトル文字列領域がダブルクリックされると
GlassPane
を表示 JTextField
に選択したセルのタイトル文字列を設定GlassPane
にJTextField
を配置してその位置とサイズをセルのタイトル文字列領域と同じになるよう変更JList
上にセルエディタとしてGlassPane
ごと表示JTextField
からフォーカスが移動したらGlassPane
を非表示に設定し、JTextField
のテキストを選択したセルのタイトル文字列に設定
参考リンク
- JTabbedPaneのタブタイトルを変更
- JListのアイテムをフィルタリングして表示
- JListのモデルをソートする
- JTextAreaとJFrameで幅固定、文字列の折り返し、親枠外まで高さ拡大可能なセルエディタを作成する
- JFileChooserのセルエディタでリネームを開始したとき拡張子を除くファイル名を選択状態にする