概要

Robotを使用してスクリーンショット画像を取得して背景画像として描画することでJFrameを半透明に見せかけます。

スクリーンショット

Swing/ScreenCapture.png

サンプルコード

private final transient Robot robot;
private final Rectangle screenRect;
private final Rectangle buf = new Rectangle();
private transient BufferedImage backgroundImage;
private final float[] data = {
    .1f, .1f, .1f,
    .1f, .2f, .1f,
    .1f, .1f, .1f,
};
private Kernel kernel = new Kernel(3, 3, data);
private ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
private Color bgc = new Color(255, 255, 255, 100);

@Override protected void paintComponent(Graphics g) {
  super.paintComponent(g);
  Graphics2D g2 = (Graphics2D) g.create();
  Point pt = getLocationOnScreen();
  buf.setBounds(screenRect);
  SwingUtilities.computeIntersection(pt.x, pt.y, getWidth(), getHeight(), buf);
  Image img = backgroundImage.getSubimage(buf.x, buf.y, buf.width, buf.height);
  g2.drawImage(img, -Math.min(pt.x, 0), -Math.min(pt.y, 0), this);
  g2.setPaint(bgc);
  g2.fillRect(0, 0, getWidth(), getHeight());
  g2.dispose();
}

public void updateBackground() {
  backgroundImage = op.filter(robot.createScreenCapture(screenRect), null);
}
View in GitHub: Java, Kotlin

解説

上記のサンプルではRobot#createScreenCapture(...)メソッドを使用してデスクトップのスクリーンショットを取得してJPanelの背景として描画することでJFrameが半透明であるかのように表示しています。

  • Robot#createScreenCapture(...)で取得した画像にConvolveOpでぼかし効果を設定
  • JPanel#getLocationOnScreen()で取得した位置を左上にしてJPanelと同じ幅と高さの矩形Rectangleを作成
  • JFrameがスクリーンの外に配置されている場合などを除く必要があるため、SwingUtilities.computeIntersection(...)でこの矩形とスクリーンサイズとの共通矩形を取得
  • スクリーン画像からgetSubimage(...)で共通矩形の画像を取得
  • 共通矩形の画像をJPanelに背景として描画
    • たとえばJFrameの左辺がスクリーンの左辺の外に存在する(JPanel#getLocationOnScreen()で取得した位置がマイナスになる)場合は共通矩形の画像はJPanelより幅が短くなるので注意が必要
  • JFrameComponentListenerを追加して移動やリサイズで背景画像を再描画
  • JFrameWindowListenerを追加してアイコン化が解除されるとスクリーン画像を更新
  • たとえば別ウィンドウにフォーカス移動してその位置を変更したりマウスホイールなどでバックグラウンドのウィンドウを更新してもスクリーン画像は更新していないのでJFrameに描画している背景画像とずれが発生する

参考リンク

コメント