• 追加された行はこの色です。
  • 削除された行はこの色です。
---
category: swing
folder: ListCellHyperlinkListener
title: JListのセルレンダラーとして設定したJEditorPaneからHyperlinkEventを取得する
tags: [JList, JEditorPane, ListCellRenderer, HyperlinkListener, MouseListener, Html]
author: aterai
pubdate: 2016-11-28T02:00:47+09:00
description: JListのセルレンダラーとして使用しているJEditorPaneに複数リンクを表示し、マウスクリックイベントを転送してHyperlinkEventが発生するように設定します。
image: https://drive.google.com/uc?export=view&id=1ZRAf_BbeW7l2RWn7LDGbJAZwkwtXgKZuuA
image: https://drive.google.com/uc?id=1ZRAf_BbeW7l2RWn7LDGbJAZwkwtXgKZuuA
---
* 概要 [#summary]
`JList`のセルレンダラーとして使用している`JEditorPane`に複数リンクを表示し、マウスクリックイベントを転送して`HyperlinkEvent`が発生するように設定します。

#download(https://drive.google.com/uc?export=view&id=1ZRAf_BbeW7l2RWn7LDGbJAZwkwtXgKZuuA)
#download(https://drive.google.com/uc?id=1ZRAf_BbeW7l2RWn7LDGbJAZwkwtXgKZuuA)

* サンプルコード [#sourcecode]
#code(link){{
DefaultListModel<SiteItem> m = new DefaultListModel<>();
m.addElement(new SiteItem("aterai",
  Arrays.asList("http://ateraimemo.com", "https://github.com/aterai")));
  Arrays.asList("https://ateraimemo.com", "https://github.com/aterai")));
m.addElement(new SiteItem("example",
  Arrays.asList("http://www.example.com", "https://www.example.com")));

JList<SiteItem> list = new JList<>(m);
list.setFixedCellHeight(120);
list.setCellRenderer(new SiteListItemRenderer());
list.addMouseListener(new MouseAdapter() {
  @Override public void mouseClicked(MouseEvent e) {
    Point pt = e.getPoint();
    int index = list.locationToIndex(pt);
    if (index >= 0) {
      SiteItem item = list.getModel().getElementAt(index);
      Component c = list.getCellRenderer().getListCellRendererComponent(
          list, item, index, false, false);
      if (c instanceof JEditorPane) {
        Rectangle r = list.getCellBounds(index, index);
        c.setBounds(r);
        pt.translate(-r.x, -r.y);
        c.dispatchEvent(new MouseEvent(
            c, e.getID(), e.getWhen(), e.getModifiers() | e.getModifiersEx(),
            pt.x, pt.y, e.getClickCount(), e.isPopupTrigger()));
        MouseEvent me = SwingUtilities.convertMouseEvent(list, e, c);
        me.translatePoint(pt.x - r.x - me.getX(), pt.y - r.y - me.getY());
        c.dispatchEvent(me);
        // pt.translate(-r.x, -r.y);
        // c.dispatchEvent(new MouseEvent(
        //     c, e.getID(), e.getWhen(), e.getModifiers() | e.getModifiersEx(),
        //     pt.x, pt.y, e.getClickCount(), e.isPopupTrigger()));
      }
    }
  }
});
}}

* 解説 [#explanation]
上記のサンプルでは、`JList`に設定した`MouseListener`のクリックイベントをその`ListCellRenderer`として使用している`JEditorPane`に`dispatchEvent`で転送し、`HyperlinkListener`でリンククリックイベントが取得できるように設定しています。

- `MouseEvent`は、そのクリック位置を`JList`から`JEditorPane`相対に変更する必要がある
-- `SwingUtilities.convertMouseEvent(list, e, editor)`ではうまく変換できないので、自前で位置を変換し、`new MouseEvent(...)`でイベントを作り直している
- `MouseEvent`はそのクリック位置を`JList`から`JEditorPane`相対に変更する必要がある
- `SwingUtilities.convertMouseEvent(list, e, editor)`でマウスイベントのソースをセルエディタに変換し、座標は`MouseEvent#translatePoint(...)`メソッドを使用してセルエディタ相対に変換

* 参考リンク [#reference]
- [[JListのセル中に配置したコンポーネント毎にカーソルを変更する>Swing/CursorOfCellComponent]]
-- `JList`からセルレンダラーへの座標返還は、こちらと同じものを使用
-- `JList`からセルレンダラーへの座標変換はこちらと同じものを使用

* コメント [#comment]
#comment
#comment