JavaFX 对背景的影响
Posted
技术标签:
【中文标题】JavaFX 对背景的影响【英文标题】:JavaFX effect on background 【发布时间】:2014-05-05 00:19:41 【问题描述】:我正在使用this 制作带有毛玻璃效果的ios 主题JavaFX2 (Java7) 应用程序。问题是这段代码在 ImageView 上使用了它的效果。我希望它对窗户后面的任何东西都使用它的效果,如下所示:
有没有办法做到这一点?我还想要你在上图中看到的那种小的阴影效果。
明确地说,我不想要那个滑块或任何东西,只是能够透过窗户看到并在边缘有轻微阴影的效果。不过,我想使用 this iOS7-ish effect 而不是 aero。
这可能很重要:我使用的是 Undecorator 的修改版本。
【问题讨论】:
【参考方案1】:import javafx.animation.*;
import javafx.application.*;
import javafx.beans.property.*;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.effect.*;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.image.*;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public class FrostyTech extends Application
private static final double BLUR_AMOUNT = 10;
private static final Effect frostEffect =
new BoxBlur(BLUR_AMOUNT, BLUR_AMOUNT, 3);
private static final ImageView background = new ImageView();
private static final StackPane layout = new StackPane();
@Override public void start(Stage stage)
layout.getChildren().setAll(background, createContent());
layout.setStyle("-fx-background-color: null");
Scene scene = new Scene(
layout,
200, 300,
Color.TRANSPARENT
);
Platform.setImplicitExit(false);
scene.setOnMouseClicked(event ->
if (event.getClickCount() == 2) Platform.exit();
);
makeSmoke(stage);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.show();
background.setImage(copyBackground(stage));
background.setEffect(frostEffect);
makeDraggable(stage, layout);
// copy a background node to be frozen over.
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!");
e.printStackTrace();
return null;
// create some content to be displayed on top of the frozen glass panel.
private Label createContent()
Label label = new Label("Create a new question for drop shadow effects.\n\nDrag to move\n\nDouble click to close");
label.setPadding(new Insets(10));
label.setStyle("-fx-font-size: 15px; -fx-text-fill: green;");
label.setMaxWidth(250);
label.setWrapText(true);
return label;
// makes a stage draggable using a given node.
public void makeDraggable(final Stage stage, final Node byNode)
final Delta dragDelta = new Delta();
byNode.setOnMousePressed(mouseEvent ->
// record a delta distance for the drag and drop operation.
dragDelta.x = stage.getX() - mouseEvent.getScreenX();
dragDelta.y = stage.getY() - mouseEvent.getScreenY();
byNode.setCursor(Cursor.MOVE);
);
final BooleanProperty inDrag = new SimpleBooleanProperty(false);
byNode.setOnMouseReleased(mouseEvent ->
byNode.setCursor(Cursor.HAND);
if (inDrag.get())
stage.hide();
Timeline pause = new Timeline(new KeyFrame(Duration.millis(50), event ->
background.setImage(copyBackground(stage));
layout.getChildren().set(
0,
background
);
stage.show();
));
pause.play();
inDrag.set(false);
);
byNode.setOnMouseDragged(mouseEvent ->
stage.setX(mouseEvent.getScreenX() + dragDelta.x);
stage.setY(mouseEvent.getScreenY() + dragDelta.y);
layout.getChildren().set(
0,
makeSmoke(stage)
);
inDrag.set(true);
);
byNode.setOnMouseEntered(mouseEvent ->
if (!mouseEvent.isPrimaryButtonDown())
byNode.setCursor(Cursor.HAND);
);
byNode.setOnMouseExited(mouseEvent ->
if (!mouseEvent.isPrimaryButtonDown())
byNode.setCursor(Cursor.DEFAULT);
);
private javafx.scene.shape.Rectangle makeSmoke(Stage stage)
return new javafx.scene.shape.Rectangle(
stage.getWidth(),
stage.getHeight(),
Color.WHITESMOKE.deriveColor(
0, 1, 1, 0.08
)
);
/** records relative x and y co-ordinates. */
private static class Delta
double x, y;
public static void main(String[] args)
launch(args);
相关问题
Frosted Glass Effect in JavaFX? How do I create a JavaFX transparent stage with shadows on only the border?【讨论】:
大声笑。你又做了一次:D。还好我在赏金结束前几秒钟就奖励了你。我吓坏了。 嘿!我这样做是为了让您可以在 FrostyPane 顶部加载任何节点,并在窗口不在焦点时关闭模糊(以使其始终保持一致)。我有几个问题: 1. 我删除了将所有内容暂停 50 毫秒的代码,它仍然可以正常工作。有什么我想念的吗? 2. 拖动窗口会重新启动我正在进行的所有功能。例如,当我移动窗口时,我的启动画面会重新启动。有什么办法吗?另外,有什么方法可以轻松实现调整大小?我想我可以应付,但我只是想知道你是否知道任何捷径。 很遗憾,如果背景发生变化,玻璃效果将不会重绘。否则,看起来很棒。 @jewelsea 第 69 行“末日机器人来袭!” xaxaxaxa +100【参考方案2】:你想要的OS依赖窗口装饰的视觉效果,只能通过OS提供的API来实现。因而被下面的StageStyle.TRANSPARENT
淘汰了。
对于 JavaFX 内容本身,您可以控制 stage > scene > root pane
层次结构的视觉效果。舞台和场景不(也不旨在)支持高级样式,因此通过在下面设置为透明来消除。
@Override
public void start(Stage primaryStage)
StackPane root = new StackPane();
root.setStyle("-fx-background-color: null;");
root.setPadding(new Insets(10));
DoubleProperty doubleProperty = new SimpleDoubleProperty(0);
Region region = new Region();
region.styleProperty().bind(Bindings
.concat("-fx-background-radius:20; -fx-background-color: rgba(56, 176, 209, ")
.concat(doubleProperty)
.concat(");"));
region.setEffect(new DropShadow(10, Color.GREY));
Slider slider = new Slider(0, 1, .3);
doubleProperty.bind(slider.valueProperty());
root.getChildren().addAll(region, slider);
primaryStage.initStyle(StageStyle.TRANSPARENT);
Scene scene = new Scene(root, 300, 250);
scene.setFill(Color.TRANSPARENT);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
但是,阴影效果不能很好地与背景颜色的 alpha 值配合使用。您可以通过将阴影的颜色更改为另一种对比色来观察它。
输出:
【讨论】:
这个答案也是正确的。我该如何对他们俩说“是”...?【参考方案3】:要扩展 Jewlsea 的答案 .. 并将上面的示例与 JavaFX 一起使用 ..
虽然这些类不是公共 API,但它确实完全避免了 AWT 堆栈。 这是一个非公开示例:
// copy a background node to be frozen over.
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();
final Screen screen = Screen.getPrimary();
try
Robot rbt = com.sun.glass.ui.Application.GetApplication().createRobot();
Pixels p = rbt.getScreenCapture(
(int)screen.getBounds().getMinX(),
(int)screen.getBounds().getMinY(),
(int)screen.getBounds().getWidth(),
(int)screen.getBounds().getHeight(),
true
);
WritableImage dskTop = new WritableImage((int)screen.getBounds().getWidth(), (int)screen.getBounds().getHeight());
dskTop.getPixelWriter().setPixels(
(int)screen.getBounds().getMinX(),
(int)screen.getBounds().getMinY(),
(int)screen.getBounds().getWidth(),
(int)screen.getBounds().getHeight(),
PixelFormat.getByteBgraPreInstance(),
p.asByteBuffer(),
(int)(screen.getBounds().getWidth() * 4)
);
WritableImage image = new WritableImage(W,H);
image.getPixelWriter().setPixels(0, 0, W, H, dskTop.getPixelReader(), X, Y);
return image;
catch (Exception e)
System.out.println("The robot of doom strikes!");
e.printStackTrace();
return null;
添加了小阴影的结果:
DropShadow shdw = new DropShadow();
shdw.setBlurType(BlurType.GAUSSIAN);
shdw.setColor(Color.GAINSBORO);
shdw.setRadius(10);
shdw.setSpread(0.12);
shdw.setHeight(10);
shdw.setWidth(10);
layout.setEffect(shdw);
【讨论】:
【参考方案4】:不透明度是 Node 的一个属性,它是 JavaFX 中用于显示在屏幕上的东西的父类。 http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#opacityProperty
所以你可以设置你想要淡出的对象的不透明度。然后,您必须添加某种方式来更改所需对象的不透明度。使用图片中的滑块是一种方法,但还有其他方法。
可以使用 DropShadow 效果来完成投影...http://docs.oracle.com/javafx/2/api/javafx/scene/effect/DropShadow.html。我从来没有使用过它。这个水平有点高,但是如果cmet中有后续问题我可以帮忙回答。
【讨论】:
那张图片与我需要的代码无关。它只是显示了我所说的“在窗户后面”的意思。我的意思是我希望 this answer 的效果应用于 Java Window 后面的任何内容。 另外,DropShadow 将被应用到窗口后面。如果窗口不透明,您将能够看到它后面的阴影。 啊,我明白了。那么Java窗口背后的对象是不受JavaFX控制的,它实际上只是操作系统桌面的一部分? 是的!我不知道该怎么办! 您可以控制窗口的不透明度。我已经做到了。只是在边缘添加阴影很棘手。此外,我放置的那个链接通过对图像应用效果来工作。我需要知道如何在动态背景上做到这一点。以上是关于JavaFX 对背景的影响的主要内容,如果未能解决你的问题,请参考以下文章