当前位置: 首页 > 知识库问答 >
问题:

JavaFX画布-仅当画布可见时绘制

墨翔宇
2023-03-14

我正在考虑将我们内部的汽车/测量应用程序从Swing移植到JavaFX,主要是因为它有更好的外观和多点触控支持,但是我找不到一种方法来渲染只有当它们可见时才可以呈现的自定义组件。

为了获得动力,想象一个有10个选项卡的屏幕,每个选项卡内都有一个显示正在测量的一些实时数据的图。任何时候,只能看到一个情节。数据量很大,计算机有足够的能力一次渲染一个情节,但不能同时渲染所有情节。

摇摆版

现在在Swing版本中,这种行为的实现非常简单。每个绘图都是一个自定义JComponent,它具有覆盖的paintComponent方法,该方法执行所有绘图。在两种重要情况下调用paintComponent:

  • 当组件可见时,例如,用户选择带有绘图的选项卡

它比这更复杂(参见http://www.oracle.com/technetwork/java/painting-140037.html详细信息),但其工作原理大致如下。重要的是,只有可见的绘图也在被处理和重画。。

移植到JavaFX?

现在,我尝试将这种行为移植到JavaFX,画布是一种自然选择。但是paintComponent回调机制已经消失,您只需直接在画布中绘制即可。getGraphicsContext2D。

如果我理解正确的话,在这个上下文中调用绘图操作并不真正执行任何立即绘图,它只是在Prism线程运行时将操作推送到Prism子系统稍后处理的堆栈上(这是正确的吗?)。所以,可能(我只是猜测,我对JavaFX很陌生),如果棱镜发现画布不可见,就不会有实际的绘画(选择了另一个标签,它被另一个节点遮挡,位于屏幕的可见部分之外,...),这样做正确吗?那就太好了。

但即使是这种情况,它也帮不了我,因为我甚至不想开始渲染,直到我知道画布是可见的。即使是对实时数据进行预处理以进行绘图,也可能需要相当多的CPU能力,甚至可能比渲染本身还要多——想象一下,插值数千个数据点以绘制几行。因此,在实时数据更改之后,我想在开始重新绘制之前,首先html" target="_blank">测试每个绘图(画布)的实际可见性。当它变得可见时,我也需要得到通知。这在JavaFX中是可能的吗?还是说我在画布上走了一条糟糕的路线,还有更好的方法?

P. S.请不要混淆这种可见性与Node.visible属性,其中一个做了不同的事情,基本上关闭了节点渲染。

共有1个答案

刘运浩
2023-03-14

使用选项卡窗格,我认为唯一的方法是观察选项卡窗格的选定项(即选定选项卡)。您可能希望对绘图区域进行编码,使其独立于是否在选项卡窗格中显示,因此我将在绘图中包含一个BooleanProperty,指示它是否处于活动状态:

public class PlotPane extends Pane {
    private final BooleanProperty active = new SimpleBooleanProperty();
    public BooleanProperty activeProperty() {
        return active ;
    }
    public final boolean isActive() {
        return activeProperty().get();
    }
    public final void setActive(boolean active) {
        activeProperty().set(active);
    }

    public PlotPane(String name) {
        // just for demo...
        activeProperty().addListener((obs, wasActive, isActive) -> {
            if (isActive) {
                System.out.println(name + " is active");
            } else {
                System.out.println(name + " is inactive");
            }
        });
    }
}

然后,当您将其组装到选项卡窗格中时,可以绑定属性:

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class ActiveTabTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        PlotPane pane1 = new PlotPane("Pane1");
        Tab tab1 = new Tab("Pane1", pane1);

        PlotPane pane2 = new PlotPane("Pane2");
        Tab tab2 = new Tab("Pane2", pane2);

        TabPane tabPane = new TabPane(tab1, tab2);

        pane1.activeProperty().bind(tabPane.getSelectionModel().selectedItemProperty().isEqualTo(tab1));
        pane2.activeProperty().bind(tabPane.getSelectionModel().selectedItemProperty().isEqualTo(tab2));


        primaryStage.setScene(new Scene(tabPane, 400, 400));
        primaryStage.show();
    }

    public static class PlotPane extends Pane {
        private final BooleanProperty active = new SimpleBooleanProperty();
        public BooleanProperty activeProperty() {
            return active ;
        }
        public final boolean isActive() {
            return activeProperty().get();
        }
        public final void setActive(boolean active) {
            activeProperty().set(active);
        }

        public PlotPane(String name) {
            // just for demo...
            activeProperty().addListener((obs, wasActive, isActive) -> {
                if (isActive) {
                    System.out.println(name + " is active");
                } else {
                    System.out.println(name + " is inactive");
                }
            });
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

如果画布在物理上不可见,你是正确的,但是这给了你打开/关闭数据流监控等东西的机会。

如果需要,可以进一步细化绑定,例如:。

plot1.activeProperty().bind(tabPane.getSelectionModel().selectedItemProperty().isEqualTo(tab1)
    .and(tabPane.sceneProperty().isNotNull()));
 类似资料:
  • 我目前正在使用画布开发一个JavaFX-Drawing-Application。在GraphicsContext的帮助下,我使用beginPath()和lineTo()方法绘制线条,但我无法找到实现橡皮擦的适当方法。

  • 我编写了这段代码,可以在JavaFX画布上绘制。它可以很好地工作,但我不知道如何重新绘制画布(比如在Swing中),以便在新画布上重新开始绘制。这是我的代码,非常感谢你的帮助!马里奥

  • 在这个例子中我们将使用画布(Canvas)创建一个简单的绘制程序。 在我们场景的顶部我们使用行定位器排列四个方形的颜色块。一个颜色块是一个简单的矩形,使用鼠标区域来检测点击。 Row { id: colorTools anchors { horizontalCenter: parent.horizontalCenter

  • 我想在HTML5画布/或SVG上执行以下操作: 有一个背景路径,将光标移过去并绘制(填充)背景路径 用户完成绘图后有回调函数 我的问题是,我不知道如何检查抽屉线是否遵循路径。 有人能给我解释一下如何做到这一点,或者给我一些建议吗? http://jsbin.com/reguyuxawo/edit?html,js,控制台,输出

  • 我是一个Java/JavaFX程序员新手,我正在开发一个简单的JavaFX建筑设计工具,在这个工具中,您可以画出墙壁、地板等,因此对象(主要是线、圆、多边形、矩形图像)是在屏幕上绘制和创建的,而不是在运行之前创建的。

  • 在画布上画画是非常好的。即使橡皮擦也能工作得很好。问题是当画布保存为图像时,它画的是黑线,而不是橡皮擦。 为了更好地理解,我添加了屏幕、镜头和代码。 1.在擦除图的同时- 我不明白为什么橡皮移动被替换为黑色,而保存画布作为一个图像。