How to create non-regular ticks for a JavaFx slider - java

I want to set specific tick on my slider.
For exemple:
[---¦---¦-----------¦------O-¦--]
[-----] : The slider
¦ : The tick
O : The cursor
The purpose is to create a timeline where we can see the highlight.

You can compose your own widget to put the ticks up against a slider. The only tricky bit is to make sure that you setPickOnBounds() to false for the slider. Also putting the ticks into a VBox and then setPickOnBounds() to true for the VBox makes it easier to click on the ticks:
public class SliderSample extends Application {
public static void main(String[] args) {
launch(args);
}
private static Image arrowImage = new Image("https://www.shareicon.net/data/12x12/2015/09/01/94166_arrow_512x512.png");
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new SliderWithTicks(), 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
class SliderWithTicks extends Pane {
private Slider slider = new Slider(0, 100, 30);
SliderWithTicks() {
getChildren().addAll(new Tick(80), new Tick(20), new Tick(30), slider);
slider.minWidthProperty().bind(widthProperty());
slider.setPickOnBounds(false);
}
class Tick extends VBox {
Tick(int value) {
getChildren().add(new ImageView(arrowImage));
setPickOnBounds(true);
setOnMouseClicked(evt -> slider.adjustValue(value));
translateXProperty().bind((slider.widthProperty().subtract(16)).multiply(value / slider.getMax()).add(2));
translateYProperty().set(12);
}
}
}
}

Related

JavaFx: ImageView disappears after moving through the scene

