TitledBorderのタイトルを直接編集する
Total: 2313
, Today: 2
, Yesterday: 2
Posted by aterai at
Last-modified:
概要
TitledBorder
のタイトルをダブルクリックすると、GlassPane
に配置したJTextField
をその上に表示して文字列を編集可能にします。
Screenshot
Advertisement
サンプルコード
class EditableTitledBorder extends TitledBorder implements MouseListener {
protected final Container glassPane = new EditorGlassPane();
protected final JTextField editor = new JTextField();
protected final JLabel renderer = new JLabel();
protected final Rectangle rect = new Rectangle();
protected Component comp;
protected final Action startEditing = new AbstractAction() {
@Override public void actionPerformed(ActionEvent e) {
if (comp instanceof JComponent) {
Optional.ofNullable(((JComponent) comp).getRootPane())
.ifPresent(r -> r.setGlassPane(glassPane));
}
glassPane.add(editor);
glassPane.setVisible(true);
Point p = SwingUtilities.convertPoint(comp, rect.getLocation(), glassPane);
rect.setLocation(p);
rect.grow(2, 2);
editor.setBounds(rect);
editor.setText(getTitle());
editor.selectAll();
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) {
if (!editor.getText().trim().isEmpty()) {
setTitle(editor.getText());
}
glassPane.setVisible(false);
}
};
// ...
View in GitHub: Java, Kotlin解説
上記のサンプルでは、TitledBorder
のタイトルをマウスでダブルクリックするとGlassPane
に配置したJTextField
を重ねて表示されてタイトル文字列が編集可能になります。
- タイトル文字列をダブルクリックで編集開始
JTextField
にフォーカスがある状態でEnterキーを入力すると編集完了JTextField
にフォーカスがある状態でESCキーで編集をキャンセル
TitledBorder
のタイトルはJLabel
を使用して描画されているがprivate
なのでその位置やサイズの取得が不可- 以下のように
TitledBorder#paintBorder(...)
メソッドからJLabel
の位置とサイズを計算しているコードを抜き出してその領域を取得 - 所得した領域内でダブルクリックされたら編集を開始し
JTextField
の表示位置とサイズをその領域に合わせてGlassPane
上に表示
private Rectangle getTitleBounds(Component c, int x, int y, int width, int height) {
String title = getTitle();
if (Objects.nonNull(title) && !title.isEmpty()) {
Border border = getBorder();
int edge = border instanceof TitledBorder ? 0 : EDGE_SPACING;
JLabel label = getLabel(c);
Dimension size = label.getPreferredSize();
Insets insets = makeBorderInsets(border, c, new Insets(0, 0, 0, 0));
int labelY = y;
int labelH = size.height;
int position = getTitlePosition();
switch (position) {
case ABOVE_TOP:
insets.left = 0;
insets.right = 0;
break;
case TOP:
insets.top = edge + insets.top / 2 - labelH / 2;
if (insets.top >= edge) {
labelY += insets.top;
}
break;
case BELOW_TOP:
labelY += insets.top + edge;
break;
case ABOVE_BOTTOM:
labelY += height - labelH - insets.bottom - edge;
break;
case BOTTOM:
labelY += height - labelH;
insets.bottom = edge + (insets.bottom - labelH) / 2;
if (insets.bottom >= edge) {
labelY -= insets.bottom;
}
break;
case BELOW_BOTTOM:
insets.left = 0;
insets.right = 0;
labelY += height - labelH;
break;
default:
break;
}
insets.left += edge + TEXT_INSET_H;
insets.right += edge + TEXT_INSET_H;
int labelX = x;
int labelW = width - insets.left - insets.right;
if (labelW > size.width) {
labelW = size.width;
}
switch (getJustification(c)) {
case LEFT:
labelX += insets.left;
break;
case RIGHT:
labelX += width - insets.right - labelW;
break;
case CENTER:
labelX += (width - labelW) / 2;
break;
default:
break;
}
return new Rectangle(labelX, labelY, labelW, labelH);
}
return new Rectangle();
}