Internal Frames in JavaFX - javafx-2

I found this example of Internal Frames
http://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html
Is it possible to make the same internal Frames in JavaFX?

With JFXtras there is a Window control, where you can add content and handle the internal window behavior.
First you will need to put in your classpath the jfxtras library. They have some instructions where you can get the library. If you are using maven, just need to add:
<dependency>
<groupId>org.jfxtras</groupId>
<artifactId>jfxtras-labs</artifactId>
<version>2.2-r5</version>
</dependency>
Or download the library and put it into your project classpath, whatever.
Now I put a sample of the demo of the Window with a little difference, allowing generation of several windows.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import jfxtras.labs.scene.control.window.CloseIcon;
import jfxtras.labs.scene.control.window.MinimizeIcon;
import jfxtras.labs.scene.control.window.Window;
public class WindowTests extends Application {
private static int counter = 1;
private void init(Stage primaryStage) {
final Group root = new Group();
Button button = new Button("Add more windows");
root.getChildren().addAll(button);
primaryStage.setResizable(false);
primaryStage.setScene(new Scene(root, 600, 500));
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
// create a window with title "My Window"
Window w = new Window("My Window#"+counter);
// set the window position to 10,10 (coordinates inside canvas)
w.setLayoutX(10);
w.setLayoutY(10);
// define the initial window size
w.setPrefSize(300, 200);
// either to the left
w.getLeftIcons().add(new CloseIcon(w));
// .. or to the right
w.getRightIcons().add(new MinimizeIcon(w));
// add some content
w.getContentPane().getChildren().add(new Label("Content... \nof the window#"+counter++));
// add the window to the canvas
root.getChildren().add(w);
}
});
}
public double getSampleWidth() {return 600;}
public double getSampleHeight() {return 500;}
#Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) {launch(args);}
}
In the original demo, the event code was in the init method, and no button was included. I add the button to create dynamically windows and adding them to the screen.
Here is a snapshot of the result of the application:
I totally recommend you try the demo of jfxtras. They have really great stuff. Hope it helps.

