Please have a look at my first JavaFX application code
package helloworld;
import javafx.application.*;
import javafx.stage.*;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
public class HelloWorld2 extends Application
{
#Override
public void start(Stage stage)
{
stage.setTitle("Hello World");
Button btn = new Button();
btn.setText("Hello");
btn.setOnAction(new Action());
StackPane pane = new StackPane();
pane.getChildren().add(btn);
stage.setScene(new Scene(pane, 300,250));
stage.show();
}
private class Action implements EventHandler
{
#Override
public void handle(Event arg0)
{
System.out.println("JavaFX World");
}
}
public static void main(String[]args)
{
launch(args);
}
}
I am getting "Unsafe Operation" warning when I run this. Application runs without any exceptions. I believe unsafe thing is coming because I have to put keyword in some place, but I don't know where. Please help!
You should to specify the type of Event
private class Action implements EventHandler<ActionEvent>
{
#Override
public void handle(ActionEvent arg0)
{
System.out.println("JavaFX World");
}
}
Related
I'm making JavaFX application with Scene Builder. I have Main Class that launch Controller with main window.
I have a label in the Controller class
I need to assign keyboard key press in main window.
Example: if I press '1' on keyboard the text of a label should be set as "key 1 is pressed.
If I press "2" on keyboard the text should be set as "key 2 is pressed"
How Can I do that?
I've tried to use this code in initialize method, but nothing happens:
category1.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent ke) {
KeyCode kc = ke.getCode();
if((kc.equals(KeyCode.D))) {
category1.setText("Key D is pressed");
}
}
});
Main Class:
package src.card;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.input.*;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
try {
Parent root = FXMLLoader.load(getClass().getResource("resources/fxml/card.fxml"));
Scene scene = new Scene(root, 1600, 600);
primaryStage.setScene(scene);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setMaximized(true);
primaryStage.setResizable(true);
primaryStage.getIcons().add(new Image("src/card/resources/logo-icon.png"));
primaryStage.show();
//adding resize and drag primary stage
ResizeHelper.addResizeListener(primaryStage);
//assign ALT+ENTER to maximize window
final KeyCombination kb = new KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN);
scene.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (kb.match(event)) {
primaryStage.setMaximized(!primaryStage.isMaximized());
primaryStage.setResizable(true);
Controller cont = Context.getInstance().getController();
if (!primaryStage.isMaximized()) {
cont.getBtnFont().setPrefWidth(20);
cont.getBtnPalette().setPrefWidth(20);
cont.getBtnQuestCards().setPrefWidth(20);
cont.getBtnNonQuestCards().setPrefWidth(20);
} else if (primaryStage.isMaximized()){
cont.getBtnFont().setPrefWidth(50);
cont.getBtnPalette().setPrefWidth(50);
cont.getBtnQuestCards().setPrefWidth(50);
cont.getBtnNonQuestCards().setPrefWidth(50
);
}
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
Controller:
#FXML private Label category1
#FXML public void initialize(URL location, ResourceBundle resources) {
category1.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent ke) {
KeyCode kc = ke.getCode();
if((kc.equals(KeyCode.D))) {
category1.setText("Key D is pressed");
}
}
});
//register Controller in Context Class
Context.getInstance().setController(this);
}
EDIT:
I've tried to use it in initialize method:
category1.getScene().setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent ke) {
KeyCode kc = ke.getCode();
if((kc.equals(KeyCode.D))) {
category1.setText("Key D is pressed");
}
}
});
and I got errors:
javafx.fxml.LoadException:
/D:/IDEA%20Projects/CategoryCards/out/production/CategoryCards/src/card/resources/fxml/card.fxml
at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2603)
If I remove getScene() from category1 - everything is going fine and application launch
It seems when I use getScene() it try to get fxml file from out folder, not my main folder, but how can I fix this?
You can do so by setting key press event(setOnKeyPressed) to parent of Label
instead of Scene. Trying to add event to Scene will give error because initialize will be called before creation of the Scene.
Let's say you have FXML file called sample.fxml and In that file you have GridPane having id root and a Label having id category1
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.GridPane?>
<GridPane fx:controller="Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10" fx:id="root">
<Label text="Category" fx:id="category1"/>
</GridPane>
And you have Controller class called Controller. To change label of category1 when any key is pressed, first you have to set category1 focus traversable by calling setFocusTraversable method on category1 and passing true. And then you have to add key press event on root(parent of category1), As shown below
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable{
#FXML private Label category1;
#FXML private GridPane root;
#Override
public void initialize(URL location, ResourceBundle resources){
category1.setFocusTraversable(true);
root.setOnKeyPressed(this::handle);
}
private void handle(KeyEvent keyEvent){
category1.setText("Key " + keyEvent.getCode().getName() + " is pressed");
}
}
And here is simple version of Main class
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 300, 275);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I want to immediately after increasing the value of i appear in the label
Example:
-in i=0 show 0
-in i=1 show 01
-in i=2 show 012
Can You Help me
import javafx.application.Application;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Example extends Application{
#Override
public void start (Stage primaryStage) {
Pane pane=new Pane();
Label label=new Label();
Button bt=new Button("Start");
pane.getChildren().addAll(bt,label);
bt.setOnAction(e->{
for (int i=0;i<10000000;i++) label.setText(label.getText()+i);
});
Scene scene = new Scene(pane,1000,500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The problem is that you update the label's value while you are on the user interface's thread. JavaFX works with a model where the updates are done at each 'tick' (60 fps). All the updates done are only visible once your eventhander's code has finished.
Additionally, given that this is a long running task it will result in an unresponsive user interface.
You should use a Worker to do the long running task. See the tutorial on asynchronous processing. Note that it will not guarantee that you will see all values as the worker can be quicker than the user interface updates and the system will coalesce these updates.
You can use Timeline to accomplish this task.
import java.util.concurrent.atomic.AtomicLong;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* #author blj0011
*/
public class JavaFXApplication177 extends Application
{
#Override
public void start(Stage primaryStage)
{
AtomicLong i = new AtomicLong();
Label label = new Label();
Button btn = new Button();
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(.5), (ActionEvent event) -> {//This controls how fast this should run. This example happens every half of a second
label.setText(label.getText() + Long.toString(i.getAndIncrement()));
}));
timeline.setCycleCount(10000000);//This controls the amount of time this should run
timeline.setOnFinished(event -> {//This tells what to do once cycle count is reached
btn.setDisable(false);
});
btn.setText("Start");
btn.setOnAction((ActionEvent event) -> {
btn.setDisable(true);
timeline.play();
});
StackPane stackPane = new StackPane(label);
VBox root = new VBox(stackPane, new StackPane(btn));
VBox.setVgrow(stackPane, Priority.ALWAYS);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Test5 extends Application {
private String text = "";
private int i;
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
StackPane pane = new StackPane();
Label lblText = new Label("");
pane.getChildren().add(lblText);
new Thread(new Runnable() {
#Override
public void run() {
try {
for (i=0;i<10000;i++) {
Platform.runLater(new Runnable() { // Run from JavaFX GUI
#Override
public void run() {
lblText.setText(lblText.getText()+i);
}
});
Thread.sleep(200);
}
}
catch (InterruptedException ex) {
}
}
}).start();
Scene scene = new Scene(pane, 200, 50);
primaryStage.setTitle("FlashText"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
}
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
//Your First Task #1
//Here UI won't be interrupted
Platform.runLater(new Runnable() {
#Override
public void run() {
//Your Second Task After Completion Of First One #2
}
});
return null;
}
};
}
};
service.start();
}
#1. The task that you want to perform in the background ex. loading the data has to be placed here. It's working great for me.
#2. Once the background task is finished this thread will be executed so Ui and background thread will run separately and smoothly.
I know it's too late for this answer but I just wanted to share what I did this might help!
I'm creating a large program to track finances. Because of this, I've cleaned up my code by positioning elements in other classes, then using aggregation to implement them in my main program. The only problem is I've started to work on interaction and handling button presses, but I can't register any button presses normally. Here's clean sample code to highlight the problem.
Main Execution Class
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.Group;
import javafx.application.Application;
import javafx.scene.layout.Pane;
import javafx.event.ActionEvent;
public class testingButton extends Application{
private buttonClass add;
#Override
public void start(Stage stage){
add = new buttonClass();
Pane root = new Pane();
root.getChildren().addAll(add.getB());
Scene scene = new Scene(root, 150,150);
stage.setTitle("Testing Visual elements");
stage.setScene(scene);
stage.show();
}
public void processButtonPress(ActionEvent event){
if(event.getSource() == add.getB()){
System.out.println("testing");
}
}
public static void main(String[] args){
launch(args);
}
}
Aggregate button class
import javafx.scene.control.Button;
public class buttonClass{
private Button b;
public buttonClass(){
b = new Button("Button");
b.setLayoutX(50);
b.setLayoutY(50);
}
public Button getB(){
return b;
}
}
How can I get the button press to register? Any help is appreciated. Thanks!
Here is the code you need...
you need to apply an actionevent to the button not try to get a button from actionevent
public class JavaApplication3 extends Application {
ButtonClass add;
#Override
public void start(Stage stage) {
add = new ButtonClass();
Pane root = new Pane();
root.getChildren().add(add);
Scene scene = new Scene(root, 150, 150);
stage.setTitle("Testing Visual elements");
stage.setScene(scene);
stage.show();
add.setOnAction((javafx.event.ActionEvent event) -> {
System.out.println("Button pressed");
});
}
public static void main(String[] args) {
launch(args);
}
and the button class
public class ButtonClass extends Button {
private Button b;
public ButtonClass() {
b = new Button("Button");
b.setLayoutX(50);
b.setLayoutY(50);
}
i am trying to influence a UI-Element during an event in javaFX.
void buttonClicked(ActionEvent e) {
labelInfo.setText("restarting - might take a few seconds");
jBoss.restart();
labelInfo.setText("JBoss successfully restarted");
}
The action "jBoss.restart()" waits till the JBoss is restarted.
The problem:
the text "restarting - ..." is not displayed. The application waits till the JBoss is restarted and then it shows the Text "JBoss successfully restarted".
My thoughts:
the scene is refreshed AFTER the event is completed. So the first label-change will not happen.
How can i show a info message during an event?
The problem it's that the FX Thread has no safe operations. So I'm guessing that jBoss.restart() it's taking a lot of time. So you have to put this command in a Service. Also I recommend to you a progress indicator to show to the user you are making a long operation.
Here it is an example but I encourage you to go to Concurrency in JavaFX and take a deep look on it. Maybe there are other things that can help you.
import javafx.application.Application;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
private Label labelInfo;
private Button button;
private ProgressIndicator progressIndicator;
#Override
public void start(Stage stage) throws Exception {
VBox vbox = new VBox(5);
vbox.setAlignment(Pos.CENTER);
labelInfo = new Label();
button = new Button("Restart");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
buttonClicked(event);
}
});
progressIndicator = new ProgressIndicator(-1);
progressIndicator.setVisible(false);
vbox.getChildren().addAll(labelInfo, progressIndicator, button);
Scene scene = new Scene(vbox, 300, 200);
stage.setScene(scene);
stage.show();
}
void buttonClicked(ActionEvent e) {
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
updateMessage("restarting - might take a few seconds");
// Here the blocking operation
// jBoss.restart();
Thread.sleep(10000);
updateMessage("JBoss successfully restarted");
return null;
}
};
}
};
// Make the progress indicator visible while running
progressIndicator.visibleProperty().bind(service.runningProperty());
// Bind the message of the service to text of the label
labelInfo.textProperty().bind(service.messageProperty());
// Disable the button, to prevent more clicks during the execution of
// the service
button.disableProperty().bind(service.runningProperty());
service.start();
}
}
JavaFX2's TableView features
"Column reordering by the user at runtime".
I'd like to disable this feature for one specific table in my Application.
Looking at the API doc, there is no obvious API hook for this.
There is, however, the columns-property. According to the doc, it represents
The TableColumns that are part of this TableView. As the user reorders the TableView columns, this list will be updated to reflect the current visual ordering.
Hoping that I'd at least be able to reset a change after it occurred, I tried adding a listener to reset changes after the fact.
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class TableTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
TableView tableView = new TableView();
tableView.getColumns().setAll(new TableColumn(), new TableColumn());
tableView.getColumns().addListener(new ListChangeListener() {
#Override
public void onChanged(Change change) {
if (change.wasPermutated()){
change.reset();
}
}
});
stage.setScene(new Scene(tableView));
stage.show();
}
}
However, the listener aborts with an IllegalStateException when I ask for wasPermutated.
Is there a way to prevent reordering, or at least revert it programatically?
See below a SSCCE that shows that the listener gets called - but the flag is set to added when moving columns. Note that you need to call next() before using the change or you will get an IllegalStateException. See the javadoc of ListChangeListener.Change for a simple canonical example.
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class TableTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
final TableView tableView = new TableView();
final TableColumn[] columns = {new TableColumn("1"), new TableColumn("2")};
tableView.getColumns().setAll(columns);
tableView.getColumns().addListener(new ListChangeListener() {
public boolean suspended;
#Override
public void onChanged(Change change) {
change.next();
if (change.wasReplaced() && !suspended) {
this.suspended = true;
tableView.getColumns().setAll(columns);
this.suspended = false;
}
}
});
stage.setScene(new Scene(tableView));
stage.show();
}
}