Right now as soon as the user clicks the first button the second one appears instantly, with or without thread. Is there a better way to do this?
// Register an event filter for a single node and a specific event type
getBtn1().addEventFilter(MouseEvent.MOUSE_CLICKED,
event -> {
if (event.getSource().equals(getBtn1())) {
getBtn1().setGraphic(new ImageView(getCrossImage()));
event.consume();
}
if (event.isConsumed()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
getBtn2().setGraphic(new ImageView(getNoughtsImage()));
}
});
You must not block the JavaFX application thread. Otherwise layout/rendering is paused until the method call completes. Since event filters run on the application thread you need to rewrite the code and allow the handler to complete without delay.
It's possible to use a PauseTransition for this purpose:
// Register an event filter for a single node and a specific event type
getBtn1().addEventFilter(MouseEvent.MOUSE_CLICKED,
event -> {
if (event.getSource().equals(getBtn1())) {
getBtn1().setGraphic(new ImageView(getCrossImage()));
event.consume();
PauseTransition pause = new PauseTransition(Duration.seconds(0.1));
pause.setOnFinished(evt -> getBtn2().setGraphic(new ImageView(getNoughtsImage())));
pause.play();
}
});
Related
I would like to show ActivityIndicator object after user tap the login button on page. Unfortunately there is small problem to do that because it seems like ActivityIndicator change state after entire method is completed. This is code I wrote so far:
private void Login(object sender, EventArgs ev)
{
BusyIndicator.IsVisible = true; //<- here I want to show indicator
try
{
//some input validation, connection opening etc
ConnectionHandler.OpenConnection(ServerIP, "dmg", false);
}
catch (Exception e)
{
Logging.Error(e.Message, "Connection", e);
}
}
When I set breakpoint after BusyIndicator.IsVisible = true; there is absolutely no change in app. However I noticed that when method is completed then indicator is shown. Is this a correct behavior of this control?
Why I need this? Because field validation and connecting with server takes some time and I need to show to user that something happens in background. Login function takes ~1 sec so indicator show and hide quickly I can't even see any change.
How can I show indicator immediately after user tap a button?
Your problem is that Login() method is being executed in the UI thread. So, despite setting BusyIndicator.IsVisible = true;, the thread continues tio execute the method to get data, so the UI does not respond.
Solution, run the OpenConnection in a different thread:
private async void Login(object sender, EventArgs ev)
{
BusyIndicator.IsVisible = true; //<- here I want to show indicator
try
{
//some input validation, connection opening etc
await Task.Run(() => { ConnectionHandler.OpenConnection(ServerIP, "dmg", false);});
}
catch (Exception e)
{
Logging.Error(e.Message, "Connection", e);
}
}
The primary purpose is to Print "click operation has been performed" in the console, if any click is performed on the page loaded in the embedded browser, for achieving the aforementioned behavior I got the below code, it shows error.
((EventTarget) el).addEventListener("click", listener, false);
Here is the complete code snippet:
https://docs.oracle.com/javafx/2/api/javafx/scene/web/WebEngine.html
EventListener listener = new EventListener() {
public void handleEvent(Event ev) {
System.out.println("Click Operation has been performed");
}
};
Document doc = webEngine.getDocument();
Element el = doc.getElementById("dummyid");
((EventTarget) el).addEventListener("click", listener, false);
As shown in the link you've provided, you can call java methods by using JSObject.setMember method.
public class JavaApplication {
public void exit() {
Platform.exit();
}
}
...
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", new JavaApplication());
You can call from the web page
Click here to exit application
This could be an alternative solution instead of using handlers
On my application(Media Player), when application is in fullscreen mode, I am fading out the top bar and bottom bar. I also wants to fade out the cursor after few seconds delay. I tried FadeTransition, but it take only Node as parameter.
I also tried using thread.
Platform.runLater(new Runnable()
{
#Override
public void run()
{
try
{
Thread.sleep(2000);
scene.setCursor(Cursor.NONE);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
});
Here I just wanted to hide the cursor after two seconds delay. It works, but also hang my application for two seconds which I don't expect.
In which way I can fade out the cursor after two seconds delay?
Your code is making the UI hang because you are making a blocking call (Thread.sleep(...)) on the FX Application Thread. If you want to do it that way, you should block on a background thread and schedule the change of the cursor on the FX Application Thread when the pause is complete.
An easier way, though, is just to use a PauseTransition:
PauseTransition pause = new PauseTransition(Duration.seconds(2));
pause.setOnFinished(e -> scene.setCursor(Cursor.NONE));
pause.play();
You can use this as well to make the cursor reappear on when the user does something, and disappear again after 2 seconds:
scene.addEventHandler(MouseEvent.ANY, e -> {
scene.setCursor(Cursor.DEFAULT);
pause.playFromStart();
});
Vaadin newbie: When a user presses a button, I like to disable it so he knows that he clicked it and there's some work going on in the background. When the (long) task is completed, I'd like to enable the button.
For this, I'm using 2 threads (background and work) but for some reason the button doesn't enabled at the end of the task.
In other words, once clicked it goes to enabled(false) and never coming back. Why? and how can I fix it?
button.addClickListener(new ClickListener()
{
public void buttonClick(ClickEvent event)
{
Thread background = new Thread(new Runnable(){
#Override
public void run()
{
Thread work = new Thread(new Runnable(){
#Override
public void run()
{
button.setEnabled(false);
try
{
Thread.sleep(2000); //long work here!
} catch (InterruptedException e)
{
e.printStackTrace();
}
button.setEnabled(true); //doesn't enable at the end of the long work!
}});
work.start();
try
{
work.join();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}});
background.start();
}
});
Maybe the best approach would be to use Button.setDisableOnClick(true) for the button and do the processing directly in the event handler without a background thread. This will show the standard loading indicator to the user until processing is done.
Otherwise you need to enable server push (#Push) and remember to use UI.access() in the background thread before updating the UI. See https://vaadin.com/book/-/page/advanced.push.html
I have a Chat application. I'd like the cursor in the chatTextArea to get back to the position 0 of the TextArea chatTextArea.
This, however, won't work:
chatTextArea.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent ke) {
if (ke.getCode().equals(KeyCode.ENTER)) {
ChatClient.main(new String[]{"localhost", String.valueOf(4444), chatTextArea.getText()});
chatTextArea.setText("");
chatTextArea.positionCaret(0);
}
}
});
How can I get it to work? Thank you.
The TextArea internally does not use the onKeyPressed property to handle keyboard input. Therefore, setting onKeyPressed does not remove the original event handler.
To prevent TextArea's internal handler for the Enter key, you need to add an event filter that consumes the event:
chatTextArea.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent ke) {
if (ke.getCode().equals(KeyCode.ENTER)) {
ChatClient.main(new String[]{"localhost", String.valueOf(4444), chatTextArea.getText()});
chatTextArea.setText("");
// chatTextArea.positionCaret(0); // not necessary
ke.consume(); // necessary to prevent event handlers for this event
}
}
});
Event filter uses the same EventHandler interface. The difference is only that it is called before any event handler. If an event filter consumes the event, no event handlers are fired for that event.