Swing/MiniMap の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/MiniMap へ行く。
- Swing/MiniMap の差分を削除
--- category: swing folder: MiniMap title: JEditorPaneのミニマップを表示する tags: [JEditorPane, JScrollPane, JScrollBar, ImgeIcon, LayoutManager] tags: [JEditorPane, JScrollPane, JScrollBar, ImageIcon, LayoutManager] author: aterai pubdate: 2019-08-12T20:46:57+09:00 description: JEditorPaneのミニマップをImageIconで作成し、これをLayoutManagerを使用してJScrollPane上に重ねて表示します。 image: https://drive.google.com/uc?id=1_Ix_ksss07Sfpz-vM0rEWJ_yorOS9dX8 hreflang: href: https://java-swing-tips.blogspot.com/2019/08/create-minimap-of-jeditorpane-with.html lang: en --- * 概要 [#summary] `JEditorPane`のミニマップを`ImageIcon`で作成し、これを`LayoutManager`を使用して`JScrollPane`上に重ねて表示します。 #download(https://drive.google.com/uc?id=1_Ix_ksss07Sfpz-vM0rEWJ_yorOS9dX8) * サンプルコード [#sourcecode] #code(link){{ private final JEditorPane editor = new JEditorPane(); private final JScrollPane scroll = new JScrollPane(editor); private final JLabel label = new JLabel() { private transient MouseInputListener handler; @Override public void updateUI() { removeMouseListener(handler); removeMouseMotionListener(handler); super.updateUI(); handler = new MiniMapHandler(); addMouseListener(handler); addMouseMotionListener(handler); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Container c = SwingUtilities.getAncestorOfClass(JViewport.class, editor); if (!(c instanceof JViewport) || editor == null) { return; } JViewport vport = (JViewport) c; Rectangle vrect = vport.getBounds(); // scroll.getViewportBorderBounds(); Rectangle erect = editor.getBounds(); Rectangle crect = SwingUtilities.calculateInnerArea(this, new Rectangle()); Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); double sy = crect.getHeight() / erect.getHeight(); AffineTransform at = AffineTransform.getScaleInstance(1d, sy); // paint Thumb Rectangle thumbRect = new Rectangle(vrect); thumbRect.y = vport.getViewPosition().y; Rectangle r = at.createTransformedShape(thumbRect).getBounds(); int y = crect.y + r.y; g2.setColor(THUMB_COLOR); g2.fillRect(0, y, crect.width, r.height); g2.setColor(THUMB_COLOR.darker()); g2.drawRect(0, y, crect.width - 1, r.height - 1); g2.dispose(); } }; private class MiniMapHandler extends MouseInputAdapter { @Override public void mousePressed(MouseEvent e) { processMiniMapMouseEvent(e); } @Override public void mouseDragged(MouseEvent e) { processMiniMapMouseEvent(e); } protected final void processMiniMapMouseEvent(MouseEvent e) { Point pt = e.getPoint(); Component c = (Component) e.getComponent(); BoundedRangeModel m = scroll.getVerticalScrollBar().getModel(); int brm = m.getMaximum() - m.getMinimum(); int iv = (int) (.5 - m.getExtent() * .5 + pt.y * brm / (double) c.getHeight()); m.setValue(iv); } } // ... scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scroll.getVerticalScrollBar().getModel().addChangeListener(e -> label.repaint()); JPanel pp = new JPanel(new BorderLayout(0, 0)); pp.add(label, BorderLayout.NORTH); JScrollPane minimap = new JScrollPane(pp); minimap.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); minimap.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); Box box = Box.createHorizontalBox(); box.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); box.add(Box.createHorizontalGlue()); box.add(button); JPanel p = new JPanel() { @Override public boolean isOptimizedDrawingEnabled() { return false; } }; p.setLayout(new BorderLayout(0, 0) { @Override public void layoutContainer(Container parent) { synchronized (parent.getTreeLock()) { Insets insets = parent.getInsets(); int width = parent.getWidth(); int height = parent.getHeight(); int top = insets.top; int bottom = height - insets.bottom; int left = insets.left; int right = width - insets.right; Component ec = getLayoutComponent(parent, BorderLayout.EAST); if (Objects.nonNull(ec)) { Dimension d = ec.getPreferredSize(); JScrollBar vsb = scroll.getVerticalScrollBar(); int vsw = vsb.isVisible() ? vsb.getSize().width : 0; ec.setBounds(right - d.width - vsw, top, d.width, bottom - top); } Component cc = getLayoutComponent(parent, BorderLayout.CENTER); if (Objects.nonNull(cc)) { cc.setBounds(left, top, right - left, bottom - top); } } } }); p.add(minimap, BorderLayout.EAST); p.add(scroll); }} * 解説 [#explanation] - `JEditorPane`の縮小画像から`ImageIcon`を生成して`JLabel`に設定し、さらにスクロールバーを非表示にした`JScrollPane`に配置してミニマップを作成 -- [[JTabbedPaneのサムネイルをJToolTipで表示>Swing/TabThumbnail]] - `JEditorPane`を配置した`JScrollPane`とミニマップを配置した`JScrollPane`を重ねて配置する`LayoutManager`を使用 -- [[Component上に重ねて配置したダイアログの表示状態をアニメーション付きで切り替える>Swing/OverlayBorderLayout]] - ミニマップとして使用する`JLabel`に`MouseListener`を追加してマウスで表示位置を変更可能に設定 -- [[JLabelとIconで作成した検索位置表示バーをマウスで操作する>Swing/BoundedRangeModel]] * 参考リンク [#reference] - [[JLabelとIconで作成した検索位置表示バーをマウスで操作する>Swing/BoundedRangeModel]] - [[Component上に重ねて配置したダイアログの表示状態をアニメーション付きで切り替える>Swing/OverlayBorderLayout]] - [[JTabbedPaneのサムネイルをJToolTipで表示>Swing/TabThumbnail]] - [[JEditorPaneで選択した文字列の色反転を無効化>Swing/SelectedTextColor]] * コメント [#comment] #comment #comment