baumlol
baumlol

Reputation: 85

JavaFX Thread freeze

I'm currently working on a JavaFX project. On GUI initialization I want to read some infos out of a HTML document using Selenium and FirefoxDriver. Normally I would use a crawler to get the infos but this document is full of JavaScript so I was only able to get to the infos using Selenium (I know, it's really bad).

Now I've got the problem that this process takes up to 15 seconds and I want to show the progress of Selenium on a JavaFX progress bar. So I've set up a Thread doing all the work and trying to update the GUI but the Thread freezes until Selenium is finished.

This is my attempt:

public class SeleniumThread extends Thread
{
    private MainViewController main;

    @Override
    public void run()
    {
        try
        {
            WebDriver driver = new FirefoxDriver();
            driver.get("http://---.jsp");
            main.getMain().getPrimaryStage().toFront();
            main.getPbStart().setProgress(0.1);
            WebElement query = driver.findElement(By.id("user"));
            query.sendKeys(new String[] {"Username"});
            query = driver.findElement(By.id("passwd"));
            query.sendKeys(new String[] {"Password"});
            query.submit();
            driver.get("http://---.jsp");
            main.getPbStart().setProgress(0.2);
            sleep(1000);
            main.getPbStart().setProgress(0.25);
            driver.get("http://---.jsp");
            main.getPbStart().setProgress(0.4);
            sleep(1000);
            main.getPbStart().setProgress(0.45);
            driver.get("---.jsp");
            main.getPbStart().setProgress(0.6);
            sleep(1000);
            main.getPbStart().setProgress(0.65);
            query = driver.findElement(By.cssSelector("button.xyz"));
            query.click();
            sleep(1000);
            main.getPbStart().setProgress(0.85);
            System.out.println(driver.getPageSource());
            driver.quit();
        }
        catch(InterruptedException e)
        {
            // Exception ...
        }

    }

    public MainViewController getMain()
    {
        return main;
    }

    public void setMain(MainViewController main)
    {
        this.main = main;
    }
}

MainViewController

public void startup()
{
    if(main.getCc().getMjUsername() != null &&
            main.getCc().getMjPassword() != null &&
            main.getCc().getMjUsername().length() != 0 &&
            main.getCc().getMjPassword().length() != 0)
    {
        SeleniumThread st = new SeleniumThread();
        st.setMain(this);
        st.setDaemon(true);
        st.run();
    }
}

I've read that I should use a Worker like Task for it, but I have no clue how to implement it. And I need to pass a parameter to this Task, because I need to set my primaryStage to the front and update the progress bar.

I hope you can understand my problem. I'd be grateful for every help.

Upvotes: 0

Views: 3496

Answers (2)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285403

  1. You look to be trying to make JavaFX calls directly from within a background thread, and while I know little about JavaFX, I do know that this is not allowed, that JavaFX calls must be made on the JavaFX Application thread. See Concurrency in JavaFX.
  2. You're not even creating a background thread. You call st.run(); which runs st on the calling thread -- not what you want. You should be calling st.start()!
  3. As a side note, you seem to be extending Thread where you really want to be implementing Runnable. Thus you really should be calling new Thread(myRunnable).start();

Upvotes: 1

hotzst
hotzst

Reputation: 7496

You are trying to update the UI from a different thread. The UI can only be updated from the UI thread. To achieve this, wrap the calls to update the progress:

Platform.runLater(() -> {main.getPbStart().setProgress(0.65);});

This will push the update of the UI into the UI thread.

Upvotes: 1

Related Questions