Swing/CursorOfCellComponent のバックアップの現在との差分(No.2)
- category: swing folder: CursorOfCellComponent title: JListのセル中に配置したコンポーネント毎にカーソルを変更する tags: [JList, Cursor, ListCellRenderer] author: aterai pubdate: 2013-10-21T00:16:35+09:00 description: JListのセルに配置されているコンポーネントをマウスの座標から検索し、それに設定されたカーソルをJListに適用します。 image:
概要
概要
JList
のセルに配置されているコンポーネントをマウスの座標から検索し、それに設定されたカーソルをJList
に適用します。
Screenshot
Advertisement
サンプルコード
サンプルコード
#spandel
JList<String> list = new JList<String>(model) {
#spanend
private LinkCellRenderer renderer;
#spanadd
class LinkCellList<E> extends JList<E> {
#spanend
private int prevIndex = -1;
protected LinkCellList(ListModel<E> model) {
super(model);
}
#spanadd
#spanend
@Override public void updateUI() {
setForeground(null);
setBackground(null);
setSelectionForeground(null);
setSelectionBackground(null);
super.updateUI();
renderer = new LinkCellRenderer();
setCellRenderer(renderer);
setFixedCellHeight(32);
setCellRenderer(new LinkCellRenderer<>());
// TEST: putClientProperty("List.isFileList", Boolean.TRUE);
}
private int prevIndex = -1;
#spanadd
#spanend
@Override protected void processMouseMotionEvent(MouseEvent e) {
Point pt = e.getPoint();
int i = locationToIndex(pt);
String s = ((ListModel<String>)getModel()).getElementAt(i);
E s = getModel().getElementAt(i);
Component c = getCellRenderer().getListCellRendererComponent(
this, s, i, false, false);
Rectangle r = getCellBounds(i, i);
c.setBounds(r);
if(prevIndex!=i) {
if (prevIndex != i) {
c.doLayout();
}
prevIndex = i;
pt.translate(-r.x, -r.y);
Component cmp = SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y);
if(cmp != null) {
setCursor(cmp.getCursor());
}else{
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
setCursor(
Optional.ofNullable(SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y))
.map(Component::getCursor)
.orElse(Cursor.getDefaultCursor()));
}
#spandel
};
#spanend
#spanadd
}
#spanend
View in GitHub: Java, Kotlin解説
解説
上記のサンプルでは、以下の手順でイベントを取得しないセルレンダラー中のコンポーネントに応じたカーソルの変更を行っています。-
JList
上をマウスカーソルを移動した時に、カーソルのある行を取得 -
JList
上をマウスカーソルを移動した時にカーソルのある行を取得 - セルレンダラーに行番号や文字列などの値を渡して描画用のコンポーネントを取得
- 描画用コンポーネントの位置とサイズを
JList#getCellBounds()
で取得したセル領域に変更Component#setBounds(...)
で描画用コンポーネントの位置とサイズを変更してもその子コンポーネントのレイアウトは更新されない
-
Component#doLayout()
で、レイアウトを更新- このサンプルで使用している
FlowLayout
では、JLabel
に設定する文字列の長さで後続のコンポーネントの位置が変化するので、Component#doLayout()
が必要
- このサンプルで使用している
-
Component#doLayout()
でレイアウトを更新- このサンプルで使用している
FlowLayout
ではJLabel
に設定する文字列の長さで後続のコンポーネントの位置が変化するのでComponent#doLayout()
を実行してレイアウトの更新を行う必要がある - ただし、同じ行の場合は描画用コンポーネントも前回と同じはずなのでレイアウトを更新する必要はない
- JListのセル内にJButtonを配置するなどのように、すべての行のレイアウトが同じ(内容に応じて変化しない)場合も同様に更新する必要はない
- このサンプルで使用している
-
JList
基準のカーソル座標を描画用コンポーネント基準に変更 -
SwingUtilities.getDeepestComponentAt(...);
で描画用コンポーネントから変更した座標の下にある子コンポーネントを取得- JListのセル内にJButtonを配置するのように、すべての行のレイアウトが同じ(内容に応じて変化しない)場合もレイアウトを更新する必要はない
-
JList
基準のカーソル位置座標を描画用コンポーネント基準に変更 -
SwingUtilities.getDeepestComponentAt(...)
メソッドで描画用コンポーネントから変更した座標の直下にある子コンポーネントを取得 - 取得した子コンポーネントのカーソルを
JList
のカーソルとして設定