我们依赖于Node.impl_isTreeVisible(),因为isVisible不能正常工作(或者至少我们想要的方式)。
/**
* @treatAsPrivate implementation detail
* @deprecated This is an internal API that is not intended for use and will be removed in the next version
*/
@Deprecated
public final boolean impl_isTreeVisible() {
return impl_treeVisibleProperty().get();
}
我们有一个自定义节点,其中包含一个Plot。这会得到连续的数据。如果不可见(仍然是托管/渲染,但隐藏),我们希望避免更新绘图。 如果节点放在未选中的选项卡上,因此在窗口中不可见,则使用isVisible仍然返回true。这会导致每次更新绘图时,所选选项卡上的节点都会重新生成。
即使节点在应用程序窗口中不可见,也会评估为真。
if (isVisible()) {
updatePlot()
}
所以我们一直在使用以下工作方式。
if (impl_isTreeVisible()) {
updatePlot()
}
然而,这将不再适用于Java 9,因为此类方法已被删除。 Java 9中是否有新的方法?
更新: 查看javafx.scene.Node的Java 9源代码我发现方法isTreeVisible(),它看起来像是impl_isTreeVisible的替代品。但是看着Javadoc我找不到这个isTreeVisible()。 http://download.java.net/java/jdk9/docs/api/javafx/scene/Node.html
尝试使用isTreeVisible()的示例将无法使用Java 9进行编译
Java9AppTest.java:50: error: cannot find symbol
if (text1.isTreeVisible()) {
^
symbol: method isTreeVisible()
location: variable text1 of type Text
Update2 :最初看不到isTreeVisible()是包私有。
Update3 :再看一下Node源代码,我开始查看NodeHelper是否可以使用它获取isTreeVisible(),但是NodeHelper包不可见。虽然使用com.sun.javafx.scene的--add-exports来访问NodeHelper可以正常工作。
--add-exports javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED
然后我可以读取Node的isTreeVisible()的状态。
final boolean isTreeVisible = NodeHelper.isTreeVisible(node);
代码示例
包含两个Tab,每个Tab都有自己的Text。 有一个更新每个文本的任务。 使用isVisible()将更新两个选项卡上的每个文本。 使用impl_isTreeVisible()只会更新真正可见的文本。 有意义的是,Text应该更新,即使它不可见。这只是为了说明问题。将文本替换为后台进程,这会使CPU工作量增加。
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Java9AppTest extends Application {
private Text text1, text2;
public static void main(String[] args) {
Java9AppTest.launch(args);
}
public void start(Stage stage) throws Exception {
TabPane root = new TabPane();
VBox box1 = new VBox();
text1 = new Text();
text1.setText("Hello World!");
text1.textProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("text1 changed from " + oldValue + " to " + newValue);
});
box1.getChildren().addAll(text1);
Tab tab1 = new Tab("Tab 1");
tab1.setContent(box1);
VBox box2 = new VBox();
text2 = new Text();
text2.setText("Another Hello World!");
text2.textProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("text2 changed from " + oldValue + " to " + newValue);
});
box2.getChildren().add(text2);
Tab tab2 = new Tab("Tab 2");
tab2.setContent(box2);
root.getTabs().addAll(tab1, tab2);
Task<Void> task = new Task<Void>() {
/* (non-Javadoc)
* @see javafx.concurrent.Task#call()
*/
@Override
protected Void call() throws Exception {
final String oldText = "Hello World!";
final String newText = "New Hello World!";
while (true) {
if (text1.isVisible()) {
if (text1.getText().equals(oldText)) {
text1.setText(newText);
} else {
text1.setText(oldText);
}
}
if (text2.isVisible()) {
if (text2.getText().equals(oldText)) {
text2.setText(newText);
} else {
text2.setText(oldText);
}
}
Thread.sleep(2000);
}
}
};
stage.setScene(new Scene(root));
stage.setWidth(200);
stage.setHeight(200);
stage.setTitle("JavaFX 9 Application");
stage.show();
Thread thread = new Thread(task, "Task");
thread.start();
}
}
答案 0 :(得分:2)
我建议在节点中添加一个属性,控制是否要更新绘图。因此,而不是if (impl_isTreeVisible()) {
只有if (shouldUpdate) {
。选项卡选择更改后,只需切换属性即可。所以从本质上讲,你的TabPane
会控制情节是否更新。
或者,您可以将TabPane
传递到您的节点并查询所选标签:tabPane.getSelectionModel().getSelectedIndex()
。但是,这意味着您的节点必须知道它所在的选项卡。
答案 1 :(得分:-1)
selected
,将该属性绑定到您的绘图的update
属性,这决定了您是否重绘了您的绘图。 update
属性,你可以暂停或继续监听输入源,或暂停或恢复获取数据的计时器。此解决方案不会向对象图添加额外的依赖项,它应该包含的容器类型,并允许您在必要时创建更复杂的绑定(如暂停按钮),并简化测试,因为此属性可在独立的方式。
根据数据源实现,如果确定没有侦听器主动处理您的数据,此解决方案也可以暂停您的数据源。