You can implement simple internal window themselves. Main idea, that InternalWindow class just skeleton, that has internal frame like functionality. You can apply any content to it.
1) Declare class
public class InternalWindow extends Region
2) You should be able to set content in window
public void setRoot(Node node) {
getChildren().add(node);
}
3) You should be able to bring window to front if many window exist
public void makeFocusable() {
this.setOnMouseClicked(mouseEvent -> {
toFront();
});
}
4) Now we need dragging functionality
//just for encapsulation
private static class Delta {
double x, y;
}
//we can select nodes that react drag event
public void makeDragable(Node what) {
final Delta dragDelta = new Delta();
what.setOnMousePressed(mouseEvent -> {
dragDelta.x = getLayoutX() - mouseEvent.getScreenX();
dragDelta.y = getLayoutY() - mouseEvent.getScreenY();
//also bring to front when moving
toFront();
});
what.setOnMouseDragged(mouseEvent -> {
setLayoutX(mouseEvent.getScreenX() + dragDelta.x);
setLayoutY(mouseEvent.getScreenY() + dragDelta.y);
});
}
5) Also we want able to resize window (I show only simple right-bottom resizing)
//current state
private boolean RESIZE_BOTTOM;
private boolean RESIZE_RIGHT;
public void makeResizable(double mouseBorderWidth) {
this.setOnMouseMoved(mouseEvent -> {
//local window's coordiantes
double mouseX = mouseEvent.getX();
double mouseY = mouseEvent.getY();
//window size
double width = this.boundsInLocalProperty().get().getWidth();
double height = this.boundsInLocalProperty().get().getHeight();
//if we on the edge, change state and cursor
if (Math.abs(mouseX - width) < mouseBorderWidth
&& Math.abs(mouseY - height) < mouseBorderWidth) {
RESIZE_RIGHT = true;
RESIZE_BOTTOM = true;
this.setCursor(Cursor.NW_RESIZE);
} else {
RESIZE_BOTTOM = false;
RESIZE_RIGHT = false;
this.setCursor(Cursor.DEFAULT);
}
});
this.setOnMouseDragged(mouseEvent -> {
//resize root
Region region = (Region) getChildren().get(0);
//resize logic depends on state
if (RESIZE_BOTTOM && RESIZE_RIGHT) {
region.setPrefSize(mouseEvent.getX(), mouseEvent.getY());
} else if (RESIZE_RIGHT) {
region.setPrefWidth(mouseEvent.getX());
} else if (RESIZE_BOTTOM) {
region.setPrefHeight(mouseEvent.getY());
}
});
}
6) Usage. First we construct all layout. Then apply it to InternalWindow.
private InternalWindow constructWindow() {
// content
ImageView imageView = new ImageView("https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/Cheetah4.jpg/250px-Cheetah4.jpg");
// title bar
BorderPane titleBar = new BorderPane();
titleBar.setStyle("-fx-background-color: green; -fx-padding: 3");
Label label = new Label("header");
titleBar.setLeft(label);
Button closeButton = new Button("x");
titleBar.setRight(closeButton);
// title bat + content
BorderPane windowPane = new BorderPane();
windowPane.setStyle("-fx-border-width: 1; -fx-border-color: black");
windowPane.setTop(titleBar);
windowPane.setCenter(imageView);
//apply layout to InternalWindow
InternalWindow interalWindow = new InternalWindow();
interalWindow.setRoot(windowPane);
//drag only by title
interalWindow.makeDragable(titleBar);
interalWindow.makeDragable(label);
interalWindow.makeResizable(20);
interalWindow.makeFocusable();
return interalWindow;
}
7) And how add window to layout
#Override
public void start(Stage primaryStage) throws Exception {
Pane root = new Pane();
root.getChildren().add(constructWindow());
root.getChildren().add(constructWindow());
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
Result
Full code: gist
Upd about close button:
You can add method to InternalWindow
public void setCloseButton(Button btn) {
btn.setOnAction(event -> ((Pane) getParent()).getChildren().remove(this));
}
And when construct:
interalWindow.setCloseButton(closeButton);

Related

Why does adding JavaFX TableViews to a VBox make other nodes disappear?

EDIT: Forgot the code...
I have an app that let's the user select CSV files for viewing. I'm using JavaFX TableViews to display the data.
For one page, the user can type into a special text box. It's a custom class I made called AutoCompleteTextArea, which extends RichTextFX's StyleClassedTextArea. On other pages, this text box should be hidden. When I have just one TableView, things work fine.
vbox.getChildren().addAll(menuBar, title, subtitle, reqBox, reqTable);
But I need other pages with different TableViews. If I add another TableView to the VBox, my AutoCompleteTextArea goes away!
vbox.getChildren().addAll(menuBar, title, subtitle, reqBox, reqTable, tempTable);
The TableViews do not appear to be overlapping... Any idea why the AutoCompleteTextArea is disappearing? The other weird thing is that if I substitute a regular TextField for the AutoCompleteTextArea, things work fine!
Here's my code. You will need RichTextFX on your build path in order to run it. Use the View Menu to see the problem. The first menu item shows the AutoCompleteTextArea (in the working case). The second menu item shows a different TableView, but this is the broken case - the AutoCompleteTextArea is gone from the first page.
Line 132 is the line in question.
I hope someone is up for the challenge!
More background:
I originally wanted to have just one TableView, and update it's contents based on the user's selection in the View Menu. But I couldn't find a good way to do that, and now here I am again... (see this post: How do I clone a JavaFX TableView?)
package FLOOR;
// --- Imports
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import org.fxmisc.richtext.StyleClassedTextArea;
import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
// --- Main Class
public class Example extends Application {
// --- All Pages
final Page[] pages = new Page[] {
new Page("Welcome!",
"Welcome Page"),
new Page("Page 1", "Shows Table_1"),
new Page("Page 2", "Shows Table_2"),
};
// --- All Tables
TableView<ObservableList<StringProperty>> reqTable = new TableView<>();
TableView<ObservableList<StringProperty>> tempTable = new TableView<>();
//TextField reqBox = new TextField();
AutoCompleteTextArea reqBox = new AutoCompleteTextArea();
// --- Current Page
final Label title = new Label();
final Label subtitle = new Label();
// --- Main
public static void main(String[] args) { launch(args); }
// --- Start
#Override
public void start(Stage stage) {
// --- Menus
// --- File Menu
// --- Import Submenu
Menu menuFile = new Menu("File");
Menu importMenu = new Menu("Import");
MenuItem reqOption = new MenuItem("Requirements");
MenuItem tempOption = new MenuItem("Templates");
importMenu.getItems().addAll(reqOption, tempOption);
//Import Requirements
reqOption.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
//TODO
}
});
//Import Templates
tempOption.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
//TODO
}
});
//Export
MenuItem export = new MenuItem("Export");
export.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
//TODO
}
});
//Exit
MenuItem exit = new MenuItem("Exit");
exit.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
System.exit(0);
}
});
menuFile.getItems().addAll(importMenu, export, new SeparatorMenuItem(), exit);
// --- View Menu
Menu menuView = new Menu("View");
//Page1
MenuItem viewRequirements = new MenuItem("Requirements");
viewRequirements.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
getPage1();
}
});
//Page2
MenuItem viewTemplates = new MenuItem("Templates");
viewTemplates.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
getPage2();
}
});
menuView.getItems().addAll(viewRequirements, viewTemplates);
// --- Menu Bar
MenuBar menuBar = new MenuBar();
menuBar.getMenus().addAll(menuFile, menuView);
// --- VBox
final VBox vbox = new VBox();
vbox.setAlignment(Pos.TOP_CENTER);
vbox.setSpacing(10);
reqTable.setMinHeight(300);
tempTable.setMinHeight(300);
reqTable.translateYProperty().set(30);
tempTable.translateYProperty().set(-275);
reqTable.setVisible(false);
tempTable.setVisible(false);
reqBox.setVisible(false);
// --- Welcome Page
title.setFont(new Font("Arial", 24));
title.translateYProperty().set(10);
title.setText(pages[0].title);
subtitle.setText(pages[0].subtitle);
subtitle.setMinHeight(30);
subtitle.setTextAlignment(TextAlignment.CENTER);
// --- Show FLOOR
vbox.getChildren().addAll(menuBar, title, subtitle, reqBox, reqTable);
//vbox.getChildren().addAll(menuBar, title, subtitle, reqBox, reqTable, tempTable);
Scene scene = new Scene(vbox, 900, 500);
stage.setScene(scene);
stage.setTitle("FLOOR");
stage.show();
}
// --- Methods
// Page Getters
private void getPage1() {
title.setFont(new Font("Arial", 24));
title.translateYProperty().set(10);
title.setText(pages[1].title);
subtitle.setText(pages[1].subtitle);
subtitle.setMinHeight(20);
reqBox.setVisible(true);
reqTable.setVisible(true);
tempTable.setVisible(false);
}
private void getPage2() {
title.setFont(new Font("Arial", 24));
title.translateYProperty().set(10);
title.setText(pages[2].title);
subtitle.setText(pages[2].subtitle);
subtitle.setMinHeight(20);
reqBox.setVisible(false);
reqTable.setVisible(false);
tempTable.setVisible(true);
}
// --- Classes
// Page
private class Page {
public String title;
public String subtitle;
public Page(String title, String subtitle) {
this.title = title;
this.subtitle = subtitle;
}
}
// AutoCompleteTextArea
public class AutoCompleteTextArea extends StyleClassedTextArea {
public final SortedSet<String> entries;
public ContextMenu entriesPopup;
public AutoCompleteTextArea() {
super();
entries = new TreeSet<>();
entriesPopup = new ContextMenu();
}
public SortedSet<String> getEntries() { return entries; }
public void populatePopup(List<String> searchResult) {
List<CustomMenuItem> menuItems = new LinkedList<>();
int maxEntries = 20;
int count = Math.min(searchResult.size(), maxEntries);
for (int i = 0; i < count; i++) {
final String result = searchResult.get(i);
Label entryLabel = new Label(result);
CustomMenuItem item = new CustomMenuItem(entryLabel, true);
menuItems.add(item);
}
entriesPopup.getItems().clear();
entriesPopup.getItems().addAll(menuItems);
}
}
}

