我正在用javafx开发一个用来检测钓鱼网站的应用程序。我有一个“预测”按钮,它在它的EventHandler中执行所有必要的处理。我还希望能够更新ProgressBar,使其具有在处理过程中达到多远的信息。为此,我使用了一个任务,使用最终结果调用updateProgress和updateValue。
但是,如果发生异常,我希望更新UI,然后使用带有一些错误值的updateProgress立即终止EventHandler的执行。但是,updateProgress不会立即更新UI。有没有什么东西不仅可以从EventHandler内部更新UI,比如任务,还可以让我准确地控制UI更新的时间?
作为参考,下面是我完整的事件处理程序代码:
predict.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event)
{
Task<Result> task = new Task<Result>()
{
@Override
protected Result call() throws Exception
{
String url = urlText.getText();
ArffData arffData = new ArffData();
try
{
updateProgress(1, 10);
URL uri = new URL(url);
String domain = uri.getHost();
arffData.setUrlSimilarity(DataGatherer.readLevenshtein(domain));
updateProgress(2, 10);
boolean redirection = DataGatherer.getRedirectionStatus(url);
arffData.setRedirection(redirection);
updateProgress(3, 10);
Response response = Jsoup.connect(url).execute();
arffData.setSpellingErrors(DataGatherer.getSpellingErrors(response).size());
}
catch (IOException e1)
{
updateProgress(-1, 10); //Should update UI before terminating
return null;
}
Classifier rf;
Instances instances;
try
{
updateProgress(4, 10);
rf = (Classifier) SerializationHelper.read("RF100.model");
instances = new DataSource("phishingData.arff").getDataSet();
}
catch (Exception e1)
{
updateProgress(-1, 10);
return null;
}
if (instances.classIndex() == -1)
instances.setClassIndex(instances.numAttributes() - 1);
String offers = offerText.getValue();
String lf = lfText.getValue();
updateProgress(5, 10);
Instance inst = InstanceSetup.setUpInstance(arffData, offers, lf, instances);
try
{
updateProgress(6, 10);
double clsLabel = rf.classifyInstance(inst);
instances.add(inst);
rf.buildClassifier(instances);
SerializationHelper.write("RF100.model", rf);
Evaluation eval = new Evaluation(instances);
eval.crossValidateModel(rf, instances, 10, new Random(1));
boolean phishing = clsLabel ==0 ?true: false;
Result result = new Result(phishing, eval.pctCorrect());
updateProgress(10, 10);
if(clsLabel == 0)
{
predictionLabel.setText("the given website IS a phishing website.");
}
else
{
predictionLabel.setText("the given website IS NOT a phishing website.");
}
updateValue(result);
accuracyLabel.setText("PhishGuard is " + String.format("%.4f%%", eval.pctCorrect()) +
" confident in this prediction.");
return result;
}
catch (Exception e)
{
updateProgress(-1, 10);
return null;
}
}
};
task.progressProperty().addListener(new ChangeListener<Number>()
{
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue)
{
switch(newValue.intValue())
{
case 1:
{
pBar.setProgress(10);
progressLabel.setText(progressLabels[1]);
}
case 2:
{
pBar.setProgress(30);
progressLabel.setText(progressLabels[2]);
}
case 3:
{
pBar.setProgress(50);
progressLabel.setText(progressLabels[3]);
}
case 4:
{
pBar.setProgress(70);
progressLabel.setText(progressLabels[4]);
}
case 5:
{
pBar.setProgress(80);
progressLabel.setText(progressLabels[5]);
}
case 6:
{
pBar.setProgress(90);
progressLabel.setText(progressLabels[6]);
}
case 10:
{
pBar.setProgress(100);
progressLabel.setText(progressLabels[0]);
}
case -1:
{
predictionLabel.setText("a prediction could not be made.");
accuracyLabel.setText("");
pBar.setProgress(0);
progressLabel.setText(progressLabels[0]);
}
}
}
});
task.valueProperty().addListener(new ChangeListener<Result>(){
@Override
public void changed(ObservableValue<? extends Result> observable, Result oldValue, Result newValue)
{
// TODO Auto-generated method stub
boolean phishing = newValue.isPhishing();
if(phishing)
{
predictionLabel.setText("the given website IS a phishing website.");
}
else
{
predictionLabel.setText("the given website IS NOT a phishing website.");
}
accuracyLabel.setText("PhishGuard is " + String.format("%.4f%%", newValue.getAccuracy()) +
" confident in this prediction.");
}
});
new Thread(task).start();
}});发布于 2017-03-08 08:06:19
Task和ProgressBar的progressProperty()要么为INDETERMINATE,要么设置为介于0和1(包括0和1)之间的值。对于进度条:
介于0和1之间的正值表示进度百分比,其中0表示0%,1表示100%。任何大于1的值都被解释为100%。
因此,当您观察任务的进度值,然后获得intValue()时,只有三种可能性:-1 (当进度不确定时)、1 (当任务完成时)或0 (所有其他值)。当您使用任务的progressProperty注册侦听器时,它已经处于INDETERMINATE状态,因此您看到的第一个更改的intValue()为0 (与您的任何情况都不匹配),并且所有后续更改都会看到相同的值,直到任务完成,此时您会看到1。此时,您将进度条的进度设置为10,如上所述,它被解释为100%。
也许你真正想做的就是将进度条的进度属性绑定到任务的进度属性上(这样它们就会一起增加)。
要定期更新文本,可以使用任务的messageProperty。
因此,我将完全删除任务的progress属性上的侦听器,并将其替换为
pBar.progressProperty().bind(task.progressProperty());
pBar.textProperty().bind(task.messageProperty());在任务中根据需要对每条消息调用updateMessage() (稍后代码)。
为此:
但是,如果发生异常,我希望更新UI,然后立即终止EventHandler的执行
我假设您真正的意思是“终止Task的执行”,因为事件处理程序早就完成了。正如注释中所指出的,默认情况下,Task处理异常。因此,您可以让异常从call()方法传播,并在onFailed处理程序中进行UI更新。
结果如下所示:
predict.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event)
{
Task<Result> task = new Task<Result>()
{
@Override
protected Result call() throws Exception
{
String url = urlText.getText();
ArffData arffData = new ArffData();
updateProgress(1, 10);
updateMessage(progressLabels[1]);
URL uri = new URL(url);
String domain = uri.getHost();
arffData.setUrlSimilarity(DataGatherer.readLevenshtein(domain));
updateProgress(2, 10);
updateMessage(progressLabels[2]);
boolean redirection = DataGatherer.getRedirectionStatus(url);
arffData.setRedirection(redirection);
updateProgress(3, 10);
updateMessage(progressLabels[3]);
Response response = Jsoup.connect(url).execute();
arffData.setSpellingErrors(DataGatherer.getSpellingErrors(response).size());
Classifier rf;
Instances instances;
updateProgress(4, 10);
updateMessage(progressLabels[4]);
rf = (Classifier) SerializationHelper.read("RF100.model");
instances = new DataSource("phishingData.arff").getDataSet();
if (instances.classIndex() == -1)
instances.setClassIndex(instances.numAttributes() - 1);
String offers = offerText.getValue();
String lf = lfText.getValue();
updateProgress(5, 10);
updateMessage(progressLabels[5]);
Instance inst = InstanceSetup.setUpInstance(arffData, offers, lf, instances);
updateProgress(6, 10);
updateMessage(progressLabels[6]);
double clsLabel = rf.classifyInstance(inst);
instances.add(inst);
rf.buildClassifier(instances);
SerializationHelper.write("RF100.model", rf);
Evaluation eval = new Evaluation(instances);
eval.crossValidateModel(rf, instances, 10, new Random(1));
boolean phishing = clsLabel ==0 ?true: false;
Result result = new Result(phishing, eval.pctCorrect());
updateProgress(10, 10);
updateMessage(progressLabels[0]);
if(clsLabel == 0)
{
predictionLabel.setText("the given website IS a phishing website.");
}
else
{
predictionLabel.setText("the given website IS NOT a phishing website.");
}
updateValue(result);
accuracyLabel.setText("PhishGuard is " + String.format("%.4f%%", eval.pctCorrect()) +
" confident in this prediction.");
return result;
}
};
pBar.progressProperty().bind(task.progressProperty());
pLabel.textProperty().bind(task.messageProperty());
task.valueProperty().addListener(new ChangeListener<Result>(){
@Override
public void changed(ObservableValue<? extends Result> observable, Result oldValue, Result newValue)
{
// TODO Auto-generated method stub
boolean phishing = newValue.isPhishing();
if(phishing)
{
predictionLabel.setText("the given website IS a phishing website.");
}
else
{
predictionLabel.setText("the given website IS NOT a phishing website.");
}
accuracyLabel.setText("PhishGuard is " + String.format("%.4f%%", newValue.getAccuracy()) +
" confident in this prediction.");
}
});
task.setOnFailed(e -> {
predictionLabel.setText("a prediction could not be made.");
accuracyLabel.setText("");
pBar.progressProperty().unbind();
pBar.setProgress(0);
progressLabel.setText(progressLabels[0]);
});
new Thread(task).start();
}});https://stackoverflow.com/questions/42658467
复制相似问题