JavaFX: pause until animation finishes - java

I have a basic javafx program where a rectangle, simulating an elevator, must move up and down at the push of 'up' and 'down' buttons. I have successfully implemented the code to do this below:
public void handle(ActionEvent event) {
if (event.getSource() == upButton) {
//this should all be put into a 'slideNode' method
TranslateTransition translateTransition1 = new TranslateTransition(Duration.millis(500), theElevator);
translateTransition1.setByX(0);
translateTransition1.setByY(-50);
translateTransition1.setCycleCount(1);
translateTransition1.setAutoReverse(false);
translateTransition1.play();
}
}
The issue I need to solve is what happens when the elevator is partway through this motion and the button is pressed again - the elevator doesn't get the full motion it would have if I waited until it reached its first destination to press the button again!
I understand why this happens, but I'd like to know if there's a way to solve this. I imagine there should be some piece of the API similar to the following, which I can toss at the end of my code:
Pause pause = new Pause(Duration.millis(500));
pause.pause();
Does such a thing exist? How would you solve my problem?

You can disable the button while the TranslateTransition is playing:
public void handle(ActionEvent event) {
if (event.getSource() == upButton) {
//this should all be put into a 'slideNode' method
TranslateTransition translateTransition1 = new TranslateTransition(Duration.millis(500), theElevator);
translateTransition1.setByX(0);
translateTransition1.setByY(-50);
translateTransition1.setCycleCount(1);
translateTransition1.setAutoReverse(false);
translateTransition.statusProperty().addListener((obs, oldStatus, newStatus) ->
button.setDisable(newStatus==Animation.Status.RUNNING));
translateTransition1.play();
}
}

Related

JavaFX - TextArea, how to activate the textarea only on double click?

JavaFX 2.2 - JDK 1.8.0_121
I have a TextArea inside a rectangle which also happens to have a mouse listener. The problem is that when I click on the TextArea it consumes the event and the rectangle doesn't get the click.
Consider the following code for example:
Group g = new Group();
Rectangle rect = new Rectangle(100,100);
TextArea textArea = new TextArea("Test");
textArea.setTranslateX(rect.getX());
textArea.setTranslateY(rect.getY());
textArea.setMinWidth(rect.getWidth());
textArea.setMinHeight(rect.getHeight());
//Calling a method to add an onMouseClickedProperty() mouse listener to the rectangle
addMouseListener(rect)
g.getChildren().addAll(rect, textArea);
In the above case the TextArea takes as much space as the rectangle so when I click on it the onMouseClickedProperty() event gets consumed by the TextArea.
Is there a way to "disable" or "remove" the onMouseClickedProperty() from the TextArea and instead have it fired when a double click occurs? In hopes that the single mouse click will be consumed by the rectangle instead.
Thanks.
EDIT:
I found a solution that works, it's not perfect but it's much more appropriate than what it was discussed in the comments.
Since you can't prevent the TextArea from consuming the MOUSED_PRESSED event the only way to process an event before TextArea areas does is using event filters.
So using the example code from above where i call the method addMouseListener(rect) instead of using just a mouse listener I'm adding an event filter, and instead of adding that to the rectangular shape I add it to the group.
private void addMouseLisenter(Group group){
group.addEventFilter(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
//Code here
}
});
}
This way both the group and the TextArea get the mouse click.
Note: If you want only the group to get the mouse click you can add event.consume().
I hope that helps someone in the future looking for something similar.
I am pretty sure you cannot get away from having to have the MouseListener unfortunately as that is primary class for all mouse events if you wanted the text area to react at all to mouse it has to have the listener.
as far as detecting double clicks there is another thread that contains the answer that you are seeking answered by Uluk Biy.
there is another answer on there proposed by mipa that might answer your question on detection of difference between single and double click however if the Nodes overlap each other.
EDIT
perhaps in this case it might be worth modifying mipa's answer, try adding this to your code (in applicable areas)
Integer clickCount = 0;
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
ScheduledFuture<?> scheduledFuture;
root.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
if (e.getButton().equals(MouseButton.PRIMARY) && clickCount < 1) {
scheduledFuture = executor.schedule(() -> clickAction(), 500, TimeUnit.MILLISECONDS);
}
clickCount += 1;
}
});
private void clickAction() {
if (clickCount == 1) {
//actions for single click
clickCount = 0;
} else if (clickCount > 1) {
//action for multiple clicks
clickCount = 0;
}
}
I found a much more appropriate solution than what was discussed, check EDIT in my question.

Get Mouse Position when pressing a character

I want to get the position of my mouse relative to the frame when I click a shortcut:
#Override
public void handle(KeyEvent keyEvent) {
if (keyEvent.isShortcutDown()) {
if (keyEvent.getCode() == KeyCode.P) {
//Code Here
}
}
}
When the KeyEvent fires, just get the pointer location using MouseInfo.
#Override
public void handle(KeyEvent keyEvent) {
if (keyEvent.isShortcutDown()) {
if (keyEvent.getCode() == KeyCode.P) {
//Code Here
Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
}
}
If you want to continuously track the mouse location, you should use a MouseMoved listener.
Hey here from five years in the future. Since JavaFX still doesn't have this feature for some reason, my solution was to subtract the X/Y position of the cursor's position on the screen (java.awt.MouseInfo) from the X/Y position of the stage. As an example for Y:
MouseInfo.getPointerInfo().getLocation().getY() - stage.getY()
It's not perfect, you'll have to optimize it a bit, but it's an actual solution (the first guy who answered seems to think the screen equals the stage...)

JavaFx multiple click events

I am creating a simple programme in javafx.
private void onClick(final Circle circle) {
circle.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
circle.setTranslateX(150.);
}
});
}
in the "public void start" i match th created circle with the method "onClick"
onClick(circle1);
this code move a circle to the right. How can I move it multiple times? I tried to create more methods analogically "onClick1" but it always respond just to the first click. I need to move it to the right with each click again.
Thank you for your time.
What about
circle.setTranslateX(circle.getTranslateX() + 150.0);

Pilling two obj with OnMousePressed on top of each other in javafx

Been trying around and searching but couldn't find any solution, so I finally decided to give up and ask further...
Creating a javafx app, I load tiles in a TilePane.
This tiles are clickable and lead to a details page of their respective content.
On each tile, if they do belong to a certain pack, I do display the pack name, that is also clickable and lead to a page showing that specific pack content.
So that means the container, the tile, that is a Pane is clickable and on top of it I have a Label that is claickable also. What happens is when I do click the Label, it also triggers the Pane onMousePressed()... Here is a part of the tile creation code, the part focused on the onMousePressed(). I tried to make the Pane react by double click and the Label by single, it works, but I want to Pane to open with a single click.
I would be more than thankfull for any ideas how to solve that.
public DownloadTile (Downloadable upload, MainApp mainApp) {
_mainApp = mainApp;
_upload = upload;
_tile = new Pane();
_tile.setPrefHeight(100);
_tile.setPrefWidth(296);
_tile.setStyle("-fx-background-color: #ffffff;");
_tile.setCursor(Cursor.HAND);
}
public void refresh() {
_tile.getChildren().clear();
_tile.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.isPrimaryButtonDown() /*&& event.getClickCount() == 2*/) {
_mainApp.showDownloadDialog(dt, _upload);
}
}
});
if (_upload.getPack() != null) {
Label pack = new Label();
pack.setText(_upload.getPack());
pack.getStyleClass().add("pack-link");
pack.setCursor(Cursor.HAND);
pack.relocate(10, 48);
_tile.getChildren().add(pack);
pack.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.isPrimaryButtonDown()) {
_mainApp.showPackPage(_upload);
}
}
});
}
}
Your label will receive the mouseclick first (since it's on top), so after you have processed the click, you can stop it from being passed down the chain using 'consume':
pane.setOnMouseClicked(
(Event event) -> {
// process your click here
System.out.println("Panel clicked");
pane.requestFocus();
event.consume();
};

Button Action in JavaFX executes in a wrong sequence

Update 1: Here is a more interesting thing. When i delete the last line { mainapp.showReportingScreen() ;} now program first execute the findAplliedJars method then show processing screen.
I'm working in JavaFX and struggling with actions of a button. What I want is, when that button is clicked:
do something;
show another screen;
do another thing;
show another screen;
But, my program skips the 2. point.
Here is my code:
public class SomeController implements Initializable {
.
.
.
#Override
public void initialize(URL location, ResourceBundle resources) {
.
.
.
someButton.setOnAction(new EventHandler<ActionEvent>(){
public void handle(ActionEvent event) {
Report.setUserName(userNameField.getText());
Report.setPassword(passwordField.getText());
Report.setSmAdress(smAdressField.getText());
mainApp.showProcessingScreen();
Report.findAppliedJars();
mainApp.showReportingScreen();
}
});
}
.
.
.
}
So, without showing processingScreen, my program executes findAppliedJars() and then shows reportingScreen.
What may be the problem? Thanks.
Update 2: Here is my showProcessingScreen() method:
public void showProcessingScreen() {
try {
// Load Report Screen
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("ProcessingScreen.fxml"));
AnchorPane processingScreen = (AnchorPane) loader.load();
// Set report screen into the center of root layout.
rootLayout.setCenter(processingScreen);
ProcessingScreenController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
Unless you somehow pause the execution, the program will continue to execute, and essentially skip over the showing of your processing screen. To show your processing screen for a certain amount of time you need to use an animation and show your reporting screen once the animation has finished. Note the code below is only an outline of what your end result may look like and does not compile.
Transition transition;
// Set up your transition or animation
transition = buildTransition();
// Show your processing screen within the transition
showProcessingScreen();
transition.setOnFinished(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
Report.findAppliedJars();
mainApp.showReportingScreen();
}
});
If you are trying to load something in the background while the processing screen is showing then you will have to use concurrency. If you go this route, the code should look similar to the above, except you would be using the Task class and the setOnSucceeded method. There are other ways to perform this operation, but I believe this is the simplest way.

Categories