Buttons not working on Program

I am trying to set up the buttons on the following program, but they will not control the program properly. I am not sure why they are not working. The reverse button works, but the start and stop buttons do not.
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ch30 extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
FanPane fan = new FanPane();
HBox hBox = new HBox(5);
Button btPause = new Button("Pause");
Button btResume = new Button("Resume");
Button btReverse = new Button("Reverse");
hBox.setAlignment(Pos.CENTER);
hBox.getChildren().addAll(btPause, btResume, btReverse);
BorderPane pane = new BorderPane();
pane.setCenter(fan);
pane.setBottom(hBox);
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 200, 200);
primaryStage.setTitle("Exercise15_28"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
//Runnable first = new Begin();
//Thread first = new Thread();
//t1.start();
Thread first = new Thread(new Runnable() {
#Override public void run() {
while (true) {
try {
//Pause
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
Platform.runLater(new Runnable() {
#Override public void run() {
fan.move();
}
});
}
}
});
first.start();
//Timeline animation = new Timeline(
//new KeyFrame(Duration.millis(100), e -> fan.move()));
//animation.setCycleCount(Timeline.INDEFINITE);
//animation.play(); // Start animation
scene.widthProperty().addListener(e -> fan.setW(fan.getWidth()));
scene.heightProperty().addListener(e -> fan.setH(fan.getHeight()));
//btPause.setOnAction(e -> first.wait());
btResume.setOnAction(e -> first.start());
btReverse.setOnAction(e -> fan.reverse());
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
class FanPane extends Pane {
private double w = 200;
private double h = 200;
private double radius = Math.min(w, h) * 0.45;
private Arc arc[] = new Arc[4];
private double startAngle = 30;
private Circle circle = new Circle(w / 2, h / 2, radius);
public FanPane() {
circle.setStroke(Color.BLACK);
circle.setFill(Color.WHITE);
getChildren().add(circle);
for (int i = 0; i < 4; i++) {
arc[i] = new Arc(w / 2, h / 2, radius * 0.9, radius * 0.9, startAngle + i * 90, 35);
arc[i].setFill(Color.RED); // Set fill color
arc[i].setType(ArcType.ROUND);
getChildren().addAll(arc[i]);
}
}
private double increment = 5;
public void reverse() {
increment = -increment;
}
public void move() {
setStartAngle(startAngle + increment);
}
public void setStartAngle(double angle) {
startAngle = angle;
setValues();
}
public void setValues() {
radius = Math.min(w, h) * 0.45;
circle.setRadius(radius);
circle.setCenterX(w / 2);
circle.setCenterY(h / 2);
for (int i = 0; i < 4; i++) {
arc[i].setRadiusX(radius * 0.9);
arc[i].setRadiusY(radius * 0.9);
arc[i].setCenterX(w / 2);
arc[i].setCenterY(h / 2);
arc[i].setStartAngle(startAngle + i * 90);
}
}
public void setW(double w) {
this.w = w;
setValues();
}
public void setH(double h) {
this.h = h;
setValues();
}
}
This should be done with a Timeline, I know it's your homework and for some crazy reason your homework has been specified to not use a Timeline. But for anybody else, don't do it this way, just use a Timeline.
That said...
You mention start and stop buttons of which you have none. I assume start means resume and stop means pause as those are the buttons you do have. So I will answer accordingly.
The easiest way to deal with this is to use a boolean variable to control whether or not the fan is moving.
Define a member of your application:
private boolean paused = false;
In your thread only move the fan if not paused:
Platform.runLater(() -> { if (!paused) fan.move(); });
Configure your buttons to set your flag:
btPause.setOnAction(e -> paused = true);
btResume.setOnAction(e -> paused = false);
I've just put the pause variable directly in the calling application, but you could encapsulate the pause status inside the fan object if you wished.
Normally when dealing with multi-threaded stuff you have to be careful about data getting corrupted due to race-conditions. For example, you would use constructs like AtomicBoolean or synchronized statements. But runLater puts everything on to the JavaFX application thread, so you don't necessarily need to worry about that.
There are alternate mechanisms you could use to ensure that your thread didn't keep looping and and sleeping, such as wait/notify or Conditions, but for a sample like this, you probably don't need that here.
Updated Application
Updated sample demonstrating the suggested modifications, tested on JDK 8u60, OS X 10.11.4.
public class ch30 extends Application {
private boolean paused = false;
#Override
public void start(Stage primaryStage) {
FanPane fan = new FanPane();
HBox hBox = new HBox(5);
Button btPause = new Button("Pause");
Button btResume = new Button("Resume");
Button btReverse = new Button("Reverse");
hBox.setAlignment(Pos.CENTER);
hBox.getChildren().addAll(btPause, btResume, btReverse);
BorderPane pane = new BorderPane();
pane.setCenter(fan);
pane.setBottom(hBox);
Thread first = new Thread(() -> {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
break;
}
Platform.runLater(() -> { if (!paused) fan.move(); });
}
});
first.setDaemon(true);
first.start();
btPause.setOnAction(e -> paused = true);
btResume.setOnAction(e -> paused = false);
btReverse.setOnAction(e -> fan.reverse());
Scene scene = new Scene(pane, 200, 200);
scene.widthProperty().addListener(e -> fan.setW(fan.getWidth()));
scene.heightProperty().addListener(e -> fan.setH(fan.getHeight()));
primaryStage.setScene(scene);
primaryStage.show();
}
}
Aside
Set the daemon status of your thread so that your application shuts down cleanly when somebody closes the main stage.
first.setDaemon(true);

