#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();
}
}
}
}
Related
what's the matter with this code?
i'm relly confused!!
i wanted to change my scene in main stage.
public class SignInController {
#FXML
TextField SignInPassword;
#FXML
TextField SignInUsername;
#FXML
CheckBox RememberMe;
public void signUpScene(MouseEvent mouseEvent) throws IOException {
Timeline timeline = new Timeline();
Scene SignUpScene = new Scene(FXMLLoader.load(getClass().getResource("sign up.fxml")),700,700);
Main.pstage.setScene(SignUpScene);
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.ZERO,new KeyValue(SignUpScene.getWidth(),0.0 )),
new KeyFrame(Duration.millis(1000.0d),new KeyValue(SignUpScene.getWidth(),700.0 ) )
);
timeline.play();
}
}
If you want to animate the width of the stage holding your new scene, you can use a Transition:
public void signUpScene(MouseEvent mouseEvent) throws IOException {
Scene SignUpScene = new Scene(FXMLLoader.load(getClass().getResource("sign up.fxml")),700,700);
Main.pstage.setScene(SignUpScene);
Rectangle clip = new Rectangle(0, 700);
Transition animateStage = new Transition() {
{
setCycleDuration(Duration.millis(1000));
}
#Override
protected void interpolate(double t) {
Main.pstage.setWidth(t * 700.0);
}
};
animateStage.play();
}
}
Maybe a better approach would be to gradually reveal the new scene using a clip:
public void signUpScene(MouseEvent mouseEvent) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("sign up.fxml"));
Scene SignUpScene = new Scene(root,700,700);
Main.pstage.setScene(SignUpScene);
Rectangle clip = new Rectangle(0, 700);
Timeline animate = new Timeline(
new KeyFrame(Duration.millis(1000),
new KeyValue(clip.widthProperty(), 700.0));
root.setClip(clip);
// when animation finishes, remove clip:
animate.setOnFinished(e -> root.setClip(null));
animate.play();
}
}
I'm extremely new to programming. I'm using JavaFX and NetBeans IDE 8.0.2 to write a simple math program. I'm trying to change scenes in the same stage, and my code works but the stage will not stay maximized once the scenes have changed. I've tried everything i could think of to keep it maximized or to restore it to maximized i.e. stage.setMaximized(true); after the next scene is switched, but none of the code is working. I created a simple example of my problem. Does anyone have any tips for me in anyway? Thank you.
public class ProblemExample extends Application
{
final double WIDTH = 600;
final double HEIGHT = 600;
Stage stage;
Scene scene1, scene2;
Pane pane1, pane2;
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
stage = primaryStage;
pane1 = new Pane();
pane2 = new Pane();
getuiPane1();
getuiPane2();
scene1 = new Scene(pane1, WIDTH, HEIGHT);
scene2 = new Scene(pane2, WIDTH, HEIGHT);
stage.setTitle("Example");
stage.setScene(scene1);
stage.setMaximized(true);
stage.show();
}
public void getuiPane1()
{
Text nextText = new Text(300, 300, "Next >>");
pane1.getChildren().add(nextText);
nextText.setOnMouseClicked(e ->
{
if (e.getSource() == nextText)
{
stage.setScene(scene2);
} else
{
stage.setScene(scene1);
}
}
);
}
public void getuiPane2()
{
Text backText = new Text(300, 300, "<< Back");
pane2.getChildren().add(backText);
backText.setOnMouseClicked(e ->
{
if (e.getSource() == backText)
{
stage.setScene(scene1);
} else
{
stage.setScene(scene2);
}
}
);
}
}
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;
}
}
When I try to load some files from JSON I want to create a progress bar that veils the screen for some seconds. The loading from JSON works, the progress bar works the only problem I have is with the veil.
So, I have my application that is running and when I try to load the JSON file I try to set the scene with the progress bar for the stage. All the things are going fine until now (even the new scene is showing the progress bar). The problem comes when I the progress bar finishes the progress (100%) it shows me blank ...and doesn't show me the old application scene. How can I resolve this ?
This is my code in the progress loader:
public Scene createContent() {
final StackPane g = new StackPane();
Region veil = new Region();
veil.setStyle("-fx-background-color: rgba(0, 0, 0, 0.4)");
veil.setOpacity(0.8);
final ProgressIndicator p1 = new ProgressIndicator();
p1.setPrefSize(100, 100);
p1.setMaxSize(150, 150);
p1.progressProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue ov, Number oldVal, Number newVal) {
if (p1.getProgress() < 0.25) {
p1.setStyle("-fx-progress-color: red;");
} else if (p1.getProgress() < 0.5) {
p1.setStyle("-fx-progress-color: orange;");
} else {
p1.setStyle("-fx-progress-color: green;");
}
}
});
// animate the styled ProgressIndicator
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.setAutoReverse(true);
final KeyValue kv = new KeyValue(p1.progressProperty(), 1);
final KeyFrame kf1 = new KeyFrame(Duration.millis(3000), kv);
timeline.getKeyFrames().add(kf1);
g.getChildren().addAll(veil,p1);
g.setAlignment(Pos.CENTER);
Task task = new Task() {
#Override
protected Object call() throws Exception {
for (int i = 0; i < 500; i++) {
updateProgress(i, 500);
Thread.sleep(5);
}
stage.hide();
return null;
}
};
p1.progressProperty().bind(task.progressProperty());
veil.visibleProperty().bind(task.runningProperty());
p1.visibleProperty().bind(task.runningProperty());
new Thread(task).start();
Scene scene = new Scene(g, 200, 200);
return scene;
}
public void play() {
timeline.play();
}
public void stop() {
timeline.stop();
}
public void start(Stage stage) {
this.stage=stage;
this.stage.setScene(createContent());
this.stage.show();
}
And this is in the JSON loader class:
ProgressLoader pl=new ProgressLoader();
pl.start(VisualAppFactory.getStage());
I do not know what you are trying to achieve excactly and what you mean by "veil", but your problem most certainly comes from calling stage.hide() while not being on the FX-Thread. Check out the documentation of the method or surround the call with a try block
try {
stage.hide();
} catch (Exception e) {
e.printStackTrace();
}
to see the effect.
Use Platform.runLater to execute the call on the FX-Thread:
Platform.runLater(()-> stage.hide());
With task.setOnSucceeded(...) you get notified when the task finished so you can set your old view into the stage or something.
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)
}