I have a code written using javafx and java 11. As I showed in the below code snippet, when I move my ImageView to right of the scene, The ImageView disappears.
At first:
and then after moving it using arrow keys with the help of scene event listener:
then:
and finally:
I don't use fxml. Here is my demo which has the problem too.
public class HelloApplication extends Application {
public String fetchResource(String path) {
return Objects.requireNonNull(getClass().getResource(path)).toString();
}
#Override
public void start(Stage stage) throws IOException {
Rectangle r = new Rectangle(100, 100);
ImageView spaceShip = new ImageView(fetchResource("spaceShip.png"));
spaceShip.setFitHeight(100);
spaceShip.setFitWidth(100);
spaceShip.setX(0);
spaceShip.setY(0);
EventHandler<KeyEvent> keyListener = event -> {
if (event.getCode() == KeyCode.RIGHT) {
spaceShip.setX(spaceShip.getX() + 20);
}
};
Group game = new Group(spaceShip);
Scene scene = new Scene(game, 1840, 1080);
scene.setOnKeyPressed(keyListener);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
I should mention that I create a rectangle and check the scenario with that, And there was not any problem. I think there is some problem with ImageView.
I couldn't reproduce the issue with your code, but I could with SceneBuilder. You may get the desired result if you wrap the Group in a Pane (at least it works in SceneBuilder).
Group game = new Group(spaceShip);
Pane pane = new Pane(game);
Scene scene = new Scene(pane, 1840, 1080);
stage.setScene(scene);
stage.show();

Javafx - mouse coordinate transformation form inside node to top top subscene

In below code, I have a box added in scene. I am printing the mouse event coordinate. Coordinates are fine when I am not clicking on the box but as soon as I click on the box I get some different set of coordinate relative to some different node. I am trying to get the normalized coordinate, relative to scene only, even if I click on the box. I cant use me.getSceneX()/Y() and cant set box as mouse transparent. So how to carry out this transformation. Thanks.
public class PointConversion extends Application
{
private final static Group worldRoot = new Group();
private final PerspectiveCamera camera = new PerspectiveCamera(true);
private final static Scene scene = new Scene(worldRoot, 1100, 800);
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage)
{
camera.setNearClip(1.0);
camera.setTranslateZ(-6000);
camera.setFarClip(100000.0);
worldRoot.getChildren().add(camera);
scene.setCamera(camera);
primaryStage.setScene(scene);
primaryStage.show();
scene.setOnMousePressed(me ->
{
Point2D mousePoint = new Point2D(me.getX(), me.getY());
if(!(me.getTarget() instanceof Scene))
{
PickResult pickResult = me.getPickResult();
mousePoint = pickResult.getIntersectedNode().localToScene(mousePoint);
}
System.out.println("me.getSource() : " + me.getTarget() + " mousePoint:" + mousePoint);
});
final PhongMaterial blueMaterial = new PhongMaterial();
blueMaterial.setDiffuseColor(Color.web(Color.CRIMSON.toString(), 0.25));
blueMaterial.setSpecularColor(Color.web(Color.CRIMSON.toString(), 0.25));
Box cubiod = new Box(500, 500, 500);
cubiod.setMaterial(blueMaterial);
worldRoot.getChildren().add(cubiod);
}
}

displaying a tooltip in javafx brings its stage into the foreground

I am trying to work around this bug in the jdk: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8088624
public class Blubb extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Button btn = new Button("Click");
btn.setTooltip(new Tooltip("Blubb"));
Scene scene = new Scene(new BorderPane(btn), 320, 240);
primaryStage.setScene(scene);
primaryStage.show();
Stage secondStage = new Stage();
secondStage.setScene(new Scene(new BorderPane(new Button("Click")), 320, 240));
//secondStage.initOwner(primaryStage);
secondStage.show();
}
}
If the button on the primary stage is hovered, it will come in front of the second stage. I found that calling initOwner() on a Stage will eliminate this behavior.
Now my problem is following: I have multiple "popups" that have a common owner (the primary stage). Hovering over controls on the primary stage doesn't cause any unexpected behavior after the initOwner() workaround. If you however hover over controls in a popup while another popup was in focus, the hovered popup will steal focus.
Is there a way I can work around this bug for not only the primary stage but also the popups?
UPDATE: turns out my workaround has undesired side-effects. Javadocs for Stage state following:
A stage will always be on top of its parent window.
So additionally, what would be a workaround that makes the popup not "always on top" and minimizable?
There is a way to get around it by overlaying StackPanes. Create your Scene with a StackPane so that you can add another StackPane when the stage has lost its focus. The overlayed pane will prevent Tooltips or anything else happening on mouse-over while the pane is not in focus. You may also minimize any of your stages and they won't be always-on-top.
public class Blubb extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Button button_1 = new Button("Button #1");
button_1.setTooltip(new Tooltip("Blubb #1"));
StackPane primary = new StackPane(new BorderPane(button_1));
primaryStage.setScene(new Scene(primary, 320, 240));
addStageFocusListener(primaryStage, primary);
primaryStage.show();
Button button_2 = new Button("Button #2");
button_2.setTooltip(new Tooltip("Blubb #2"));
StackPane second = new StackPane(new BorderPane(button_2));
Stage secondStage = new Stage();
addStageFocusListener(secondStage, second);
secondStage.setScene(new Scene(second, 320, 240));
secondStage.show();
}
public void addStageFocusListener(Stage stage, StackPane stackPane) {
stage.focusedProperty().addListener(new ChangeListener<Boolean>(){
public final StackPane preventTooltip = new StackPane();
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if(stage.isFocused()) {
if(stackPane.getChildren().contains(preventTooltip)) {
stackPane.getChildren().remove(preventTooltip);
}
} else {
stackPane.getChildren().add(preventTooltip);
}
}
});
}
}
You can try this:
public static final disableMouseEventOnUnfocus(final Stage stage)
{
if (stage == null
|| stage.getScene() == null
|| stage.getScene().getRoot() == null)
return;
else
{
stage.getScene().getRoot().mouseTransparentProperty().bind(stage.focusedProperty().not());
}
}
I didn't try it though, but if it works, this should be a good alternative. There is no need to restructure your layout, and you can leave all your layout in FXML, without specifying fx:id for the tooltips.
I've come up with this alternative solution, as I've found it easier in my case to subclass Tooltip and apply a fix there. I just overload the show() method to only show if the owning window is focused. It's working like a charm for me...
public class FixedTooltip extends Tooltip {
public FixedTooltip(String string) {
super(string);
}
#Override
protected void show() {
Window owner = getOwnerWindow();
if (owner.isFocused())
super.show();
}
}
You could try to unset the tooltip whenever the node's window loses focus. Such as below:
public class Blubb extends Application {
public static void main(String[] args) {
launch(args);
}
public static void installTooltip(Node n, Tooltip tp)
{
Window w = n.getScene().getWindow();
w.focusedProperty().addListener((val, before, after) -> {
if (after)
Tooltip.install(n, tp);
else
Tooltip.uninstall(n, tp);
});
if (w.isFocused())
Tooltip.install(n, tp);
else
Tooltip.uninstall(n, tp);
}
#Override
public void start(Stage primaryStage) throws Exception {
Tooltip tp = new Tooltip("Blubb");
Button btn = new Button("Click");
Scene scene = new Scene(new BorderPane(btn), 320, 240);
primaryStage.setScene(scene);
//primaryStage.show();
Stage secondStage = new Stage();
secondStage.setScene(new Scene(new BorderPane(new Button("Click")), 320, 240));
//secondStage.initOwner(primaryStage);
secondStage.show();
primaryStage.show();
installTooltip(btn, tp);
}
}
Of course, you would have to call installTooltip after the node is added to the component.

JavaFx Transparent window - yes please. Mouse transparent - no thanks