JavaFX maximize the size of node children

I want to have squares added to a pane, and those squares maximized.
One square takes up the whole pane.
Two squares split the pane.
Three squares make it all in thirds.
When it overflows it goes to the next "row" and continues the process.
All the squares should be the same size.
Is there a way of using the standard layouts or which should I modify?
Thanks
Here's my take on this problem. I don't think it's a great solution, but at least it might help point out some techniques somebody might build on to get a better solution. Basically the solution overrides layoutChildren() to recalculate the preferred tile size as the number of tiles or the available space changes. I'm not sure getWidth or getHeight should really be called from layoutChildren (though it seems to work in this case).
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.util.Random;
public class TilePaneSample extends Application {
private static final Random random = new Random(42);
#Override
public void start(Stage stage) {
TilePane tiles = createTiles();
VBox layout = new VBox(
createControls(tiles),
tiles
);
VBox.setVgrow(tiles, Priority.ALWAYS);
stage.setScene(new Scene(layout, 400, 300));
stage.show();
}
private TilePane createTiles() {
TilePane tiles = new TilePane() {
#Override
protected void layoutChildren() {
if (getChildren().size() > 0) {
setPrefTileWidth(
Math.floor(
Math.min(
Math.max(
Tile.MIN_SIZE,
getWidth() / getChildren().size()
),
getHeight()
)
)
);
setPrefTileHeight(getPrefTileWidth());
}
super.layoutChildren();
}
};
tiles.setStyle("-fx-background-color: papayawhip;");
tiles.setPrefColumns(5);
tiles.setPrefRows(5);
tiles.getChildren().add(new Tile());
return tiles;
}
private ToolBar createControls(TilePane tiles) {
Button addTile = new Button("Add Tile");
addTile.setOnAction(action -> tiles.getChildren().add(new Tile()));
Button removeTiles = new Button("Remove Tiles");
removeTiles.setOnAction(action -> tiles.getChildren().clear());
ToolBar controls = new ToolBar(addTile, removeTiles);
controls.setMinHeight(ToolBar.USE_PREF_SIZE);
return controls;
}
private class Tile extends StackPane {
public static final int MIN_SIZE = 100;
public Tile() {
setStyle(
"-fx-background-color: " +
"rgb(" + random.nextInt(256) + ", " +
+ random.nextInt(256) + ", "
+ random.nextInt(256) + ");"
);
setMinSize(MIN_SIZE, MIN_SIZE);
}
}
public static void main(String[] args) { launch(args); }
}

