如何使用javaFX创建透明窗口阶段?

时间:2016-06-19 17:50:36

标签: javafx-2 javafx-8 transparent aero-glass

我想制作一个透明的舞台,如下图(Windows 7)

that is windows 7 gadget window.. it looks like a fully glass

所以我尝试制作那种形式的screencapture方法..但它让人感到困惑......

这是我的代码,希望它可以更好地解释这个问题:

import javafx.application.*;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Demo extends Application{
    private static final double BLUR_AMOUNT = 7;
    private static final Effect myBlur = new BoxBlur(BLUR_AMOUNT, BLUR_AMOUNT, 3);
    private static final ImageView background = new ImageView();
    private static final StackPane layout = new StackPane();

    private Button btn=new Button("hello");

    @Override 
    public void start(Stage stage) {
        layout.getChildren().addAll(background,btn);
        layout.setStyle("-fx-background-color: null");

        Scene scene = new Scene(layout,300, 300,Color.TRANSPARENT);

        stage.initStyle(StageStyle.TRANSPARENT);
        stage.setScene(scene);
        stage.show();
        stage.setX(0);
        stage.setY(0);

        background.setImage(copyBackground(stage));
        background.setEffect(myBlur);

        makeDraggable(stage);
    }

    private static class Delta {
        double x,y;
    }

    public void makeDraggable(final Stage stage) {
        final Delta dragDelta = new Delta();
        btn.setOnMousePressed(mouseEvent -> {
            dragDelta.x = stage.getX() - mouseEvent.getScreenX();
            dragDelta.y = stage.getY() - mouseEvent.getScreenY();    
        });

        btn.setOnMouseDragged(mouseEvent -> {
            stage.setX(mouseEvent.getScreenX() + dragDelta.x);
            stage.setY(mouseEvent.getScreenY() + dragDelta.y);
            btn.setOpacity(0.0);
            background.setImage(copyBackground(stage));
        });

         btn.setOnMouseReleased(mouseEvent -> {
            btn.setOpacity(1.0);
        });
    }

    private Image copyBackground(Stage stage) {
        final int X = (int) stage.getX();
        final int Y = (int) stage.getY();
        final int W = (int) stage.getWidth();
        final int H = (int) stage.getHeight();

        try {
            java.awt.Robot robot = new java.awt.Robot();
            java.awt.image.BufferedImage image = robot.createScreenCapture(new java.awt.Rectangle(X, Y, W, H));

            return SwingFXUtils.toFXImage(image, null);
        } catch (java.awt.AWTException e) {
            System.out.println("The robot of doom strikes!");
            return null;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

1 个答案:

答案 0 :(得分:0)

您看到效果的原因是机器人正在拍摄部分屏幕的快照,包括您创建的窗口。此外,这个快照发生在舞台的xy属性发生变化之后但在窗口实际移动之前(因此在机器人之前"看到"效果改变的属性)。因此,您最终会生成不正确的图像。

一个简单的解决方法是在显示舞台之前对整个屏幕进行快照,然后在舞台移动(或更改大小)时更新应用于图像视图的视口:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.BoxBlur;
import javafx.scene.effect.Effect;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Demo extends Application{
    private static final double BLUR_AMOUNT = 7;
    private static final Effect myBlur = new BoxBlur(BLUR_AMOUNT, BLUR_AMOUNT, 3);
    private static final ImageView background = new ImageView();
    private static final StackPane layout = new StackPane();

    private Button btn=new Button("hello");

    @Override 
    public void start(Stage stage) {
        layout.getChildren().addAll(background,btn);
        layout.setStyle("-fx-background-color: null");

        Scene scene = new Scene(layout,300, 300,Color.TRANSPARENT);

        stage.initStyle(StageStyle.TRANSPARENT);
        stage.setScene(scene);
        stage.show();
        stage.setX(0);
        stage.setY(0);

        background.setImage(copyBackground(stage));

        background.viewportProperty().bind(Bindings.createObjectBinding(() -> 
            new Rectangle2D(stage.getX(), stage.getY(), stage.getWidth(), stage.getHeight()), 
            stage.xProperty(), stage.yProperty(), stage.widthProperty(), stage.heightProperty()));

        background.setEffect(myBlur);

        makeDraggable(stage);
    }

    private static class Delta {
        double x,y;
    }

    public void makeDraggable(final Stage stage) {
        final Delta dragDelta = new Delta();
        btn.setOnMousePressed(mouseEvent -> {
            dragDelta.x = stage.getX() - mouseEvent.getScreenX();
            dragDelta.y = stage.getY() - mouseEvent.getScreenY();    
        });

        btn.setOnMouseDragged(mouseEvent -> {
            stage.setX(mouseEvent.getScreenX() + dragDelta.x);
            stage.setY(mouseEvent.getScreenY() + dragDelta.y);
            btn.setOpacity(0.0);
//            background.setImage(copyBackground(stage));
        });

         btn.setOnMouseReleased(mouseEvent -> {
            btn.setOpacity(1.0);
        });
    }

    private Image copyBackground(Stage stage) {

        Rectangle2D screen = Screen.getPrimary().getBounds() ;

        final int X = (int) screen.getMinX();
        final int Y = (int) screen.getMinX();
        final int W = (int) screen.getWidth();
        final int H = (int) screen.getHeight();

        try {
            java.awt.Robot robot = new java.awt.Robot();
            java.awt.image.BufferedImage image = robot.createScreenCapture(new java.awt.Rectangle(X, Y, W, H));

            return SwingFXUtils.toFXImage(image, null);
        } catch (java.awt.AWTException e) {
            System.out.println("The robot of doom strikes!");
            return null;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

这里的缺点是图像不能代表独立于您的应用程序发生的对桌面的任何更改。一个可能的解决方法是使用WritableImage并在窗口更改位置时动态更新窗口覆盖的部分。这里的逻辑有点棘手,但也不算太差。