I would like to create a simple JavaFx class that shows the user a translucent rectangle (say an arbitrary 50% transparency) covering the users screen. It should simply allow me to get the Point of a mouse click event. This sounds trivial, but when I create transparent windows they always seem to be transparent to mouse events rather than just my requirement of semi-transparent visibility. The mouse event is never triggered.
I've used setMouseTransparent(false) on the rectangle and the root pane, but this makes no difference. I'd be really grateful if somebody could indicate any errors/misconceptions.
Here's the trivial test class I have created:
public class ClickScreen implements MouseListener {
private ClickScreenListener listener;
private Stage window;
private Point point;
public ClickScreen(ClickScreenListener listener) {
// Get screen size
Rectangle2D r = Screen.getPrimary().getBounds();
// Something to put stuff in
StackPane root = new StackPane();
// Translucent rectangle on the pane
Rectangle rectangle = new Rectangle(r.getWidth(), r.getHeight());
rectangle.setFill(Color.rgb(183, 183, 183, 0.5));
root.getChildren().add(rectangle);
Scene scene = new Scene(root, r.getWidth(), r.getHeight());
scene.setFill(null);
window = new Stage();
window.initStyle(StageStyle.TRANSPARENT);
window.setTitle("Click drop location");
window.setScene(scene);
this.listener = listener;
}
public Point getLocation(){
return point;
}
#Override
public void mouseClicked(MouseEvent e) {
point = e.getLocationOnScreen();
listener.screenClicked(point);
}
}
Edit:
A simpler example of the transparency issue I am experiencing is from this Hello World! example. When I mouse over the button, it's about 50:50 chance of clicking the button or just clicking "through" and giving focus to the underlying window (which is usually eclipse in my case). Would love you thoughts on this.
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
scene.setFill(null);
primaryStage.setScene(scene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.show();
}
}
Check your Imports
You are using some kind of weird setup where you are mixing AWT/Swing classes and JavaFX classes, which really isn't advised (and doesn't work at all in the combination and manner you have used). Just be careful in your JavaFX programs not to import any java.awt.* or javax.swing.* classes unless you really know what you are doing in mixing code for two different toolkits.
Sample Solution
Here is a sample solution which imports only JavaFX classes and utilizes JavaFX events, but otherwise tries to stick to the coding/callback style of the sample code in your question. (The sample could be further simplified through use of Java 8 lambdas).
import javafx.application.Application;
import javafx.event.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.*;
public class ClickListenerSample
extends Application
implements ClickScreenListener {
private Label clickFeedbackLabel = new Label("");
#Override public void start(Stage stage) {
Button listen = new Button("listen");
listen.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
new ClickScreen(ClickListenerSample.this);
}
});
VBox layout = new VBox(10);
layout.getChildren().setAll(
listen,
clickFeedbackLabel
);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout, 100, 80));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
#Override public void screenClicked(Point2D point) {
clickFeedbackLabel.setText(point.getX() + ", " + point.getY());
}
}
interface ClickScreenListener {
void screenClicked(Point2D point);
}
class ClickScreen {
private ClickScreenListener listener;
private Stage window;
private Point2D point;
public ClickScreen(ClickScreenListener listener) {
// Get screen size
Rectangle2D r = Screen.getPrimary().getBounds();
// Something to put stuff in
StackPane root = new StackPane();
root.setStyle("-fx-background-color: null;");
// Translucent rectangle on the pane
Rectangle rectangle = new Rectangle(r.getWidth(), r.getHeight());
rectangle.setFill(Color.rgb(183, 183, 183, 0.5));
root.getChildren().add(rectangle);
Scene scene = new Scene(root, r.getWidth(), r.getHeight());
scene.setFill(null);
window = new Stage();
window.initStyle(StageStyle.TRANSPARENT);
window.setTitle("Click drop location");
window.setScene(scene);
scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
point = new Point2D(event.getScreenX(), event.getScreenY());
listener.screenClicked(point);
window.hide();
}
});
window.show();
this.listener = listener;
}
public Point2D getLocation(){
return point;
}
}

Is it possible to style ProgressIndicator?

I like ProgressIndicator, except I'd like to change it's color and circle width. Is it possible (with css or without)?
Of course, it's very easy.
You can find all related methods and styles in doc:
API: http://docs.oracle.com/javafx/2/api/index.html?overview-summary.html
CSS: http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html#progressindicator
public class HelloProgressIndicator extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
Scene scene = new Scene(root, 200, 200);
ProgressIndicator pi = new ProgressIndicator(.314);
// changing color with css
pi.setStyle(" -fx-progress-color: red;");
// changing size without css
pi.setMinWidth(150);
pi.setMinHeight(150);
root.getChildren().add(pi);
stage.setScene(scene);
stage.show();
}
}
Using CSS in JavaFX 19
.progress-indicator:indeterminate .segment {
-fx-background-color: red;
}

Categories

Resources