I am new to JavaFX, and I am following this tutorial, https://wiki.eclipse.org/Efxclipse/Tutorials/Tutorial1, to become familiar with it.
I am trying to set up a DropShadow for my text, and it says the constructor is not recognized. Yet, the tutorial uses the exact line of code with no errors, and according to the DropShadow JavaDoc a constructor of this type should exist.
Exact error that is shown
NOTE: I forgot to delete the line that says "DropShadow d", but this has no effect on the rest of the application.
I attempted to create a DropShadow named 'd' on a separate line of code that followed the exact scheme of the constructor, but this did not work either.
DropShadow d = new DropShadow(2,3,3,Color.RED);
t.setEffect(d);
Appending zeros does not allow the constructor to recognize the values as doubles.
I'm using JDK_1.8_144 and e(fx)clipse 3.0.0.2, i.e. the latest release of each.
So, does anybody know why the DropShadow cannot be constructed?
Thanks!
package myapp;
import com.sun.prism.paint.Color;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.BorderPane;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.awt.*;
public class JavaFX extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane p = new BorderPane();
Text t = new Text("Hello FX");
t.setFont(Font.font("Arial", 60));
t.setEffect(new DropShadow(2,3,3,Color.RED));
p.setCenter(t);
primaryStage.setScene(new Scene(p));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Related
I am trying to learn JavaFX and just stumbled across something I'm confused about. I created a new project in IntelliJ and added a single button.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
private Button firstButton;
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
firstButton = new Button("My First Button");
StackPane layout = new StackPane();
layout.getChildren().add(firstButton);
Scene scene = new Scene(layout, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
When I create the button with text it adds symbols instead of the text.
Window with "My First Button" as commanded text.
When I change the text to something small (I was thinking that it was erroring if the text was longer than the button length) it got even stranger. This is the next example I tried:
firstButton = new Button("E");
And the text I got was: Window with "E" as commanded text.
I have Googled a bunch and have not found anyone talking about this. Either I'm a bad Googler or it's not a common problem. My initial thought was that it was an encoding issue. After I saw the mystery E -> G though I'm thinking there might be something else off.
Any ideas what is going on?
Thank you!
I am following a JavaFX book and one of the examples to show text within the window but there is no text shown within the window. Please help.
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
public void start(Stage myStage){
myStage.setTitle("Demonstrate a Simple Scene Graph");
FlowPane rootNode = new FlowPane();
Scene myScene = new Scene (rootNode,500,500);
myStage.setScene(myScene);
Label myLabel = new Label ("A simple JavaFX label.");
rootNode.getChildren().add(myLabel);
myStage.show();
}
}
I am using intelij with project SDK 10, and project language 10.
Thank you in advance!
update on 29th July 2018. Managed to resolve the problem. Simply input
" -Dprism.order=sw " excluding the double quotation mark into VM options.
I found the solution here : https://www.reddit.com/r/javahelp/comments/84w6i6/problem_displaying_anything_with_javafx_only/
You can send a desktop notification with JavaFx like this (requires jdk 8u20 or later):
package sample;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import org.controlsfx.control.Notifications;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
// Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Button notifyButton = new Button("Notify");
notifyButton.setOnAction(e -> {
Notifications.create().title("Test").text("Test Notification!").showInformation();
});
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(notifyButton, 100, 50));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
But this way you have to create a main window (stage), is it possible to avoid this? I am looking for a way to send notification like using zenity in bash: most of the code is non-gui, but uses some gui elements for informing or interacting with user in a very basic fashion.
It looks like the ControlsFX notifications require a existing stage. You can create a hidden utility stage. Try something like this.
package sample;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.controlsfx.control.Notifications;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
}
public static void main(String[] args) {
new JFXPanel();
notifier("Good!", "It's working now!");
}
private static void notifier(String pTitle, String pMessage) {
Platform.runLater(() -> {
Stage owner = new Stage(StageStyle.TRANSPARENT);
StackPane root = new StackPane();
root.setStyle("-fx-background-color: TRANSPARENT");
Scene scene = new Scene(root, 1, 1);
scene.setFill(Color.TRANSPARENT);
owner.setScene(scene);
owner.setWidth(1);
owner.setHeight(1);
owner.toBack();
owner.show();
Notifications.create().title(pTitle).text(pMessage).showInformation();
}
);
}
}
new JFXPanel() initializes the JavaFX thread without having to extend Application. You have to call this before any calls to Platform.runLater() otherwise you will get a thread exception. You only need to call it once for the whole application though. Honestly it is probably better to create your own notification stage and display it directly. Create a stage like above and put your own contents. You can probably reuse some of the styling from the ControlsFX source.
I use JavaFX NumberBindings in order to calculate certain values. Initially everything works as expected. After a rather small amount of time, however, the binding just stops working. I don't receive an Exception, either.
I've tried several bindings, as well as high- and low-level approaches. Even the calculation itself (when overridden) just stops and isn't called anymore. I've also updated to the latest JDK (1.8.0_05) and rebuilt/restarted everything.
The following Minimal Working Example illustrates the problem. It should System.out.println the current width of the main window to STDOUT. After resizing the window for about 10 seconds, the output simply stops. I've also tried to bind the resulting property to a JavaFX control, in order to ensure the Property's continued usage, but that was of no avail. I believe I'm missing some very basic behaviour of the Property/Bindings here, Google doesn't seem to know that behaviour at all.
import javafx.application.Application;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class BindingsProblem extends Application {
#Override
public void start(Stage primaryStage) {
// Initialization...
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
// Binding - The problem occurrs here!
NumberBinding currentWidthPlusTen = primaryStage.widthProperty().add(10);
IntegerProperty boundNumberProperty = new SimpleIntegerProperty();
boundNumberProperty.bind(currentWidthPlusTen);
boundNumberProperty.addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
System.out.println(newValue.toString());
}
});
}
public static void main(String[] args) {
launch(args);
}
}
The binding uses a WeakListener to observe the value of currentWidthPlusTen. Since you don't keep a reference to the boundNumberProperty, it is eligible for garbage collection as soon as the start(...) method exits. When the garbage collector kicks in, the reference is lost entirely and the binding no longer works.
To see this directly, add the line
root.setOnMousePressed( event -> System.gc());
to the start(...) method. You can force the listener to "stop working" by clicking on the window.
Obviously, that's not what you want: the fix is to retain the reference to boundNumberProperty after start(...) exits. For example:
import javafx.application.Application;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class BindingsProblem extends Application {
IntegerProperty boundNumberProperty;
#Override
public void start(Stage primaryStage) {
// Initialization...
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
// Binding - The problem occurrs here!
NumberBinding currentWidthPlusTen = primaryStage.widthProperty()
.add(10);
boundNumberProperty = new SimpleIntegerProperty();
boundNumberProperty.bind(currentWidthPlusTen);
boundNumberProperty.addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
System.out.println(newValue.toString());
}
});
}
public static void main(String[] args) {
launch(args);
}
}
Update
Anyone running into this issue might also want to look at Tomas Mikula's ReactFX, which provides a cleaner workaround for this (at the expense of using a third-party library, which you would need to spend some time learning). Tomas explains this issue and how ReactFX resolves it in this blog and the subsequent post.
I have a question regarding JavaFX. I taught myself Java and now I'm learning JavaFX.
I've been trying to update the location of a 50x50 black block on the screen. I have a YAxis variable that when I change changes the location of the block.
I want the block to "flow" down the screen similar to Tetris.
My code is messy, as I'm just messing around with it, so please excuse that:
package gamefx;
import javafx.animation.Animation;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class GameFX extends Application {
public Image img = new Image("Block1.png");
public ImageView image = new ImageView(img);
public int YAxis = -200;
#Override
public void start(Stage primaryStage) throws InterruptedException{
primaryStage.setTitle("Game");
StackPane stckp1 = new StackPane();
Scene scn = new Scene(stckp1, 700, 700);
primaryStage.setScene(scn);
primaryStage.show();
image.setTranslateY(YAxis);
stckp1.getChildren().add(image);
}
}
Since you want to see your block moving, you need an animation. See Oracle tutorial for more information.
A sample code, quickly written:
TranslateTransition tt = new TranslateTransition(Duration.millis(2000), image);
tt.setByY(yAxis);
tt.setCycleCount(1);
tt.play();
Side-note: Variable names shall not start with an upper-case letter. Use yAxis instead of YAxis.