概要

GlassPaneを使用して、Lightbox風にアニメーションしながら画像を表示します。

サンプルコード

class LightboxGlassPane extends JPanel {
  private final ImageIcon image = new ImageIcon(
      LightboxGlassPane.class.getResource("test.png"));
  private final AnimeIcon animatedIcon = new AnimeIcon();
  private float alpha;
  private int w;
  private int h;
  private final Rectangle rect = new Rectangle();
  private Timer animator;
  private Handler handler;

  @Override public void updateUI() {
    removeMouseListener(handler);
    removeHierarchyListener(handler);
    super.updateUI();
    setOpaque(false);
    super.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    if (handler == null) {
      handler = new Handler();
    }
    addMouseListener(handler);
    addHierarchyListener(handler);
  }
  private class Handler extends MouseAdapter implements HierarchyListener {
    @Override public void mouseClicked(MouseEvent me) {
      me.getComponent().setVisible(false);
    }

    @Override public void hierarchyChanged(HierarchyEvent e) {
      if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0
          && !e.getComponent().isDisplayable() && animator != null) {
        animator.stop();
      }
    }
  }

  @Override public void setVisible(boolean isVisible) {
    boolean oldVisible = isVisible();
    super.setVisible(isVisible);
    JRootPane rootPane = getRootPane();
    if (rootPane != null && isVisible() != oldVisible) {
      rootPane.getLayeredPane().setVisible(!isVisible);
    }
    boolean b = animator == null || !animator.isRunning();
    if (isVisible && b) {
      w = 40;
      h = 40;
      alpha = 0f;
      animator = new Timer(10, new ActionListener() {
        @Override public void actionPerformed(ActionEvent e) {
          animatedIcon.next();
          repaint();
        }
      });
      animator.start();
    } else {
      if (animator != null) {
        animator.stop();
      }
    }
    animatedIcon.setRunning(isVisible);
  }

  @Override protected void paintComponent(Graphics g) {
    JRootPane rootPane = getRootPane();
    if (rootPane != null) {
      rootPane.getLayeredPane().print(g);
    }
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();

    if (h < image.getIconHeight() + 5 + 5) {
      h += image.getIconHeight() / 16;
    } else if (w < image.getIconWidth() + 5 + 5) {
      h  = image.getIconHeight() + 5 + 5;
      w += image.getIconWidth() / 16;
    } else if (alpha < 1f) {
      w  = image.getIconWidth() + 5 + 5;
      alpha = alpha + .1f;
    } else {
      animatedIcon.setRunning(false);
      animator.stop();
    }
    rect.setSize(w, h);
    Rectangle screen = getBounds();
    rect.setLocation(screen.x + screen.width / 2  - rect.width / 2,
                     screen.y + screen.height / 2 - rect.height / 2);

    g2d.setColor(new Color(100, 100, 100, 100));
    g2d.fill(screen);
    g2d.setColor(new Color(255, 255, 255, 200));
    g2d.fill(rect);

    if (alpha > 0) {
      if (alpha > 1f) {
        alpha = 1f;
      }
      g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
      g2d.drawImage(image.getImage(), rect.x + 5, rect.y + 5,
                    image.getIconWidth(),
                    image.getIconHeight(), this);
    } else {
      animatedIcon.paintIcon(
          this, g2d,
          screen.x + screen.width / 2  - animatedIcon.getIconWidth() / 2,
          screen.y + screen.height / 2 - animatedIcon.getIconHeight() / 2);
    }
    g2d.dispose();
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、JFrameGlassPaneを設定して、このGlassPaneの中央にインジケータ、高さ幅がアニメーションしながら拡大する矩形、画像を順番に表示しています。

  • 任意の場所のクリックで画像を非表示にするため、GlassPaneにマウスリスナーを追加してGlassPane#setVisible(false)を実行

参考リンク

コメント