A
A
Alexey2022-03-23 18:04:16
Java
Alexey, 2022-03-23 18:04:16

How to make a button in JavaFX do nothing?

There is a button that processes a more or less significant event in time. In my case, in a JavaFX application, it displays a new captcha each time it is clicked. The onAction type method from the controller is attached to the button, it all happens in it. I want that if I click on the button once, and then immediately the second, then while the method after the first click has not yet completed its work, the second method is not called. Let's say at the very end of the method I print the word "end" to the console, and I want to be able to click on the button as many times as I want until I see this word, and nothing happens. I tried to put a flag according to the classics, like at the beginning of the method do And after it buttonIsPressed = true and at the end of everything buttonIsPressed = false
if (buttonIsPressed) return;

But it did not help. As I understand it, these methods tend to accumulate, they can be added to the queue, and then executed one after the other, and how many times I press the button, the method will then work so many times. If I pressed the button 10 times in a couple of seconds, then after I finished clicking, the captcha picture changed again 5 times, and it also lasted for about a couple of seconds, in short, it is undesirable for this to happen. I am writing an application for myself, for the purpose of studying, that is, you can leave it like that, but the soul wants it to be perfect

What are the possible solutions here? I thought that it might be necessary to somehow create a second thread, and then everything will be executed simultaneously, in parallel, and not sequentially, or maybe just put some kind of delay, a timer on the button between clicks, but I don’t know how to implement all this. Or maybe JavaFX already has some kind of ready-made object, a method that will help me, and I don’t need to invent anything? Don't know

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexey, 2022-03-26
@MicroKlizma

Thanks to the comments in question and some googling, I figured out what's what. I solved the problem by creating a new thread. This way the thread will run in parallel with the main thread. And while the button exists, in parallel and independently, another thread can control it. When I click on the button, I call the onAction() method, in which I create a new thread with an entry point in the form of a method that should handle everything

public void onAction() throws InterruptedException {
        Thread thread = new Thread(this::someMethod);
        thread.start();
    }

Next, we do everything we wanted to do in this method, but at the same time, while the code is running, we make the button inactive: button.setDisable(true). Thanks to this, it changes color and the ability to click on it disappears (it also seems that you can modify its style in this state in the css file: .button:disabled )
public void someMethod() {
        button.setDisable(true);
        //code
        button.setDisable(false);
    }

This solution worked fine for me and the way I wanted. But it throws an exception, although it can be killed if wrapped in a try catch, it will still work:
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
I think that a good programmer should deal with exceptions :)
As I understand it, an exception is thrown when the view (UI), elements (nodes) (node) of the application changes. Apparently, this can only be done in the FX applicaton thread. In my program, I changed the text field and the image field. And there is a solution - to make all these changes using Platform.runLater (). In it, as well as when creating a Thread, an object of type Runnable is passed. Runnable is a functional interface, so instead of creating a whole class that implements Runnable, let's use lambda expressions for the sake of brevity. In my case for my application, the method would look something like this:
public void someMethod() {
        button.setDisable(true);
        //some code
        Platform.runLater( () -> textField.setText(text) );
        //some code
        Platform.runLater( () -> imageView.setImage(image) );
        //some code
        button.setDisable(false);
    }

Interestingly, setDisable() should also be wrapped in Platform.runLater(). But I tested it, the program worked without exceptions even if not wrapped, although it would seem that this method makes the button change color and makes it inactive, non-clickable, changes the state of the button (by the way, you can find out this state using isDisabled()), but no, that's all works

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question