2015-12-04 172 views
0

我目前正在開發一個JavaFX項目。在GUI初始化時,我想使用Selenium和FirefoxDriver從HTML文檔中讀取一些信息。通常我會使用爬蟲來獲取信息,但是這個文檔充滿了JavaScript,所以我只能使用Selenium來獲取信息(我知道,這真的很糟糕)。JavaFX線程凍結

現在我遇到了這個過程最多需要15秒的問題,我想在JavaFX進度條上顯示Selenium的進度。所以我建立了一個線程來完成所有工作,並嘗試更新GUI,但線程凍結直到Selenium完成。

這是我的嘗試:

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(); 
    } 
} 

我讀過,我應該使用像任務工作者它,但我不知道如何實現它。我需要將參數傳遞給此任務,因爲我需要將我的primaryStage設置爲前端並更新進度欄。

我希望你能理解我的問題。我會很感激每一個幫助。

+0

1)你看看試圖讓JavaFX的直接從後臺線程中調用,雖然我知道關於JavaFX一點,我知道這是不允許的,這JavaFX的來電必須在JavaFX應用程序線程上進行。參見[JavaFX中的併發症](http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm)。 2)作爲一個附註,你似乎在擴展Thread,你真的想實現Runnable。 –

+1

「我讀過我應該使用像Task這樣的工作者,但我不知道如何實現它。」 ['Task'](http://docs.oracle.com/javase/8/javafx/api/index.html?javafx/concurrent/Task.html)API文檔有很多示例,包括具有參數和更新進度。 –

回答

1

您正嘗試從其他線程更新UI。 UI只能從UI線程更新。爲了實現這一點,換行電話以更新進度:

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

這會將UI的更新推送到UI線程中。

+0

謝謝,這很好。但這是不好的做法?我只是好奇,因爲我沒有用Runnable和JavaFX做很多事情,正如你所看到的。 – baumlol

+1

'Platform.runLater'沒問題,只要你不要將數以萬計的電話垃圾郵件發送出去 - 實際上最壞的做法是從其他類訪問你的Progressbar。通常情況下,你會在FXML控制器類(不是'main' !!)中公開一個[可寫屬性](https://docs.oracle.com/javafx/2/api/javafx/beans/property/SimpleDoubleProperty.html)一個在你的控制器類中反映到進度條上的屬性的線程設置值。這就是所謂的「數據封裝」。 – specializt

1
  1. 你看看試圖讓JavaFX的直接從後臺線程中調用,雖然我知道一點關於JavaFX的,我知道這是不允許的,是JavaFX的呼叫必須JavaFX應用程序的線程上進行。見Concurrency in JavaFX
  2. 你甚至沒有創建後臺線程。你打電話st.run();哪些運行在調用線程 - 不是你想要的。您應該致電st.start()
  3. 作爲一個方面說明,您似乎正在擴展Thread,您真的想要實現Runnable。因此,你真的應該叫new Thread(myRunnable).start();