how can I implement water 2D wave effect in JavaFX, I have image and want to when click on image a wave(or more) start expanding from that point, just like when we drop a piece rock into the calm water and we see the wave expanding.
This is a conversion of parts of old sun JavaFX 1 ripple generator to JavaFX 2.
It's not the most realistic water ripple effect, but maybe it's enough to get you started creating your own. You could add in a DisplacementMap effect to distort your image as a result of the "waves".
The code uses JavaFX animation timelines to generate expanding concentric circles that gradually fade away of time.
import javafx.animation.*;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.*;
import javafx.scene.shape.Circle;
import javafx.stage.*;
import javafx.util.Duration;
public class FishSim extends Application {
private static final Paint SCENE_FILL = new RadialGradient(
0, 0, 300, 300, 500, false, CycleMethod.NO_CYCLE,
FXCollections.observableArrayList(new Stop(0, Color.BLACK), new Stop(1, Color.BLUE))
);
#Override public void start(Stage stage) {
final RippleGenerator rippler = new RippleGenerator();
final Scene scene = new Scene(rippler, 600, 400, SCENE_FILL);
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.setGeneratorCenterX(event.getSceneX());
rippler.setGeneratorCenterY(event.getSceneY());
rippler.createRipple();
rippler.startGenerating();
}
});
scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.setGeneratorCenterX(event.getSceneX());
rippler.setGeneratorCenterY(event.getSceneY());
}
});
scene.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.stopGenerating();
}
});
stage.setTitle("Click, hold mouse button down and move around to create ripples");
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
/**
* Generates ripples on the screen every 0.5 seconds or whenever
* the createRipple method is called. Ripples grow and fade out
* over 3 seconds
*/
class RippleGenerator extends Group {
private class Ripple extends Circle {
Timeline animation = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(radiusProperty(), 0)),
new KeyFrame(Duration.seconds(1), new KeyValue(opacityProperty(), 1)),
new KeyFrame(Duration.seconds(3), new KeyValue(radiusProperty(), 100)),
new KeyFrame(Duration.seconds(3), new KeyValue(opacityProperty(), 0))
);
private Ripple(double centerX, double centerY) {
super(centerX, centerY, 0, null);
setStroke(Color.rgb(200, 200, 255));
}
}
private double generatorCenterX = 100.0;
private double generatorCenterY = 100.0;
private Timeline generate = new Timeline(
new KeyFrame(Duration.seconds(0.5), new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
createRipple();
}
}
)
);
public RippleGenerator() {
generate.setCycleCount(Timeline.INDEFINITE);
}
public void createRipple() {
final Ripple ripple = new Ripple(generatorCenterX, generatorCenterY);
getChildren().add(ripple);
ripple.animation.play();
Timeline remover = new Timeline(
new KeyFrame(Duration.seconds(3), new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
getChildren().remove(ripple);
ripple.animation.stop();
}
})
);
remover.play();
}
public void startGenerating() {
generate.play();
}
public void stopGenerating() {
generate.stop();
}
public void setGeneratorCenterX(double generatorCenterX) {
this.generatorCenterX = generatorCenterX;
}
public void setGeneratorCenterY(double generatorCenterY) {
this.generatorCenterY = generatorCenterY;
}
}
The original JavaFX 1 fish simulator code that the conversion is based on came from a jfrog repository (which might no longer exist if you click it).
Robert Ladstätter created a 2D water effect sample animation for JavaFX 2 (using Scala). Roberts animation is like viewing the water from the side rather than above, but perhaps some of the concepts might help you.
In this tutorial you can find how to use custom GLSL/HLSL pixel shaders for JavaFX.
And the code for a simple distortion procedural wave in screenSpace in HLSL form:
uniform extern texture ScreenTexture;
sampler ScreenS = sampler_state
{
Texture = <ScreenTexture>;
};
float wave; // pi/.75 is a good default
float distortion; // 1 is a good default
float2 centerCoord; // 0.5,0.5 is the screen center
float4 PixelShader(float2 texCoord: TEXCOORD0) : COLOR
{
float2 distance = abs(texCoord - centerCoord);
float scalar = length(distance);
// invert the scale so 1 is centerpoint
scalar = abs(1 - scalar);
// calculate how far to distort for this pixel
float sinoffset = sin(wave / scalar);
sinoffset = clamp(sinoffset, 0, 1);
// calculate which direction to distort
float sinsign = cos(wave / scalar);
// reduce the distortion effect
sinoffset = sinoffset * distortion/32;
// pick a pixel on the screen for this pixel, based on
// the calculated offset and direction
float4 color = tex2D(ScreenS, texCoord+(sinoffset*sinsign));
return color;
}
technique
{
pass P0
{
PixelShader = compile ps_2_0 PixelShader();
}
}
I hope it helps.
Related
I've been trying to create a program that displays a ball in the center of a window, with 4 buttons titled Up, Down, Left and Right at the bottom. When you press the buttons the ball moves in the corresponding direction. I've got that part figured out, but I also need to figure out how to make it so if making the ball go in a certain direction obscures it from view, it stops it from going in that direction. I need to find a way to detect the boundaries of the window, and stopping the ball from being able to go outside of the boundary. Here's what I have so far:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
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.Circle;
import javafx.stage.Stage;
public class Ball extends Application {
private BallControl circle = new BallControl();
#Override
public void start(Stage primaryStage) {
HBox pane = new HBox();
pane.setSpacing(10);
pane.setAlignment(Pos.CENTER);
Button btUp = new Button("UP");
Button btDown = new Button("DOWN");
Button btLeft = new Button("LEFT");
Button btRight = new Button("RIGHT");
pane.getChildren().add(btLeft);
pane.getChildren().add(btRight);
pane.getChildren().add(btUp);
pane.getChildren().add(btDown);
BorderPane borderPane = new BorderPane();
borderPane.setCenter(circle);
borderPane.setBottom(pane);
BorderPane.setAlignment(pane, Pos.CENTER);
btUp.setOnAction(new UpHandler());
btDown.setOnAction(new DownHandler());
btLeft.setOnAction(new LeftHandler());
btRight.setOnAction(new RightHandler());
Scene scene = new Scene(borderPane, 250, 250);
primaryStage.setTitle("Ball"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show();
}
class UpHandler implements EventHandler<ActionEvent> {
public void handle(ActionEvent e) {
circle.up();
System.out.println("Up Button Pressed");
}
}
class DownHandler implements EventHandler<ActionEvent> {
public void handle(ActionEvent e) {
circle.down();
System.out.println("Down Button Pressed");
}
}
class LeftHandler implements EventHandler<ActionEvent> {
public void handle(ActionEvent e) {
circle.left();
System.out.println("Left Button Pressed");
}
}
class RightHandler implements EventHandler<ActionEvent> {
public void handle(ActionEvent e) {
circle.right();
System.out.println("Right Button Pressed");
}
}
public static void main(String[] args) {
launch(args);
}
}
class BallControl extends Pane {
public final double radius = 20;
private double x = radius, y = radius;
private double dx = 1, dy = 1;
private Circle circle = new Circle();
public BallControl() {
getChildren().add(circle);
circle.setCenterX(125.0f);
circle.setCenterY(115.0f);
circle.setRadius(25.0f);
circle.setStroke(Color.BLACK);
circle.setFill(Color.WHITE);
}
protected void moveBall() {
// Check boundaries
if (x < radius || x > getWidth() - radius) {
dx = 0; // Change ball move direction
}
if (y < radius || y > getHeight() - radius) {
dy = 0; // Change ball move direction
}
// Adjust ball position
x += dx;
y += dy;
circle.setCenterX(x);
circle.setCenterY(y);
}
public void up() {
circle.setCenterY(circle.getCenterY() - 10);
}
public void down() {
circle.setCenterY(circle.getCenterY() + 10);
}
public void left() {
circle.setCenterX(circle.getCenterX() - 10);
}
public void right() {
circle.setCenterX(circle.getCenterX() + 10);
}
}
Here is the part that I was hoping would make the program check for boundaries, but it doesn't seem to work:
protected void moveBall() {
// Check boundaries
if (x < radius || x > getWidth() - radius) {
dx = 0; // Change ball move direction
}
if (y < radius || y > getHeight() - radius) {
dy = 0; // Change ball move direction
}
// Adjust ball position
x += dx;
y += dy;
circle.setCenterX(x);
circle.setCenterY(y);
Someone else already asked a very similar question How to make the ball bounce off the walls in JavaFX?
Nevertheless, all you were missing was a check method before making the next move. I added moveAcceptable() and deleted BallControl for simplicity.
public class Ball extends Application
{
Circle circle = new Circle();
Pane bc = new Pane();
public BorderPane borderPane;
#Override
public void start(Stage primaryStage)
{
bc.getChildren().add(circle);
circle.setCenterX(125.0f);
circle.setCenterY(115.0f);
circle.setRadius(25.0f);
circle.setStroke(Color.BLACK);
circle.setFill(Color.WHITE);
HBox pane = new HBox();
pane.setSpacing(10);
pane.setAlignment(Pos.CENTER);
Button btUp = new Button("UP");
Button btDown = new Button("DOWN");
Button btLeft = new Button("LEFT");
Button btRight = new Button("RIGHT");
pane.getChildren().add(btLeft);
pane.getChildren().add(btRight);
pane.getChildren().add(btUp);
pane.getChildren().add(btDown);
borderPane = new BorderPane();
borderPane.setCenter(bc);
borderPane.setBottom(pane);
BorderPane.setAlignment(pane, Pos.CENTER);
btUp.setOnAction(new UpHandler());
btDown.setOnAction(new DownHandler());
btLeft.setOnAction(new LeftHandler());
btRight.setOnAction(new RightHandler());
Scene scene = new Scene(borderPane, 250, 250);
primaryStage.setTitle("Ball"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show();
}
class UpHandler implements EventHandler<ActionEvent>
{
public void handle(ActionEvent e)
{
if (moveAcceptable("up"))
circle.setCenterY(circle.getCenterY() - 10);
System.out.println("Up Button Pressed");
}
}
class DownHandler implements EventHandler<ActionEvent>
{
public void handle(ActionEvent e)
{
if (moveAcceptable("Down"))
circle.setCenterY(circle.getCenterY() + 10);
System.out.println("Down Button Pressed");
}
}
class LeftHandler implements EventHandler<ActionEvent>
{
public void handle(ActionEvent e)
{
if (moveAcceptable("Left"))
circle.setCenterX(circle.getCenterX() - 10);
System.out.println("Left Button Pressed");
}
}
class RightHandler implements EventHandler<ActionEvent>
{
public void handle(ActionEvent e)
{
if (moveAcceptable("Right"))
circle.setCenterX(circle.getCenterX() + 10);
System.out.println("Right Button Pressed");
}
}
public boolean moveAcceptable(String direction)
{
final Bounds bounds = borderPane.getLayoutBounds();
if (direction.equalsIgnoreCase("up"))
{
return (circle.getCenterY() > (bounds.getMinY() + circle.getRadius()));
} else if (direction.equalsIgnoreCase("down"))
{
return circle.getCenterY() < (bounds.getMaxY() - circle.getRadius());
} else if (direction.equalsIgnoreCase("right"))
{
return circle.getCenterX() < (bounds.getMaxX() - circle.getRadius());
} else //left
{
return circle.getCenterX() > (bounds.getMinX() + circle.getRadius());
}
}
public static void main(String[] args)
{
launch(args);
}
}
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); }
}
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);
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");
I am trying to paint only one part of Image. The image human is 159x22 length.
In that image there is 8 human bodies (2 left, 2 right and etc.). If i try to set the Frame to humanSprite.setFrame(1); I will get an error since I specified in the Sprite constructor the size of an Image so there is only one frame.
Well I have tried to divide it by 8 and Ill getjava.lang.IllegalArgumentException`.
Here is the class :
package org.pack.rhynn;
import java.io.IOException;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import java.util.Random;
public class play extends GameCanvas implements Runnable{
int sleep = 30;
private Image map;
private Sprite mapSprite;
private Image human;
private Sprite humanSprite;
private int humanX = getWidth() /2;
private int humanY = getHeight() /2;
public play(){
super(false);
}
public void start(){
try {
map = Image.createImage("/mapas.png");
human = Image.createImage("/human.PNG");
} catch (IOException ioex) {
System.out.println(ioex);
}
mapSprite = new Sprite(map);
mapSprite.defineReferencePixel(100, 150);
mapSprite.setRefPixelPosition(0, 0);
humanSprite = new Sprite(human,159,22);
humanSprite.defineReferencePixel(1, 10);
humanSprite.setRefPixelPosition(humanX, humanY);
Thread thr = new Thread(this);
thr.start();
}
public void run(){
while(true){
updateScreen(getGraphics());
try{
Thread.sleep(sleep);
}catch(Exception e){}
}
}
private void createBackground(Graphics g){
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
}
private void updateScreen(Graphics g){
createBackground(g);
mapSprite.setRefPixelPosition(0, 0);
mapSprite.paint(g);
humanSprite.setRefPixelPosition(humanX, humanY);
humanSprite.setFrame(0);
humanSprite.setPosition(50,50);
humanSprite.paint(g);
flushGraphics();
}
}
The problem seems to be with your image. All frames must have the same width and height and the image final width and hight must be a multiple of them.
For example, let's say all your frames are in a single row. If the frame width is 19 and you have 8 frames, the final image width must be 152.