Is there any event handler present in Java FX, if i close a window directly bt pressing [X] button on Top right side.
Which events gets fire in this case ?
Nothing is working so far , neither setOnHiding not setOnCloseRequest()
Please help.
Try this one
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class Main extends Application {
#Override
public void start(Stage stage) {
Text text = new Text("!");
text.setFont(new Font(40));
VBox box = new VBox();
box.getChildren().add(text);
final Scene scene = new Scene(box,300, 250);
scene.setFill(null);
stage.setScene(scene);
stage.show();
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
System.out.println("Stage is closing");
}
});
stage.close();
}
public static void main(String[] args) {
launch(args);
}
}
Source Stage close event : Stage « JavaFX « Java
Related
I have a GUI that uploads a bunch of settings via serial once the 'upload' button is pressed.
This upload takes some time and has some Thread.sleep's in it, so during upload the GUI freezes but still allows the user to press the upload button some more, which results in even more freezing.
What would be the best way to directly disable the upload button, upload in the background, and enable the button when finished?
Thanks for the reply.
To answer my own question, I already found a simple solution by creating a task:
public class uploadTask extends Task<String> {
#Override
protected String call() throws Exception {
}
}
I would recommend using RxJavaFx.
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.rxjavafx.observables.JavaFxObservable;
import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
import io.reactivex.schedulers.Schedulers;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class BackgroundTaskButtonApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Button button = new Button("Run!");
StackPane stackPane = new StackPane(button);
Scene scene = new Scene(stackPane, 400, 400);
stage.setScene(scene);
stage.show();
JavaFxObservable.actionEventsOf(button)
.doOnNext(event -> button.setDisable(true))
.switchMap(event -> Observable.just(event).observeOn(Schedulers.single()).doOnNext(e -> runLongTask()))
.observeOn(JavaFxScheduler.platform())
.doOnNext(event -> button.setDisable(false))
.subscribe();
}
private void runLongTask() {
System.out.println(Thread.currentThread().getName() + " runLongTask()");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I want to fire some action when there was NO drag event between mouse pressed and released events. In other words - when user kept his mouse cursor still while clicking.
The question is specificly about rective way achive it. Really would appreciate RxJava2 solution (I'm using it with RxJavaFx).
Observable.combineLatest(
JavaFxObservable.eventsOf(panel1, MouseEvent.DRAG_DETECTED).map(event -> System.currentTimeMillis()).startWith(System.currentTimeMillis()),
JavaFxObservable.eventsOf(panel1, MouseEvent.MOUSE_PRESSED).map(event -> System.currentTimeMillis()),
JavaFxObservable.eventsOf(panel1, MouseEvent.MOUSE_RELEASED).map(event -> System.currentTimeMillis()),
(dragDectedMillis, pressedMillis, releasedMillis) -> releasedMillis > pressedMillis && dragDectedMillis < pressedMillis ? true : false)
.filter(noDragDetected -> noDragDetected)
.subscribe(next -> System.out.println("Action"));
import io.reactivex.Observable;
import io.reactivex.rxjavafx.observables.JavaFxObservable;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class PressedReleasedWithoutDraggedApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
StackPane stackPane = new StackPane();
stackPane.setPrefSize(800, 600);
stage.setScene(new Scene(stackPane));
stage.show();
Observable<MouseEvent> mousePressedObservable = JavaFxObservable.eventsOf(stackPane, MouseEvent.MOUSE_PRESSED);
Observable<MouseEvent> mouseReleasedObservable = JavaFxObservable.eventsOf(stackPane, MouseEvent.MOUSE_RELEASED);
Observable<MouseEvent> mouseDraggedObservable = JavaFxObservable.eventsOf(stackPane, MouseEvent.MOUSE_DRAGGED);
mousePressedObservable
.switchMap(mousePressed -> mouseReleasedObservable.takeUntil(mouseDraggedObservable))
.subscribe(next -> System.out.println("PRESSED'N'RELEASED without DRAGGED"));
}
}
I have a JavaFX GUI where I wish to intercept the pressing of the SpaceBar and use it to call a method. I wrote an EventFilter that seems to do the trick. It includes the command event.consume() which I believe is supposed to keep the KeyEvent from propagating to the various controls.
My issue is that when I added a TextField, and this field has the focus, the Spacebar presses are not being consumed as I thought they would. The " " are captured by the TextField. I would like to intercept and prevent the " " from being added to the TextField.
What am I leaving out in the code below in order to keep " " from reaching the TextField? The api, if I am reading it correctly, says that filters registered with a parent control can intercept an event before it reaches the children nodes. But even when putting the filter directly on the TextField, I am still having " " chars appear in the TextField.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SpaceIntercept extends Application implements EventHandler <KeyEvent>
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
TextField textField = new TextField("asdf");
Group root = new Group();
Scene scene = new Scene(root, 200, 100);
scene.addEventFilter(KeyEvent.ANY, event -> handle(event));
// root.addEventFilter(KeyEvent.ANY, event -> handle(event));
// textField.addEventFilter(KeyEvent.ANY, event -> handle(event));
root.getChildren().add(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.SPACE)
{
if (event.getEventType() == KeyEvent.KEY_PRESSED)
{
System.out.println("Code that responds to SpaceBar");
}
event.consume();
}
}
}
The text field is probably listening for KEY_TYPED events. As is well-documented, getCode() returns KeyCode.UNDEFINED for a KEY_TYPED event. Thus you do not catch this case.
You can check for the character variable as well as the code variable to handle all cases:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SpaceIntercept extends Application implements EventHandler <KeyEvent>
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
TextField textField = new TextField("asdf");
Group root = new Group();
Scene scene = new Scene(root, 200, 100);
scene.addEventFilter(KeyEvent.ANY, event -> handle(event));
// root.addEventFilter(KeyEvent.ANY, event -> handle(event));
// textField.addEventFilter(KeyEvent.ANY, event -> handle(event));
root.getChildren().add(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.SPACE || " ".equals(event.getCharacter()))
{
if (event.getEventType() == KeyEvent.KEY_PRESSED)
{
System.out.println("Code that responds to SpaceBar");
}
event.consume();
}
}
}
A simple solution i can think,which although doesn't blocks the space from being added to the TextField,but it replaces it after it has been added almost instantly is adding a changeListener to the TextProperty of the TextField:
textField.textProperty().addListener((observable,oldValue,newValue)->{
textField.setText(textField.getText().replace(" ", ""));
});
This may also be helpfull http://fxexperience.com/2012/02/restricting-input-on-a-textfield/
I am using ControlsFX - HiddenSidesPane where i add some link(ToggleButtons) to be clicked for navigation.
The problem i have is whenever anything is clicked, the HiddenSiddesPane hides.
The desired behavior is when anything inside it is clicked it should not close/hide, unless cursor hovers out of it.
SSCCE to demonstrate undesired behavior
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.controlsfx.control.HiddenSidesPane;
public class MyHiddenSidesPaneDemo extends Application{
public static void main(String[] args) { Application.launch(args); }
#Override
public void start(Stage primaryStage) throws Exception {
VBox root = new VBox();
TableView tv = new TableView();
HiddenSidesPane hiddenSidesPane = new HiddenSidesPane();
hiddenSidesPane.setContent(tv);
hiddenSidesPane.setLeft(new ListView());
root.getChildren().addAll(hiddenSidesPane);
primaryStage.setTitle("HiddenSidesPane Example Demo");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Try the following:
ListView listView = new ListView();
hiddenSidesPane.setLeft(listView);
listView.setOnMouseEntered(e->hiddenSidesPane.setPinnedSide(Side.LEFT)); //Keep left side pinned
listView.setOnMouseExited(e->hiddenSidesPane.setPinnedSide(null)); //unpin when mouse exits
How to implement something kinda internal frame in JavaFx 2.0 specifically?
My attempt is as so..
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
ConnectDb connection;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
final Stage stage1 = new Stage();
StackPane pane = new StackPane();
Button btn = new Button("Click Me");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
connection = new ConnectDb();
try {
connection.start(stage1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Fire some thing..");
}
});
pane.getChildren().add(btn);
stage.setScene(new Scene(pane ,200, 300));
stage.show();
}
}
ConnectDb.java
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ConnectDb extends Application {
#Override
public void start(Stage stage) throws Exception {
StackPane pane = new StackPane();
Button btn = new Button("Click On Button which is me");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Something here..");
}
});
pane.getChildren().add(btn);
stage.setScene(new Scene(pane ,200, 300));
stage.show();
}
}
First of all, for your approach, you don't really need to (and therefore should not) extend ConnectDb from Application as you just use the start method to create new stages. You just need one Application class (in your case Main). You could just as well create the new stage/scene in your first event handler.
Secondly, there is no real MDI support in JavaFX 2.1. Right now, you can just have multiple Stages (which is the equivalent to having multiple windows/frames). But you cannot have something like an internal frame in a desktop pane.
I guess you could take the following actions:
Just use multiple Stages (windows) with the drawback that they will float quite uninspiredly on your desktop
Use Swing as a container (with JDesktopPane and JInternalFrame) and integrate JavaFX (here's a nice How-To)
Implement your own framework that emulates MDI behavior
Find a framework that provides MDI behavior
Wait for a future release of JavaFX that hopefully provides MDI support (as far as I know, there's a change request pending...)
Create parent AncorPane.
Add several children AnchorPanes to it. They will serve as internal frames. Add different content to these.
Set children AnchorPanes invisible.
Add buttons to hide, resize or close children AnchorPanes. When needed, call function to set all children AnchorPanes invisible, except for one.