2012-07-31 24 views
9

समस्या मैं रनटाइम पर कस्टम मेड पैनलों, JavaFX दृश्य बिल्डर के माध्यम से बनाया जोड़ने के लिए, एक gridpane करना चाहते हैं। मेरे कस्टम बनाया पैनल बटन, लेबल और इतने पर exsits।JavaFX2 - बहुत खराब प्रदर्शन जब कस्टम मेड (fxml) पैनलों जोड़ने gridpane को गतिशील

मेरे प्रयास मैं फलक से विस्तार करने के लिए कोशिश की ...

public class Celli extends Pane{ 
    public Celli() throws IOException{ 
     Parent root = FXMLLoader.load(getClass().getResource("Cell.fxml")); 
     this.getChildren().add(root);  
    } 
} 

... और फिर conroller

@FXML 
private void textChange(KeyEvent event) { 
    GridPane g = new GridPane(); 
     for (int i=0 : i<100; i++){ 
       g.getChildren().add(new Celli()); 
     } 
    } 
} 

यह काम करता है के जोड़ने विधि में इस पैनल का उपयोग करें, लेकिन यह बहुत खराब प्रदर्शन करता है।

क्या मैं रहा हूँ वहाँ JavaFX दृश्य बिल्डर के माध्यम से पैनल डिजाइन करने के लिए एक रास्ता है (और एक परिणाम के fxml में इस पैनल होने के रूप में) और फिर के लिए इस fxmlloader का मेकअप उपयोग के बिना रनटाइम पर एक gridpane में जोड़ने प्रत्येक उदाहरण। मुझे लगता है कि यह fxml लोडर की वजह से खराब प्रदर्शन करता है। जब मैं मानक बटन जोड़ता हूं उदा। whitout fxml यह बहुत तेज है।

उत्तर

19

संक्षिप्त उत्तर: नहीं, यह नहीं है (जावाएफएक्स 2.x और 8.0 के रूप में)। यह एक भविष्य संस्करण में हो सकता है (JFX> 8)

लांग जवाब: FXMLLoader वर्तमान में एक टेम्पलेट प्रदाता है कि एक ही आइटम बार बार को दर्शाता है के रूप में प्रदर्शन करने के लिए नहीं बनाया गया है। इसके बजाय यह बड़े जीयूआई (या उन्हें क्रमबद्ध करने के लिए) के लिए एक बार लोडर होने का मतलब है।

प्रदर्शन खराब है क्योंकि FXML फ़ाइल के आधार पर, प्रत्येक कॉल पर load() पर, FXMLLoader को प्रतिबिंब के माध्यम से कक्षाओं और इसकी गुणों को देखना होगा। इसका अर्थ है:

  1. प्रत्येक आयात विवरण के लिए, कक्षा को सफलतापूर्वक लोड होने तक प्रत्येक कक्षा को लोड करने का प्रयास करें।
  2. प्रत्येक वर्ग के लिए, एक बीन एडाप्टर बनाएं जो इस वर्ग के सभी गुणों को देखता है और संपत्ति को दिए गए मानकों को लागू करने का प्रयास करता है।
  3. गुणों के पैरामीटर का उपयोग फिर से प्रतिबिंब के माध्यम से किया जाता है।

वर्तमान में कोड में किए गए उसी FXML फ़ाइल में load() पर अगली कॉल के लिए कोई सुधार नहीं है। इसका मतलब है: पाए गए वर्गों की कोई कैशिंग नहीं, बीनएडाप्टर की कैशिंग नहीं है और इसी तरह।

वहाँ FXMLLoader उदाहरण के लिए एक कस्टम classloader की स्थापना करके, चरण 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(); 
    } 
} 

उपयोग:

public static ClassLoader cachingClassLoader = new MyClassLoader(FXMLLoader.getDefaultClassLoader()); 

FXMLLoader loader = new FXMLLoader(resource); 
loader.setClassLoader(cachingClassLoader); 

यह महत्वपूर्ण प्रदर्शन को गति। हालांकि, चरण 2 के लिए कोई कामकाज नहीं है, इसलिए यह अभी भी एक समस्या हो सकती है।

हालांकि, इसके लिए आधिकारिक जावाएफएक्स जिरा में पहले ही फीचर अनुरोध हैं। इन अनुरोधों का समर्थन करना आपके लिए अच्छा होगा।

लिंक:

http://javafx-jira.kenai.com/browse/RT-23413

http://javafx-jira.kenai.com/browse/RT-23511

+0

शानदार उत्तर सेबेस्टियन – jewelsea

+0

अंत में लिंक अब मान्य नहीं हैं। क्या किसी को पता है कि वे क्या इंगित करते थे, और अद्यतन जेडीके - ??? उनके अनुरूप आईडी? – Itai

2

मैं ने वही समस्या पड़ा है। मुझे कई बार गतिशील रूप से एक कस्टम fxml- आधारित घटक लोड करना पड़ा, और यह बहुत लंबा समय ले रहा था। मेरे मामले में FXMLLoader.load विधि कॉल महंगा था।

मेरा दृष्टिकोण घटक तत्कालता को समानांतर करना था और इससे समस्या हल हो गई।

उदाहरण सवाल पर पोस्ट को ध्यान में रखते, multithread दृष्टिकोण के साथ नियंत्रक तरीका होगा:

private void textChange(KeyEvent event) { 
    GridPane g = new GridPane(); 
    // creates a thread pool with 10 threads 
    ExecutorService threadPool = Executors.newFixedThreadPool(10); 
    final List<Celli> listOfComponents = Collections.synchronizedList(new ArrayList<Celli>(100)); 

    for (int i = 0; i < 100; i++) { 
     // parallelizes component loading 
     threadPool.execute(new Runnable() { 
      @Override 
      public void run() { 
       listOfComponents.add(new Celli()); 
      } 
     }); 
    } 

    // waits until all threads completion 
    try { 
     threadPool.shutdown();  
     threadPool.awaitTermination(3, TimeUnit.SECONDS); 
    } catch (InterruptedException e) { 
     // seems to be a improbable exception, but we have to deal with it 
     e.printStackTrace(); 
    } 

    g.getChildren().addAll(listOfComponents); 
} 
+0

जावाएफएक्स के किस संस्करण ने आप 2.2 या 8. ओ का उपयोग किया था? JavaFX8.0 के साथ, आपकी विधि अपवाद के साथ विफल हो जाती है: "java.lang.IllegalStateException: FX अनुप्रयोग थ्रेड पर नहीं ..." – Daniel

+0

संस्करण जो मैंने इस कोड का उपयोग किया था 2.2 था। – Crferreira

0

बस "पहले से ही भरी हुई कक्षाओं की कैशिंग के लिए" कोड जोड़ने कोड दिया @Sebastian सर में। यह मेरे लिए काम कर रहा है। कृपया बेहतर प्रदर्शन के लिए इसमें बदलाव का सुझाव दें।

@Override 
public Class<?> loadClass(String name) throws ClassNotFoundException { 
    System.out.println("In Class loader"); 

    Class result; 
    System.out.println(" >>>>>> Load class : "+name); 
    result = (Class)classes.get(name); 
    if(result != null){ 
     System.out.println(" >>>>>> returning cached class."); 
     return result; 
    }else{ 
    Class<?> c = findClass(name); 
    if (c == null) { 
     throw new ClassNotFoundException(name); 
    } 
    System.out.println(" >>>>>> loading new class for first time only"); 
    return c; 
    } 
}