当我运行以下代码时,我得到一个超出范围的数组索引异常。我的目标是绑定Text obj和ProgressBar对象,以便它们同时更新。我试图使用双向绑定。我必须踩到某个地方。我已经运行了很多次并且看到它成功运行了一次或两次。通常在观看进度条几分钟后发生异常。有时我在各自的进度条上看到了一个Text obj或两个退出更新,但进度条继续前进直到异常。 JavaFX绑定专家请帮忙。
Exception in thread "JavaFX Application Thread" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:418)
at java.util.ArrayList.get(ArrayList.java:431)
at javafx.scene.Parent.updateCachedBounds(Parent.java:1580)
at javafx.scene.Parent.recomputeBounds(Parent.java:1524)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1377)
at javafx.scene.Node.updateGeomBounds(Node.java:3556)
at javafx.scene.Node.getGeomBounds(Node.java:3509)
at javafx.scene.Node.getLocalBounds(Node.java:3457)
at javafx.scene.Node.updateTxBounds(Node.java:3620)
at javafx.scene.Node.getTransformedBounds(Node.java:3403)
at javafx.scene.Node.updateBounds(Node.java:538)
at javafx.scene.Parent.updateBounds(Parent.java:1708)
at javafx.scene.Parent.updateBounds(Parent.java:1706)
at javafx.scene.Parent.updateBounds(Parent.java:1706)
at javafx.scene.Parent.updateBounds(Parent.java:1706)
at javafx.scene.Parent.updateBounds(Parent.java:1706)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2404)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:314)
at com.sun.javafx.tk.Toolkit$$Lambda$163/2039336538.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:525)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:505)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(QuantumToolkit.java:334)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$40/1271950976.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda$36/1963387170.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
这是完整的来源。
package javafxapplication2;
import java.io.BufferedReader;
import java.net.URL;
import java.security.Provider.Service;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.ResourceBundle;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextBoundsType;
import javafx.util.StringConverter;
import javafx.util.converter.DoubleStringConverter;
import javafx.util.converter.NumberStringConverter;
import org.controlsfx.control.HyperlinkLabel;
public class FXMLDocumentController implements Initializable {
@FXML
private TreeView treeView;
List<JobProgress> jobProgressInfos = Arrays.<JobProgress>asList(
new JobProgress("JJ&P_POP_DAT", "Running Jobs"),
new JobProgress("Des_master_33334", "Running Jobs"),
new JobProgress("FS_BUSS", "Running Jobs"),
new JobProgress("CONER_DWN_MIX", "Running Jobs"),
new JobProgress("newjb", "Running Jobs"),
new JobProgress("jb name", "Running Jobs"),
new JobProgress("tst jb", "Pending Jobs"),
new JobProgress("ult--ob", "Pending Jobs"),
new JobProgress("inl jb", "Pending Jobs"),
new JobProgress("fst jb", "Completed Jobs"),
new JobProgress("VoCt_Nme_Jb", "Completed Jobs"));
TreeItem<String> rootNode = new TreeItem<>("Job Details");
@Override
public void initialize(URL url, ResourceBundle rb) {
}
void setup()
{
rootNode.setExpanded(true);
for (JobProgress jobProgressInfo : jobProgressInfos)
{
Text text = new Text();
text.setBoundsType(TextBoundsType.VISUAL);
text.setFill(Color.BLACK);
ProgressBar bar = new ProgressBar(0.0);
//Bind bar and text:
bar.progressProperty().bind(jobProgressInfo.getJobPercentDouble());
text.textProperty().bind(jobProgressInfo.getJobPercentString());
StackPane stack = new StackPane();
stack.getChildren().addAll(bar,text);
Node icon = stack;
text.textProperty().addListener(new ChangeListener<String>()
{
public void changed(ObservableValue ov, String t, String t1) {
System.out.println(ov);
System.out.println(t);
System.out.println(t1);
System.out.println("");
}
});
TreeItem<String> empLeaf = new TreeItem<>(jobProgressInfo.getJobName(),icon);
boolean found = false;
for (TreeItem<String> depNode : rootNode.getChildren())
{
if (depNode.getValue().contentEquals(jobProgressInfo.getJobStatus()))
{
depNode.getChildren().add(empLeaf);
found = true;
break;
}
}
if (!found) {
TreeItem<String> depNode = new TreeItem<>(
jobProgressInfo.getJobStatus()
);
rootNode.getChildren().add(depNode);
depNode.getChildren().add(empLeaf);
}
}
treeView.setRoot(rootNode);
treeView.addEventHandler(MouseEvent.MOUSE_CLICKED,new EventHandler<MouseEvent>()
{
@Override public void handle(MouseEvent mouseEvent)
{
if ( mouseEvent.getButton().equals(MouseButton.PRIMARY))
{
if (treeView.getSelectionModel().getSelectedItem() instanceof TreeItem)
{
TreeItem item = (TreeItem)treeView.getSelectionModel().getSelectedItem();
if (item.getParent() != null && item.getParent().getParent() != null)
{
System.out.println("You primary clicked a job!");
}
}
}
else if ( mouseEvent.getButton().equals(MouseButton.SECONDARY))
{
if (treeView.getSelectionModel().getSelectedItem() instanceof TreeItem)
{
TreeItem item = (TreeItem)treeView.getSelectionModel().getSelectedItem();
if (item.getParent() != null && item.getParent().getParent() != null)
{
System.out.println("You scondary clicked a job!");
}
}
}
}
});
Service svc = new Service();
svc.createTask().run();
}
public class Service extends javafx.concurrent.Service<Void>
{
@Override
protected Task<Void> createTask()
{
return new TestTask();
}
private class TestTask extends Task<Void>
{
public TestTask()
{
}
@Override
protected Void call() throws Exception
{
for (JobProgress jp : jobProgressInfos)
{
new Thread(){
@Override
public void run(){
try {
for(double i=0; i<=1; i+=0.01)
{
DecimalFormat df = new DecimalFormat("#.####");
jp.setJobPercentDouble(Double.parseDouble( df.format(i)));
Thread.sleep(500);
}
} catch (InterruptedException ex) {
System.err.println("Error on Thread Sleep");
}
}
}.start();
}
return null;
}
@Override
protected void succeeded()
{
}
@Override
protected void cancelled()
{
}
}
}
public static class JobProgress
{
private final SimpleDoubleProperty jobPercentDouble;
private final SimpleStringProperty jobPercentString;
private final SimpleStringProperty jobName;
private final SimpleStringProperty jobStatus;
private final HyperlinkLabel hyperLink;
private JobProgress(String aJobName, String aJobStatus) {
this.jobName = new SimpleStringProperty(aJobName);
this.jobStatus = new SimpleStringProperty(aJobStatus);
this.hyperLink = new HyperlinkLabel("test");
this.jobPercentDouble = new SimpleDoubleProperty();
this.jobPercentString = new SimpleStringProperty();
Bindings.bindBidirectional(jobPercentString,jobPercentDouble, new NumberStringConverter());
// StringConverter<? extends Number> converter = new NumberStringConverter();
// Bindings.bindBidirectional(stringProp, doubleProp, new Format()
// {
//
// @Override
// public StringBuffer format(Object obj, StringBuffer toAppendTo,FieldPosition pos)
// {
// System.out.println(obj.toString());
// return toAppendTo.append(obj.toString());
// }
//
// @Override
// public Object parseObject(String source, ParsePosition pos)
// {
// System.out.println("parseObj " + source);
// return Integer.parseInt(source);
// }
//
// });
}
public String getJobName() {
return jobName.get();
}
public void setJobName(String value) {
jobName.set(value);
}
public String getJobStatus() {
return jobStatus.get();
}
public void setJobStatus(String value) {
jobStatus.set(value);
}
public SimpleStringProperty getJobPercentString() {
return jobPercentString;
}
public void setJobPercentString(String value) {
jobPercentString.set(value);
}
public SimpleDoubleProperty getJobPercentDouble() {
return jobPercentDouble;
}
public void setJobPercentDouble(double value) {
jobPercentDouble.set(value);
}
}
}
这里是FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="509.0" prefWidth="222.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="javafxapplication2.FXMLDocumentController">
<children>
<TreeView fx:id="treeView" layoutX="11.0" layoutY="5.0" prefHeight="496.0" prefWidth="200.0" AnchorPane.bottomAnchor="8.0" AnchorPane.leftAnchor="11.0" AnchorPane.rightAnchor="11.0" AnchorPane.topAnchor="5.0" />
</children>
</AnchorPane>
最后但并非最不重要的主要内容:
package javafxapplication2;
import java.net.URL;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXApplication2 extends Application {
@Override
public void start(Stage stage) throws Exception
{
URL resource = getClass().getResource("FXMLDocument.fxml");
FXMLLoader loader = new FXMLLoader(resource);
Parent root = (Parent) loader.load();
FXMLDocumentController controller = loader.getController();
controller.setup();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
答案 0 :(得分:3)
你把很多部分混合在一起,比如Service,Task,Thread。而且您的命名约定不是JavaFX的命名约定,就像您的属性一样。
在我清理了一些代码并创建了一个自己的JobProgress类文件之后,你现在应该准备好了。
您错过了在JobProgress对象上设置初始进度。那么如果没有数字,bibinding如何将数字转换为字符串?!
此外,我已删除了一些侦听器和操作处理程序。您应该可以再次添加它们。
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextBoundsType;
public class FXMLDocumentController implements Initializable {
@FXML
private TreeView treeView;
private final List<JobProgress> jobList = Arrays.<JobProgress>asList(
new JobProgress("JJ&P_POP_DAT", "Running Jobs"),
new JobProgress("Des_master_33334", "Running Jobs"),
new JobProgress("FS_BUSS", "Running Jobs"),
new JobProgress("CONER_DWN_MIX", "Running Jobs"),
new JobProgress("newjb", "Running Jobs"),
new JobProgress("jb name", "Running Jobs"),
new JobProgress("tst jb", "Pending Jobs"),
new JobProgress("ult--ob", "Pending Jobs"),
new JobProgress("inl jb", "Pending Jobs"),
new JobProgress("fst jb", "Completed Jobs"),
new JobProgress("VoCt_Nme_Jb", "Completed Jobs"));
@Override
public void initialize(URL url, ResourceBundle rb) {
TreeItem<String> rootNode = new TreeItem<>("Job Details");
rootNode.setExpanded(true);
for (JobProgress jb : jobList) {
Text text = new Text();
ProgressBar bar = new ProgressBar(0.0);
bar.progressProperty().bind(jb.jobProgressProperty());
text.setBoundsType(TextBoundsType.VISUAL);
text.setFill(Color.BLACK);
text.textProperty().bind(jb.jobProgressStringProperty());
StackPane stack = new StackPane();
stack.getChildren().addAll(bar, text);
Node icon = stack;
TreeItem<String> empLeaf = new TreeItem<>(jb.getJobName(), icon);
boolean found = false;
for (TreeItem<String> depNode : rootNode.getChildren()) {
if (depNode.getValue().contentEquals(jb.getJobStatus())) {
depNode.getChildren().add(empLeaf);
found = true;
break;
}
}
if (!found) {
TreeItem<String> depNode = new TreeItem<>(jb.getJobStatus());
rootNode.getChildren().add(depNode);
depNode.getChildren().add(empLeaf);
}
}
treeView.setRoot(rootNode);
new Thread(simulateProgress()).start();
}
private Task<Void> simulateProgress() {
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
for (double i = 0.0; i <= 1.0; i += 0.1) {
for (JobProgress job : jobList) {
job.setJobProgress(i);
}
Thread.sleep(1000);
}
return null;
}
};
return task;
}
}
import java.net.URL;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXApplication2 extends Application {
@Override
public void start(Stage stage) throws Exception {
URL resource = getClass().getResource("FXMLDocument.fxml");
FXMLLoader loader = new FXMLLoader(resource);
Parent root = (Parent) loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.util.converter.NumberStringConverter;
public class JobProgress {
private final SimpleDoubleProperty jobProgress;
public double getJobProgress() {
return jobProgress.get();
}
public void setJobProgress(double value) {
jobProgress.set(value);
}
public SimpleDoubleProperty jobProgressProperty() {
return jobProgress;
}
private final SimpleStringProperty jobProgressString;
public void setJobProgressString(String value) {
jobProgressString.set(value);
}
public String getJobProgressString() {
return jobProgressString.get();
}
public SimpleStringProperty jobProgressStringProperty() {
return jobProgressString;
}
private final SimpleStringProperty jobName;
public String getJobStatus() {
return jobStatus.get();
}
public void setJobStatus(String value) {
jobStatus.set(value);
}
private final SimpleStringProperty jobStatus;
public String getJobName() {
return jobName.get();
}
public void setJobName(String value) {
jobName.set(value);
}
public JobProgress(String jobName, String jobStatus) {
this.jobName = new SimpleStringProperty(jobName);
this.jobStatus = new SimpleStringProperty(jobStatus);
this.jobProgress = new SimpleDoubleProperty(0.0);
this.jobProgressString = new SimpleStringProperty();
Bindings.bindBidirectional(jobProgressString, jobProgress, new NumberStringConverter());
}
}
解决方案如下所示: