Javafx 双向绑定 SimpleDoubleProperty SimpleStringProperty 数组越界
Javafx bidirectional binding SimpleDoubleProperty SimpleStringProperty Array out of bounds
当我 运行 以下代码时,我得到一个数组索引越界异常。我的目标是绑定一个 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(Toolkit.java:314)
at com.sun.javafx.tk.Toolkit$$Lambda3/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$runToolkit0(QuantumToolkit.java:334)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda/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$null5(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda/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);
}
}
你把很多部分混在一起了,比如服务、任务、线程。而且您的命名约定不是 JavaFX 的命名约定,就像您的属性一样。
在我稍微清理一下代码并制作了自己的 class JobProgress 文件之后,您现在应该可以获取它了。
您错过了为 JobProgress 对象设置初始进度。那么,如果没有数字,bibinding 应该如何将数字转换为字符串?!
我还删除了一些侦听器和操作处理程序。您应该可以简单地再次添加它们。
FXMLDocumentController.java
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;
}
}
JavaFXApplication2.java
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);
}
}
JobProgress.java
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());
}
}
解决方案如下所示:
当我 运行 以下代码时,我得到一个数组索引越界异常。我的目标是绑定一个 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(Toolkit.java:314)
at com.sun.javafx.tk.Toolkit$$Lambda3/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$runToolkit0(QuantumToolkit.java:334)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda/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$null5(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda/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);
}
}
你把很多部分混在一起了,比如服务、任务、线程。而且您的命名约定不是 JavaFX 的命名约定,就像您的属性一样。
在我稍微清理一下代码并制作了自己的 class JobProgress 文件之后,您现在应该可以获取它了。
您错过了为 JobProgress 对象设置初始进度。那么,如果没有数字,bibinding 应该如何将数字转换为字符串?!
我还删除了一些侦听器和操作处理程序。您应该可以简单地再次添加它们。
FXMLDocumentController.java
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;
}
}
JavaFXApplication2.java
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);
}
}
JobProgress.java
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());
}
}
解决方案如下所示: