我正在javafx开发一个检测网络钓鱼网站的应用程序。我有一个"预测"在其EventHandler中执行所有必要处理的按钮。我还希望能够更新ProgressBar,其中包含有关处理过程中获取的信息。我为此使用了一个Task,使用最终结果调用updateProgress和updateValue。
但是,如果发生异常,我想更新UI,然后使用带有一些错误值的updateProgress立即终止EventHandler的执行。但是,updateProgress不会立即更新UI。是否存在一些不仅可以从EventHandler内部更新UI(如Task),还可以让我控制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();
}});
答案 0 :(得分:1)
progressProperty()
和Task
INDETERMINATE
都是intValue()
或者设置为0到1(含)之间的值。对于进度条:
0到1之间的正值表示0为0%且1为100%的进度百分比。任何大于1的值都被解释为100%。
因此,当您观察任务的进度值,然后获得-1
时,只有三种可能性:1
(当进度不确定时),0
(当任务完成),或progressProperty
(所有其他值)。当您使用任务INDETERMINATE
注册听众时,它已处于intValue()
状态,因此您看到的第一个更改为0
1
(与您的任何内容都不匹配)在您看到10
时,在任务完成之前,所有后续更改都会看到相同的值。此时,您将进度条的进度设置为pBar.progressProperty().bind(task.progressProperty());
pBar.textProperty().bind(task.messageProperty());
,如上所述,将其解释为100%。
你真正想要做的只是将进度条的progress属性绑定到任务的progress属性(所以它们只是一起增加)。
要定期更新文本,您可以使用任务ProgressBar
。
因此,我将完全删除任务的进度属性上的侦听器,并将其替换为
updateMessage()
根据需要使用您需要的每条消息(稍后代码)调用Task
。
为此:
但是,如果发生异常,我想更新UI然后立即终止执行EventHandler
我假设你的意思是“终止执行Task
”,因为事件处理程序早已完成。如评论中所述,call()
默认处理异常。因此,您可以让异常从onFailed
方法传播,并在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();
}});
处理程序中执行UI更新。
结果如下所示:
imageView.subviews