JavaFX ProgressBar: how to change bar color?

I'm trying to change the color of bar in ProgressBar with
pBar.setStyle("-fx-accent: green");
but I have encountered a problem: that doesn't seem to work right for me! (Or I just don't understand something)
here is the code:
public class JavaFXApplication36 extends Application {
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
ProgressBar pbRed = new ProgressBar(0.4);
ProgressBar pbGreen = new ProgressBar(0.6);
pbRed.setLayoutY(10);
pbGreen.setLayoutY(30);
pbRed.setStyle("-fx-accent: red;"); // line (1)
pbGreen.setStyle("-fx-accent: green;"); // line (2)
root.getChildren().addAll(pbRed, pbGreen);
Scene scene = new Scene(root, 150, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
}
I always get 2 red progressbars with it! It seems that code in line (1) changes the style of ProgressBar class, not the instance.
Another strange moment is that deleting line (1) don't result in 2 green progress bars. So I can figure that line (2) is completely useless!! WHY?! That's definitely getting odd.
Is there any way to set separate colors for separate progressbars?
Answer updated to add a simple non-animated example with multiple progress bars
The code in your question should display two different colored progress bars, the fact that it doesn't is a bug in the JavaFX css processing system. Log the bug against the runtime project here: http://javafx-jira.kenai.com.
As a workaround, instead of calling setStyle on the progress bars, define the accent colors used to color progress bars within a stylesheet and add a style class to the progress bars. Then, you can create multiple progress bars within the same application, all with different colors.
As Uluk points out, you can use JavaFX 2.2 caspian.css in conjunction with the JavaFX 2 css reference guide and the JavaFX 2 css tutorial to determine how to style things.
Here is some sample code which customizes a progress bar based upon the information in those references.
Sample css:
/** progress.css
place in same directory as
ColoredProgressBarStyleSheet.java or SimpleColoredProgressBar.java
ensure build system copies the css file to the build output path */
.root { -fx-background-color: cornsilk; -fx-padding: 15; }
.progress-bar { -fx-box-border: goldenrod; }
.green-bar { -fx-accent: green; }
.yellow-bar { -fx-accent: yellow; }
.orange-bar { -fx-accent: orange; }
.red-bar { -fx-accent: red; }
Simple sample program:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
// shows multiple progress bars drawn in different colors.
public class SimpleColoredProgressBar extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) {
final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(
new ColoredProgressBar("red-bar", 0.2),
new ColoredProgressBar("orange-bar", 0.4),
new ColoredProgressBar("yellow-bar", 0.6),
new ColoredProgressBar("green-bar", 0.8)
);
layout.getStylesheets().add(getClass().getResource("progress.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
}
class ColoredProgressBar extends ProgressBar {
ColoredProgressBar(String styleClass, double progress) {
super(progress);
getStyleClass().add(styleClass);
}
}
}
Simple sample program output:
More complicated sample program with a single animated progress bar which changes color dynamically depending on the amount of progress made:
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
// shows a progress bar whose bar changes color depending on the amount of progress.
public class ColoredProgressBarStyleSheet extends Application {
public static void main(String[] args) { launch(args); }
private static final String RED_BAR = "red-bar";
private static final String YELLOW_BAR = "yellow-bar";
private static final String ORANGE_BAR = "orange-bar";
private static final String GREEN_BAR = "green-bar";
private static final String[] barColorStyleClasses = { RED_BAR, ORANGE_BAR, YELLOW_BAR, GREEN_BAR };
#Override public void start(Stage stage) {
final ProgressBar bar = new ProgressBar();
final Timeline timeline = new Timeline(
new KeyFrame(Duration.millis(0), new KeyValue(bar.progressProperty(), 0)),
new KeyFrame(Duration.millis(3000), new KeyValue(bar.progressProperty(), 1))
);
Button reset = new Button("Reset");
reset.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
timeline.playFromStart();
}
});
bar.progressProperty().addListener(new ChangeListener<Number>() {
#Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
double progress = newValue == null ? 0 : newValue.doubleValue();
if (progress < 0.2) {
setBarStyleClass(bar, RED_BAR);
} else if (progress < 0.4) {
setBarStyleClass(bar, ORANGE_BAR);
} else if (progress < 0.6) {
setBarStyleClass(bar, YELLOW_BAR);
} else {
setBarStyleClass(bar, GREEN_BAR);
}
}
private void setBarStyleClass(ProgressBar bar, String barStyleClass) {
bar.getStyleClass().removeAll(barColorStyleClasses);
bar.getStyleClass().add(barStyleClass);
}
});
final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(bar, reset);
layout.getStylesheets().add(getClass().getResource("progress.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
timeline.play();
}
}
More complicated sample program output:
You should to override (or customize) the style with JavaFX CSS selectors. See caspian.css for more information. In your own stylesheet define:
.progress-bar .bar {
-fx-background-color:
-fx-box-border,
linear-gradient(to bottom, derive(-fx-accent,95%), derive(-fx-accent,10%)),
red; /* this line is the background color of the bar */
-fx-background-insets: 0, 1, 2;
-fx-padding: 0.416667em; /* 5 */
}
For those who want a simple answer (and without needing to add CSS files):
ProgressBar pbGreen = new ProgressBar(0.6);
pbGreen.setStyle("-fx-accent: green");

