2014-03-26 82 views
23

我使用this來製作一個具有磨砂玻璃效果的基於iOS的JavaFX2(Java7)應用程序。問題是這段代碼在ImageView上使用它的效果。我想它用它的作用,對任何的窗戶後面,像這樣:JavaFX對背景的影響

反正有做到這一點?我也喜歡你在上面的圖片周圍看到的那個小陰影效果。

爲了清楚起見,我不想要那個滑塊或任何東西,只是能夠透過窗戶看到並在邊緣周圍留下輕微陰影的效果。不過,我想使用this iOS7-ish effect而不是aero。

這可能很重要:我使用Undecorator的修改版本。

回答

18

frosty

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); 
    } 
} 

相關問題

+0

大聲笑。你再做一次:D。在賞金結束之前幾秒鐘,我給了你一件好事。我在那裏嚇壞了。 – Taconut

+0

嘿!我做到了,所以你可以在FrostyPane上加載任何節點,並在窗口沒有焦點時關閉模糊(使其始終保持一致)。我有幾個問題:1.我刪除了暫停50ms一切的代碼,它仍然正常工作。有什麼我失蹤? 2.拖動窗口重新啓動我正在進行的任何功能。例如,當我移動窗口時,我的啓動畫面會重新啓動。任何方式在這個?另外,有什麼方法可以輕鬆實現調整大小?我想我可以處理它,但我只想知道你是否知道任何捷徑。 – Taconut

+0

不幸的是,如果背景變化,玻璃效果將不會重繪。否則,看起來不錯。 – dejuknow

0

不透明度是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。我從來沒有用過它。這有點高,但如果在評論中有後續問題,我可以幫助回答。

+0

那張照片是無關的,我需要的代碼。它只是顯示我的意思是「在窗戶後面」。我的意思是,我想從[這個答案]的效果(http://stackoverflow.com/questions/22622034/frosted-glass-effect-in-javafx/22630754#22630754)適用於任何背後的Java窗口。 – Taconut

+0

此外,DropShadow將應用在窗口後面。如果窗口不透明,您將能夠看到它背後的陰影。 – Taconut

+0

啊我明白了。所以Java窗口背後的對象不在JavaFX的控制之下,它實際上只是操作系統桌面的一部分? Yup! –

10

只能通過操作系統提供的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值無法很好地發揮作用。您可以通過將陰影的顏色更改爲另一個對比來觀察它。

輸出:
enter image description here

+0

這個答案也是正確的。我如何對他們兩人說「是」...? – Taconut

+0

@Tacout,沒辦法,只有upvote :) –

2

要擴大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); 

fxScreenCapture