I want to handle click on ProgressBar like on slider. and learn a percent of track.
I would use slider instead progressbar but it doesn't have a highlighted track until thumb.
I need create something like a progress in a music player of playing song, and possibility to seek with a click on progress.
Do anybody have a tips how can i do it?
Here is another approach. Real hybrid of slider and progress bar :). Meet SlidoProgressBar!
public class SlidoProgressBarDemo extends Application {
#Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root);
scene.getStylesheets().add(this.getClass().getResource("style.css").toExternalForm());
stage.setScene(scene);
stage.setTitle("Progress Controls");
double sliderWidth = 200;
final Slider slider = new Slider();
slider.setMin(0);
slider.setMax(50);
slider.setMinWidth(sliderWidth);
slider.setMaxWidth(sliderWidth);
final ProgressBar pb = new ProgressBar(0);
pb.setMinWidth(sliderWidth);
pb.setMaxWidth(sliderWidth);
final ProgressIndicator pi = new ProgressIndicator(0);
slider.valueProperty().addListener(new ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> ov,
Number old_val, Number new_val) {
pb.setProgress(new_val.doubleValue() / 50);
pi.setProgress(new_val.doubleValue() / 50);
}
});
StackPane pane = new StackPane();
pane.getChildren().addAll(pb, slider);
final HBox hb = new HBox();
hb.setSpacing(5);
hb.setAlignment(Pos.CENTER);
hb.getChildren().addAll(pane, pi);
scene.setRoot(hb);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
with style.css:
.slider .track {
-fx-background-color:null; /* Hide the track */
-fx-background-insets: 1 0 -1 0, 0, 1;
-fx-background-radius: 2.5, 2.5, 1.5;
-fx-padding: 0.208333em; /* 2.5 */
}
The basic logic is to put slider and progress into stackpane. Give them the same width. Bind the progress values of them. Hide the track of the slider.
Output:
i solved this problem with code :
progress.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.getButton() == MouseButton.PRIMARY){
Bounds b1 = progress.getLayoutBounds();
double mouseX = event.getSceneX();
double percent = (((b1.getMinX() + mouseX ) * 100) / b1.getMaxX());
//correcting a percent, i don't know when it need
percent -= 2;
progress.setProgress((percent) / 100);
//do something with progress in percent
}
}
});
Just a tornadoFX example:
package bj
import javafx.application.Application
import javafx.geometry.Insets
import javafx.scene.control.ProgressBar
import javafx.scene.control.Slider
import javafx.scene.paint.Color
import tornadofx.*
/**
* Created by BaiJiFeiLong#gmail.com at 18-12-13 下午9:28
*/
class MainView : View() {
private lateinit var progressBar: ProgressBar
private lateinit var slider: Slider
override val root = vbox {
stackpane {
padding = Insets(100.0)
progressbar(initialValue = .0) {
progressBar = this
maxWidth = Double.MAX_VALUE
}
slider(max = 1, value = .0) {
slider = this
}
}
}
init {
progressBar.progressProperty().bind(slider.valueProperty())
progressBar.paddingLeftProperty.bind(progressBar.heightProperty().divide(2))
progressBar.paddingRightProperty.bind(progressBar.heightProperty().divide(2))
}
}
class MainStylesheet : Stylesheet() {
init {
slider {
track {
backgroundColor = MultiValue(arrayOf(Color.TRANSPARENT))
}
}
}
}
class App : tornadofx.App(MainView::class, MainStylesheet::class)
fun main(args: Array<String>) {
Application.launch(App::class.java, *args)
}
Related
#FXML
void minimize(MouseEvent event) {
Stage stage=(Stage) iconMinimize.getScene().getWindow();
stage.setIconified(true);
}
I have an icon that minimizes my program by mouse click. For example, when I minimize Windows for a program, you can see how the program works with an effect. The program slowly moves back to the taskbar. I would like to have such an effect too. If I do that with the code from the top, the program is right in the system tray. How do I get such an effect?
Animate the window size when you want to iconify the app and listen to the iconified property to do the reverse animation when the Stage is restored:
#Override
public void start(Stage primaryStage) {
StageHideAnimator.create(primaryStage);
Button minimize = new Button("minimize");
minimize.setOnAction(evt -> {
StageHideAnimator animator = StageHideAnimator.getStageHideAnimator((Node) evt.getSource());
animator.iconify();
});
Button close = new Button("close");
close.setOnAction(evt -> primaryStage.close());
VBox content = new VBox(minimize, close, new Rectangle(200, 200, Color.BLUE));
content.setPadding(new Insets(10));
content.setStyle("-fx-background-color: green;");
primaryStage.initStyle(StageStyle.TRANSPARENT);
Scene scene = new Scene(content);
primaryStage.setScene(scene);
primaryStage.setOnShown(evt -> {
WindowUtils.placeAtPrimaryScreenBottom(primaryStage);
});
primaryStage.show();
}
public final class WindowUtils {
private WindowUtils() { }
public static void placeAtPrimaryScreenBottom(Stage stage) {
stage.setY(Screen.getPrimary().getVisualBounds().getMaxY() - stage.getHeight());
}
}
public class StageHideAnimator {
// key used for storing animators in the properties map of a Stage
private static final Object PROPERTY_KEY = new Object();
private double sceneHeight;
private double decorationHeight;
private final Stage stage;
private Timeline animation;
// fraction of height relative to full height
private final DoubleProperty height = new SimpleDoubleProperty();
// getter for the animator
public static StageHideAnimator getStageHideAnimator(Stage stage) {
return (StageHideAnimator) stage.getProperties().get(PROPERTY_KEY);
}
// get animator of window containing the node
public static StageHideAnimator getStageHideAnimator(Node node) {
return getStageHideAnimator((Stage) node.getScene().getWindow());
}
private StageHideAnimator(Stage stage) {
this.stage = stage;
stage.iconifiedProperty().addListener((o, oldValue, newValue) -> {
// do reverse hide animation when stage is shown
if (!newValue) {
animation.setRate(-1);
if (animation.getStatus() == Animation.Status.STOPPED) {
animation.playFrom("end");
} else {
animation.play();
}
}
});
height.addListener((o, oldValue, newValue) -> {
// resize stage and put it at the bottom of the primary screen
stage.setHeight(sceneHeight * newValue.doubleValue() + decorationHeight);
WindowUtils.placeAtPrimaryScreenBottom(stage);
});
}
public static StageHideAnimator create(Stage stage) {
if (stage.getProperties().containsKey(PROPERTY_KEY)) {
// don't allow 2 animators
throw new IllegalArgumentException("animator already exists");
}
StageHideAnimator animator = new StageHideAnimator(stage);
stage.getProperties().put(PROPERTY_KEY, animator);
return animator;
}
private void initHeight() {
sceneHeight = stage.getScene().getHeight();
decorationHeight = stage.getHeight() - sceneHeight;
}
public void iconify() {
if (stage.isIconified()) {
return;
}
if (animation == null) {
initHeight(); // save initial height of stage
animation = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(height, 1d, Interpolator.EASE_BOTH)),
new KeyFrame(Duration.seconds(1), new KeyValue(height, 0d, Interpolator.EASE_BOTH)));
animation.setOnFinished(evt -> {
if (animation.getRate() == 1) {
// iconify at end of hiding animation
animation.setRate(-1);
stage.setIconified(true);
}
});
animation.play();
} else {
animation.setRate(1);
if (animation.getStatus() == Animation.Status.STOPPED) {
initHeight(); // save initial height of stage
animation.playFromStart();
} else {
animation.play();
}
}
}
}
Demonstration of answer:(answered May 29 at 3:10 am)
**10/7/2016** you can find the code on GitHub
Actual Question before answered:(asked May 22 at 19:53)
The title might be not too great but what I want to do is something like this in JavaFX:
Examples
YouTube:
StackOverFlow(which has and autocomplete):
Question:
I don't require to write me the code for that. Instead I want to know how I can achieve that using JavaFX and some ideas.
For the tags you can use a custom styled HBox containing a Text (the tag name) node an a Button (the deletion button (X)). By playing around with the background and the border you can achieve the desired look of the tags.
The onAction handler of the button should remove the tag from it's parent...
For the whole tag bar you can use another HBox. Use the appropriate border for the correct look. In addition to the tags add a TextField with no background as last element and set the Hgrow property of that TextField to Priotity.ALWAYS to cover the rest of the available space.
The onAction handler of this TextField adds new tags and clears the content of the TextField.
You could e.g. use ControlsFX's autocompletion features with the TextField or implement it on your own for a custom look...
public class TagBar extends HBox {
private final ObservableList<String> tags;
private final TextField inputTextField;
public ObservableList<String> getTags() {
return tags;
}
public TagBar() {
getStyleClass().setAll("tag-bar");
getStylesheets().add(getClass().getResource("style.css").toExternalForm());
tags = FXCollections.observableArrayList();
inputTextField = new TextField();
inputTextField.setOnAction(evt -> {
String text = inputTextField.getText();
if (!text.isEmpty() && !tags.contains(text)) {
tags.add(text);
inputTextField.clear();
}
});
inputTextField.prefHeightProperty().bind(this.heightProperty());
HBox.setHgrow(inputTextField, Priority.ALWAYS);
inputTextField.setBackground(null);
tags.addListener((ListChangeListener.Change<? extends String> change) -> {
while (change.next()) {
if (change.wasPermutated()) {
ArrayList<Node> newSublist = new ArrayList<>(change.getTo() - change.getFrom());
for (int i = change.getFrom(), end = change.getTo(); i < end; i++) {
newSublist.add(null);
}
for (int i = change.getFrom(), end = change.getTo(); i < end; i++) {
newSublist.set(change.getPermutation(i), getChildren().get(i));
}
getChildren().subList(change.getFrom(), change.getTo()).clear();
getChildren().addAll(change.getFrom(), newSublist);
} else {
if (change.wasRemoved()) {
getChildren().subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear();
}
if (change.wasAdded()) {
getChildren().addAll(change.getFrom(), change.getAddedSubList().stream().map(Tag::new).collect(Collectors.toList()));
}
}
}
});
getChildren().add(inputTextField);
}
private class Tag extends HBox {
public Tag(String tag) {
getStyleClass().setAll("tag");
Button removeButton = new Button("X");
removeButton.setOnAction((evt) -> tags.remove(tag));
Text text = new Text(tag);
HBox.setMargin(text, new Insets(0, 0, 0, 5));
getChildren().addAll(text, removeButton);
}
}
}
style.css
.tag-bar {
-fx-border-color: blue;
-fx-spacing: 3;
-fx-padding: 3;
-fx-max-height: 30;
}
.tag-bar .tag {
-fx-background-color: lightblue;
-fx-alignment: center;
}
.tag-bar .tag .button {
-fx-background-color: transparent;
}
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Sort");
StackPane.setAlignment(btn, Pos.BOTTOM_CENTER);
TagBar tagBar = new TagBar();
btn.setOnAction((ActionEvent event) -> {
FXCollections.sort(tagBar.getTags());
});
Button btn2 = new Button("add \"42\"");
btn2.setOnAction(evt -> {
if (!tagBar.getTags().contains("42")) {
tagBar.getTags().add("42");
}
});
VBox root = new VBox();
root.getChildren().addAll(tagBar, btn, btn2);
root.setPrefSize(300, 400);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
Simple implementation of this code!
import ....
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
BorderPane root = new BorderPane();
HBox tagsPane = new HBox(10);
tagsPane.setStyle("-fx-border-color: #F1F1F1;" +
" -fx-border-width: 1px;" +
" -fx-border-radius: 10;" +
" -fx-border-insets: 5");
root.setBottom(tagsPane);
TextField textField = new TextField();
textField.setPromptText("Tag name - ENTER to add");
textField.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
tagButton(tagsPane, textField.getText());
textField.clear();
}
});
root.setTop(textField);
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 450, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
//little image as 15x15 for example
Image toUse = new Image("sample/delete.png");
//box is the pane where this buttons will be placed
public void tagButton(HBox box,String tag){
ImageView closeImg = new ImageView(toUse);
Button result = new Button(tag,closeImg);
result.setPrefHeight(20);
result.setContentDisplay(ContentDisplay.RIGHT);
result.setOnAction(event -> box.getChildren().remove(result));
box.getChildren().add(result);
}
}
Also if u need different events for click on tag and click on "X" you can implement tagButton like this :
public void tagButton(HBox box,String tag){
ImageView closeImg = new ImageView(toUse);
HBox button = new HBox();
button.setStyle("-fx-padding:4;" +
" -fx-border-width: 2;" +
" -fx-border-color: black;" +
" -fx-border-radius: 4;" +
" -fx-background-color: f1f1f1;" +
" -fx-border-insets: 5;");
button.setPrefHeight(20);
button.getChildren().addAll(new Label(tag),closeImg);
closeImg.setOnMouseClicked(event ->
box.getChildren().remove(button)
);
button.setOnMouseClicked(event -> {
//doSomethig
});
box.getChildren().add(button);
}
This is my version too
The whole Main class
its somehow long that's why.
But to sum up. You need a
1: FlowPane for the container, and you do not have to worry about wrapping,it will wrap itself, both vertical or horizontal.
2: Label of course for your Text, which has a GraphicProperty
3: Path - well you could use Button, and add a Shape or Image to it, but that will be a lot of Nodes, so i used Path and i drew a X red button.
The rest is styling to your preferred color
EDIT
something like this?
you can style it to get that output
setFont(Font.font("Serif Regular", FontWeight.SEMI_BOLD,12));
use this line on the TextField
Here is a basic example of a tag bar (I wrote some code, because I think it's easier to follow). For the additional AutoComplete function you could use e.g. ControlsFx, as fabian already mentioned.
public class CloseTag extends HBox implements Comparable<CloseTag> {
private Label label;
private Label closeIcon;
public CloseTag(String text) {
setStyle("-fx-padding:8;");
Text icon = GlyphsDude.createIcon(FontAwesomeIcon.TIMES_CIRCLE);
closeIcon = new Label(null, icon);
label = new Label(text, new StackPane(closeIcon));
label.setContentDisplay(ContentDisplay.RIGHT);
getChildren().add(label);
}
public void setOnCloseAction(EventHandler<? super MouseEvent> action) {
closeIcon.setOnMouseClicked(action);
}
public String getText() {
return label.getText();
}
#Override
public int compareTo(CloseTag other) {
return getText().compareTo(other.getText());
}
}
public class TagPane extends FlowPane {
private TextField textField;
public TagPane() {
setStyle("-fx-padding:8;" + "-fx-hgap:10;");
setOnMouseClicked(evt -> onMouseClickedd(evt));
textField = new TextField();
textField.setOnKeyPressed(evt -> onKeyPressed(evt, textField));
}
private void onMouseClickedd(MouseEvent mouseEvent) {
if (mouseEvent.getTarget() != this || textField.getParent() != null ) {
return;
}
getChildren().add(textField);
textField.requestFocus();
}
private void onKeyPressed(KeyEvent evt, TextField textField) {
if (evt.getCode() == KeyCode.ENTER || evt.getCode() == KeyCode.TAB) {
createTag(textField.getText());
textField.clear();
}
}
private void createTag(String text) {
CloseTag tag = new CloseTag(text);
tag.setOnCloseAction(evt -> removeTag(tag));
getChildren().remove(textField);
getChildren().add(tag);
}
private void removeTag(CloseTag tag) {
getChildren().remove(tag);
}
}
I've wrapped my brain around a challenge for 2 days now. I am all empty for ideas, so I hope someone out there know how to do this.
I got inspired by Angela Caicedo's city app, from the website https://blogs.oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx, and trying to make a similar app-gui to show available rooms and lecture halls at my University.
I am using Java FX to build the gui, and I get the whole GUI printed out, which is a java fx pane with a image on it. What I want, however, is to just see a small part of the gui (the backgroundimage I am using is w:1500px h:500, so each part will be w:500px h:500px), then be able to push a button or a arrow (or similar) to move the window to the next step. On top of the image there is 3 panes with w:500px h:500px snapped to each other. Maybe this is a bad solution, considering all the pane-types Java FX has available.
So, what I need is a constrained viewer of sorts.
I've also used FMXL to build the GUI, having one FMXL document, one Controller and a css-file to handle the design.
I'm sure I've been everywhere on the internet by now, so I really hope someone has done this before in Java FX :)
Ok, here is some code example. The first sample works nice, but I want to implement the second example instead. I am reading on the TranslateTransition of JavaFX, but my efforts of trying to switch the code is hopeless..
1'st example (working, and is fading in and out of the fxml screen):
public boolean setScreen(final String name){
if (screens.get(name) != null) { //screen loaded
final DoubleProperty opacity = opacityProperty();
if (!getChildren().isEmpty()) { //if there is more than one screen
Timeline fade = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(opacity, 1.0)),
new KeyFrame(new Duration(2000), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
getChildren().remove(0); //remove the displayed screen
getChildren().add(0, screens.get(name)); //add the screen
Timeline fadeIn = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)),
new KeyFrame(new Duration(2000), new KeyValue(opacity, 1.0)));
fadeIn.play();
}
}, new KeyValue(opacity, 0.0)));
fade.play();
} else {
setOpacity(0.0);
getChildren().add(screens.get(name)); //no one else been displayed, then just show
Timeline fadeIn = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)),
new KeyFrame(new Duration(1000), new KeyValue(opacity, 1.0)));
fadeIn.play();
}
return true;
} else {
System.out.println("screen hasn't been loaded!!! \n");
return false;
}
}
Second example, the TranslateTransition I want to implement instead:
private final double IMG_WIDTH = 500;
private final double IMG_HEIGHT = 500;
private final int NUM_OF_IMGS = 3;
private final int SLIDE_FREQ = 4; // in secs
#Override
public void start(Stage stage) throws Exception {
stage.initStyle(StageStyle.UNDECORATED);
StackPane root = new StackPane();
Pane clipPane = new Pane();
// To center the slide show incase maximized
clipPane.setMaxSize(IMG_WIDTH, IMG_HEIGHT);
clipPane.setClip(new Rectangle(IMG_WIDTH, IMG_HEIGHT));
HBox imgContainer = new HBox();
ImageView imgGreen = new ImageView(new Image(getClass().getResourceAsStream("uib_01.jpg")));
ImageView imgBlue = new ImageView(new Image(getClass().getResourceAsStream("uib_02.jpg")));
ImageView imgRose = new ImageView(new Image(getClass().getResourceAsStream("uib_03.jpg")));
imgContainer.getChildren().addAll(imgGreen, imgBlue, imgRose);
clipPane.getChildren().add(imgContainer);
root.getChildren().add(clipPane);
Scene scene = new Scene(root, IMG_WIDTH, IMG_HEIGHT);
stage.setTitle("Image Slider");
stage.setScene(scene);
startAnimation(imgContainer);
stage.show();
}
private void startAnimation(final HBox hbox) {
EventHandler<ActionEvent> slideAction = (ActionEvent t) -> {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1.5), hbox);
trans.setByX(-IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
EventHandler<ActionEvent> resetAction = (ActionEvent t) -> {
TranslateTransition trans = new TranslateTransition(Duration.seconds(1), hbox);
trans.setByX((NUM_OF_IMGS - 1) * IMG_WIDTH);
trans.setInterpolator(Interpolator.EASE_BOTH);
trans.play();
};
List<KeyFrame> keyFrames = new ArrayList<>();
for (int i = 1; i <= NUM_OF_IMGS; i++) {
if (i == NUM_OF_IMGS) {
keyFrames.add(new KeyFrame(Duration.seconds(i * SLIDE_FREQ), resetAction));
} else {
keyFrames.add(new KeyFrame(Duration.seconds(i * SLIDE_FREQ), slideAction));
}
}
Timeline anim = new Timeline(keyFrames.toArray(new KeyFrame[NUM_OF_IMGS]));
anim.setCycleCount(Timeline.INDEFINITE);
anim.playFromStart();
}
The screen should change on button click. I have this in a separate controller class:
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
public class roomAppController implements Initializable, ScreenController {
private ScreenPane myScreenPane;
#FXML
public ImageView bldArw_1;
public ImageView rmArw_1;
#FXML
private void handleExitButtonEvent(MouseEvent e) {
System.out.println("Button is clicked");
System.exit(0);
}
#FXML
private void handleNextPageEvent(MouseEvent e) {
if((ImageView)e.getSource() == bldArw_1) {
myScreenPane.setScreen("buildingScreen");
}
if((ImageView)e.getSource() == rmArw_1) {
myScreenPane.setScreen("roomScreen");
}
System.out.println("Clicked");
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
#Override
public void setScreenPane(ScreenPane screenPage) {
myScreenPane = screenPage;
}
}
I'm using this to make a iOS-themed JavaFX2 (Java7) application with a frosted glass effect. The problem is that this code uses its effect on an ImageView. I'd like it to use its effect on whatever's behind the window, like this:
Is there anyway to do that? I'd also like that small drop-shadow effect you see around the above image.
To be clear, I don't want that slider or anything, just the effect of being able to see through the window and having that slight shadow around the edges. I want to use this iOS7-ish effect instead of aero, though.
This might be important: I'm using a modified version of Undecorator.
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);
}
}
Related Questions
Frosted Glass Effect in JavaFX?
How do I create a JavaFX transparent stage with shadows on only the border?
The visual effect that you want for OS dependent window decoration, can only be achieved through the APIs that OS provides. And thus was eliminated by StageStyle.TRANSPARENT below.
For JavaFX content itself, you can control the visuals of the stage > scene > root pane hierarchy. Stage and scene do not (and not aimed to) support advanced stylings so were eliminated by setting as transparent below.
#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();
}
However the drop shadow effect does not play well with alpha value of the background color. You can observe it by changing the shadow's color to another contrast one.
Output:
To expand on Jewlsea's answer .. And using the above example with JavaFX ONLY ..
While the classes are not public API, it does avoid the AWT stack completely.
Here is a non public example :
// 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;
}
}
Results with a small dropshadow added:
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);
The opacity is a property of Node, which is the parent class in JavaFX for things that show up on the screen. http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#opacityProperty
So you can just set the opacity on the object that you want to have fade away. You then have to add some sort of way to change the opacity on the desired object. Using the slider from your image is one way, but there are others.
Drop shadows can be done using the DropShadow effect... http://docs.oracle.com/javafx/2/api/javafx/scene/effect/DropShadow.html. I have never used it. This is a little high level but if there are follow up questions in the comments I can help answer them.
This question already has answers here:
How to create Splash screen with transparent background in JavaFX
(2 answers)
Closed 9 years ago.
I'm interested how I can display "Loading" message during JavaFX startup. I noticed for example that when I start SceneBuilder I have to wait ~5 seconds before the application is displayed in front of the user. Can I for example display some message during JVM start time?
UPDATE
I tested this code:
public class test extends Application
{
private Pane splashLayout;
private ProgressBar loadProgress;
private Label progressText;
private WebView webView;
private Stage mainStage;
private static final int SPLASH_WIDTH = 676;
private static final int SPLASH_HEIGHT = 227;
public static void main(String[] args) throws Exception
{
launch(args);
}
#Override
public void init()
{
ImageView splash = new ImageView(new Image("http://fxexperience.com/wp-content/uploads/2010/06/logo.png"));
loadProgress = new ProgressBar();
loadProgress.setPrefWidth(SPLASH_WIDTH - 20);
progressText = new Label("Loading System Modules ...");
splashLayout = new VBox();
splashLayout.getChildren().addAll(splash, loadProgress, progressText);
progressText.setAlignment(Pos.CENTER);
splashLayout.setStyle("-fx-padding: 5; -fx-background-color: cornsilk; -fx-border-width:5; -fx-border-color: linear-gradient(to bottom, chocolate, derive(chocolate, 50%));");
splashLayout.setEffect(new DropShadow());
}
#Override
public void start(final Stage initStage) throws Exception
{
showSplash(initStage);
showMainStage();
webView.getEngine().documentProperty().addListener(new ChangeListener<Document>()
{
#Override
public void changed(ObservableValue<? extends Document> observableValue, Document document, Document document1)
{
if (initStage.isShowing())
{
loadProgress.progressProperty().unbind();
loadProgress.setProgress(1);
progressText.setText("All Modules Are Loaded!");
mainStage.setIconified(false);
initStage.toFront();
FadeTransition fadeSplash = new FadeTransition(Duration.seconds(1.2), splashLayout);
fadeSplash.setFromValue(1.0);
fadeSplash.setToValue(0.0);
fadeSplash.setOnFinished(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent actionEvent)
{
initStage.hide();
}
});
fadeSplash.play();
}
}
});
}
private void showMainStage()
{
mainStage = new Stage(StageStyle.DECORATED);
mainStage.setTitle("FX Experience");
mainStage.setIconified(true);
// create a WebView.
webView = new WebView();
webView.getEngine().load("http://fxexperience.com/");
loadProgress.progressProperty().bind(webView.getEngine().getLoadWorker().workDoneProperty().divide(100));
// layout the scene.
Scene scene = new Scene(webView, 1000, 600);
webView.prefWidthProperty().bind(scene.widthProperty());
webView.prefHeightProperty().bind(scene.heightProperty());
mainStage.setScene(scene);
mainStage.show();
}
private void showSplash(Stage initStage)
{
Scene splashScene = new Scene(splashLayout);
initStage.initStyle(StageStyle.UNDECORATED);
final Rectangle2D bounds = Screen.getPrimary().getBounds();
initStage.setScene(splashScene);
initStage.setX(bounds.getMinX() + bounds.getWidth() / 2 - SPLASH_WIDTH / 2);
initStage.setY(bounds.getMinY() + bounds.getHeight() / 2 - SPLASH_HEIGHT / 2);
initStage.show();
}
}
I noticed that the splash image is started with the main stage simultaneity but the main stage is minimized. Can I freeze the appearance of the main stage until the splash screen is completed with the loading. I want to do some internal checks before I display the main stage.
Use javax.swing.JProgressBar to achieve this.
Check the details in JProgressBar (docs)