use*_*969 10 performance javafx-2 fxml scenebuilder
问题 我想在运行时将通过javafx场景构建器构建的自定义面板添加到网格窗格.我自定义的面板存在按钮,标签等.
我的尝试 我试图从窗格扩展...
public class Celli extends Pane{
public Celli() throws IOException{
Parent root = FXMLLoader.load(getClass().getResource("Cell.fxml"));
this.getChildren().add(root);
}
}
Run Code Online (Sandbox Code Playgroud)
...然后在控制器的添加方法中使用此面板
@FXML
private void textChange(KeyEvent event) {
GridPane g = new GridPane();
for (int i=0 : i<100; i++){
g.getChildren().add(new Celli());
}
}
}
Run Code Online (Sandbox Code Playgroud)
它有效,但表现非常差.
我正在寻找的 是有没有办法通过javafx场景构建器设计面板(因此在fxml中有这个面板),然后在运行时将它添加到gridpane而不为每个实例使用这个fxmlloader.我认为它因fxml加载器而表现不佳.当我添加一个标准按钮,例如whitout fxml时,速度要快得多.
Seb*_*ian 21
简答:不,它不是(截至JavaFX 2.x和8.0).它可能是未来的版本(JFX> 8)
答案 很长: FXMLLoader目前不是作为模板提供程序执行的,它一次又一次地实例化同一个项目.相反,它意味着是一个大型GUI(或序列化它们)的一次性加载器.
性能很差,因为根据FXML文件,在每次调用时load(),FXMLLoader必须通过反射查找类及其属性.这意味着:
对于load()在代码中完成的相同FXML文件的后续调用,目前也没有任何改进.这意味着:没有找到已找到的类的缓存,没有缓存BeanAdapter等等.
但是,通过将自定义类加载器设置为FXMLLoader实例,可以解决步骤1的性能问题:
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class MyClassLoader extends ClassLoader{
private final Map<String, Class> classes = new HashMap<String, Class>();
private final ClassLoader parent;
public MyClassLoader(ClassLoader parent) {
this.parent = parent;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> c = findClass(name);
if ( c == null ) {
throw new ClassNotFoundException( name );
}
return c;
}
@Override
protected Class<?> findClass( String className ) throws ClassNotFoundException {
// System.out.print("try to load " + className);
if (classes.containsKey(className)) {
Class<?> result = classes.get(className);
return result;
} else {
try {
Class<?> result = parent.loadClass(className);
// System.out.println(" -> success!");
classes.put(className, result);
return result;
} catch (ClassNotFoundException ignore) {
// System.out.println();
classes.put(className, null);
return null;
}
}
}
// ========= delegating methods =============
@Override
public URL getResource( String name ) {
return parent.getResource(name);
}
@Override
public Enumeration<URL> getResources( String name ) throws IOException {
return parent.getResources(name);
}
@Override
public String toString() {
return parent.toString();
}
@Override
public void setDefaultAssertionStatus(boolean enabled) {
parent.setDefaultAssertionStatus(enabled);
}
@Override
public void setPackageAssertionStatus(String packageName, boolean enabled) {
parent.setPackageAssertionStatus(packageName, enabled);
}
@Override
public void setClassAssertionStatus(String className, boolean enabled) {
parent.setClassAssertionStatus(className, enabled);
}
@Override
public void clearAssertionStatus() {
parent.clearAssertionStatus();
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
public static ClassLoader cachingClassLoader = new MyClassLoader(FXMLLoader.getDefaultClassLoader());
FXMLLoader loader = new FXMLLoader(resource);
loader.setClassLoader(cachingClassLoader);
Run Code Online (Sandbox Code Playgroud)
这显着加快了性能.但是,步骤2没有解决方法,因此这可能仍然是一个问题.
但是,官方JavaFX jira中已有功能请求.你支持这个请求会很高兴.
链接:
FXMLLoader应该能够在load()调用之间缓存导入和属性:https://bugs.openjdk.java.net/browse/JDK-8090848
将setAdapterFactory()添加到FXMLLoader:https://bugs.openjdk.java.net/browse/JDK-8102624