How to make an undecorated window movable / draggable in JavaFX?

I have to create an application in which minimize and maximize button will be disabled.
I have used "StageStyle.UNDECORATED" with which the application will not be movable or draggable anymore, so I am searching for any other alternative to make my application.
Do anyone having solution for this?
To achieve the window to be undecorated but still movable/dragable you have to handle the appropriate MouseEvent on any node of your choice.
Example:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class SimpleWindowApplication extends Application {
private double xOffset = 0;
private double yOffset = 0;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) {
primaryStage.initStyle(StageStyle.UNDECORATED);
BorderPane root = new BorderPane();
root.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
xOffset = event.getSceneX();
yOffset = event.getSceneY();
}
});
root.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
primaryStage.setX(event.getScreenX() - xOffset);
primaryStage.setY(event.getScreenY() - yOffset);
}
});
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Learn more from the very valuable examples contained on Oracle's JavaFX download page under: JavaFX Demos and Samples
Sole purpose of this class is to allow undecorated Window to be dragged. It also performs the duty to ensure TaskBar remains visible with FullScreen, and ensure undecorated window not dragged out of screen.
Lastly its provides a bug fix to the error "css resource not found."
Simply paste below code in the main class in the overridden start() method just about when the Stage is ABOUT READY to be shown or after.
WindowStyle.allowDrag(root, stage);
WindowStyle.stageDimension(stage.getWidth(), stage.getHeight());
NOTE: Paste the above when the Stage is ABOUT READY to be shown or after.
For full screen window use:
WindowStyle.fullScreen(Stage stage);
To resize back to previous use:
WindowStyle.restoreScreen(Stage stage);
To add custom stylesheets to your scene, Simply paste below code in the main class in the overridden start() method after defining your scene.
scene.getStylesheets().add(WindowStyle.addStyleSheet(String css));
The name of css to be used for styling can be in the form of: main.css or styles/main.css
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.input.MouseEvent;
import javafx.stage.Screen;
import javafx.stage.Stage;
/**
* #author: BENJAH
*/
public class WindowStyle {
private static final Rectangle2D SCREEN_BOUNDS= Screen.getPrimary()
.getVisualBounds();
private static double[] pref_WH, offset_XY;
private static String styleSheet;
private WindowStyle(String css) {
styleSheet= getClass().getResource(css).toString();
}
protected static void allowDrag(Parent root, Stage stage) {
root.setOnMousePressed((MouseEvent p) -> {
offset_XY= new double[]{p.getSceneX(), p.getSceneY()};
});
root.setOnMouseDragged((MouseEvent d) -> {
//Ensures the stage is not dragged past the taskbar
if (d.getScreenY()<(SCREEN_BOUNDS.getMaxY()-20))
stage.setY(d.getScreenY() - offset_XY[1]);
stage.setX(d.getScreenX() - offset_XY[0]);
});
root.setOnMouseReleased((MouseEvent r)-> {
//Ensures the stage is not dragged past top of screen
if (stage.getY()<0.0) stage.setY(0.0);
});
}
//Sets the default stage prefered width and height.
protected static void stageDimension(Double width, Double height) {
pref_WH= new double[]{width, height};
}
protected static void fullScreen(Stage stage) {
stage.setX(SCREEN_BOUNDS.getMinX());
stage.setY(SCREEN_BOUNDS.getMinY());
stage.setWidth(SCREEN_BOUNDS.getWidth());
stage.setHeight(SCREEN_BOUNDS.getHeight());
}
protected static void restoreScreen(Stage stage) {
stage.setX((SCREEN_BOUNDS.getMaxX() - pref_WH[0])/2);
stage.setY((SCREEN_BOUNDS.getMaxY() - pref_WH[1])/2);
stage.setWidth(pref_WH[0]);
stage.setHeight(pref_WH[1]);
}
protected static String addStyleSheet(String css) {
new WindowStyle(css);
return styleSheet;
}
}

Resources