2015-12-04 227 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();