JavaFX图形:如何更改绘制设置?

JavaFX图形:如何更改绘制设置?,java,javafx,Java,Javafx,大约一个月前,我在测试JavaFX图形API,但我担心性能。性能问题是,我必须传递一个Paint对象来为形状着色 问题:无法更改现有绘制的设置 我只需要更新一个绘图,例如,颜色,但是没有像颜色设置红色,颜色设置绿色,颜色设置蓝色和颜色设置不透明度这样的方法。也没有字段() 表演 我可以尝试更改Paint设置的唯一方法是构造另一个Paint,但是这将涉及运行垃圾收集器。对吗 编译器应该根据这些对象的使用方式自动优化它们。但是甲骨文在它的编译器上没有提到这一点,至少对我来说,到目前为止 如果他们

大约一个月前,我在测试JavaFX图形API,但我担心性能。性能问题是,我必须传递一个
Paint
对象来为形状着色


问题:无法更改现有
绘制的设置
我只需要更新一个
绘图
,例如,
颜色
,但是没有像
颜色设置红色
颜色设置绿色
颜色设置蓝色
颜色设置不透明度
这样的方法。也没有字段()


表演 我可以尝试更改
Paint
设置的唯一方法是构造另一个
Paint
,但是这将涉及运行垃圾收集器。对吗

编译器应该根据这些对象的使用方式自动优化它们。但是甲骨文在它的编译器上没有提到这一点,至少对我来说,到目前为止

如果他们说垃圾收集很好,那不是我的错。我没有提到垃圾收集有什么帮助



那么,重新构建一个
画图
是一个好的解决方案吗?你们还知道JavaFX替代方案可以处理我想要的吗?

你们关心的问题实际上并不存在。由于
Paint
是一个不可变的类(出于许多原因,这是一个很好的设计选择),因此在JavaFX中更新某些内容的颜色的正确方法是创建一个新的
Paint
实例,并在需要时将其设置为属性。以前使用过的不再有引用的实例将在将来某个时候被垃圾收集器高效地清理掉

下面是一个简单的演示,它可以在每次渲染场景时创建新的
绘制
实例(以及新的
背景
背景填充
实例)。如果帧渲染时间超过25ms(任意阈值),它将打印警告。在我的系统中,它会在前几帧发出警告,有时会在窗口隐藏并完全重新显示时发出警告

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class UpdateColorContinuously extends Application {

    @Override
    public void start(Stage primaryStage) {
        Pane root = new Pane();
        root.setMinSize(600, 600);

        new AnimationTimer() {

            private long start = -1 ;
            private long lastUpdate ;

            @Override
            public void handle(long now) {
                if (start < 0) {
                    start = now ;
                    lastUpdate = now ;
                }
                long elapsed = now - start ;
                double elapsedSeconds  = elapsed / 1_000_000_000.0 ;
                Color newColor = Color.hsb(elapsedSeconds * 5, 1.0, 1.0);
                BackgroundFill fill = new BackgroundFill(newColor, CornerRadii.EMPTY, Insets.EMPTY);
                Background bg = new Background(fill);
                root.setBackground(bg);

                if (now - lastUpdate > 25_000_000) {
                    System.err.println("Warning: frame rendering took "+ (now-lastUpdate)/1_000_000 + " ms");
                }

                lastUpdate = now ;
            }

        }.start();

        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
导入javafx.animation.AnimationTimer;
导入javafx.application.application;
导入javafx.geometry.Insets;
导入javafx.scene.scene;
导入javafx.scene.layout.Background;
导入javafx.scene.layout.BackgroundFill;
导入javafx.scene.layout.CornerRadii;
导入javafx.scene.layout.Pane;
导入javafx.scene.paint.Color;
导入javafx.stage.stage;
公共类UpdateColor不断扩展应用程序{
@凌驾
公共无效开始(阶段primaryStage){
窗格根=新窗格();
根.setMinSize(600600);
新的AnimationTimer(){
私人长期启动=-1;
私人长期更新;
@凌驾
公共无效句柄(长){
如果(开始<0){
开始=现在;
lastUpdate=now;
}
长时间运行=现在-开始;
双elapsedSeconds=已用时间/1_000_000.0;
Color newColor=Color.hsb(延时秒*5,1.0,1.0);
BackgroundFill fill=新的背景填充(newColor,CornerRadii.EMPTY,Insets.EMPTY);
背景bg=新背景(填充);
根挫折地(bg);
如果(现在-最新更新>25_000_000){
System.err.println(“警告:帧渲染时间为”+(现在为lastUpdate)/1_000_000+“ms”);
}
lastUpdate=now;
}
}.start();
场景=新场景(根);
初级阶段。场景(场景);
primaryStage.show();
}
公共静态void main(字符串[]args){
发射(args);
}
}

可能我运行的时间不够长,GC需要运行;一个
Paint
实例需要的内存量保守估计为50字节,因此您需要创建
10^7
这样的实例以使用500MB(现代桌面系统上相当小的RAM量,可能相当于一次GC扫描)。大致上,这将在两天内生成一次GC扫描。

我可以尝试更改绘制设置的唯一方法是构造另一个绘制,但这将涉及运行垃圾收集器。对吗?不。油漆可能在其他地方被引用,因此不符合垃圾收集的条件。此外,即使不再存在对对象的引用,这并不意味着“销毁”最后一个引用涉及运行垃圾收集器。垃圾收集通常基于其他一些标准。您正在创建不存在的问题。只要在需要时创建新的
Paint
实例即可。由于对象的状态非常小,因此具有四个浮点值的对象的内存占用非常小,并且GC在处理此类对象时非常高效。编写干净地实现需求所需的代码,如果遇到性能问题,请分析并确定问题的原因。不要发明不存在的问题。@James\u我不是在发明问题。如果他们说单个垃圾收集器运行缓慢,那么想象一下,如果这种情况快速发生5次?但垃圾收集器根本不是这样工作的。您的问题,并包括创建新的
Paint
实例会导致性能问题的实际证据。(如果你没有这样的证据,那么你是在捏造不存在的问题。)评论不用于进一步讨论。记住,“你不必担心这个,因为…”是一个有效的答案,应该发布到下面的答案框中,而不是作为一系列评论。说真的,我不是在抱怨。我没有说“使<代码>颜色可变”。当我的意思是
Color
对象可以在使用后立即删除(清理)时,我说