2010-08-26 5 views
0

J'ai un problème bizarre en essayant d'exporter des JPanels Java personnalisés vers un fichier PNG. Le processus d'exportation des composants que j'ai rédigés jusqu'ici a fonctionné parfaitement.Composant JComponent personnalisé avec composants Swing incorporés non positionnés dans l'image exportée

Mes JPanels incluent des composants JComponents personnalisés (par exemple, redéfinir paintComponent (Graphics g) et écrire ce que je dois faire).

Le processus d'exportation se présente comme suit (du JPanel étendu je):

public void export(File file, int width, int height) 
    throws IOException 
{ 
    Dimension size = getSize(); 

    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
    Graphics2D g2 = image.createGraphics(); 
    draw (g2, new Rectangle (0, 0, width, height)); 

    try { 
     ImageIO.write(image, "png", file); 
    } catch (FileNotFoundException e) { 
     throw new IOException ("Unable to export chart to (" 
       + file.getAbsolutePath() + "): " + e.getLocalizedMessage()); 
    } finally { 
     g2.dispose(); 
    } 
} 

La méthode « draw() » provoque surtout des composants enfants du JPanel à tirer réutilisant la nouvelle taille de l'image à exporter. Fonctionne très bien. Le problème que j'ai aujourd'hui est que j'ai un JPanel personnalisé qui inclut des composants Swing (un JScrollPane enveloppant un JEditorPane). Ce JPanel inclut l'un de mes composants JComponents personnalisés, puis ce second composant JComponent avec le composant JScrollPane. Environ 75% du temps, ce second composant JComponent avec JScrollPane n'est pas positionné correctement dans l'image exportée lorsque j'exécute l'exportation. Il est positionné au point (0, 0) et la taille est ce à quoi il ressemble à l'écran. La méthode « draw() » pour cette JComponent se présente comme suit:

public void draw(Graphics2D g2, Rectangle componentArea) { 

    scrollPane.setBounds(componentArea); 
    textArea.setText(null); 
    sb.append("<html>"); 
    sb.append("<h1 style=\"text-align:center;\">" + "XXXXXXXXX XXXXXXX" + "</h1>"); 
    textArea.setText(sb.toString()); 

    super.paintComponents(g2); 
} 

Mais environ 25% du temps, cela fonctionne - ce JComponent avec le scrollpane est correctement positionné dans mon image exportée. Le re-dessiner les composants fonctionne.

Il est comme il y a une double mise en mémoire tampon passe ici que je ne peux pas figger ....

idées?

Répondre

0

Modifiez-vous l'objet Transformer de l'objet Graphics fourni dans votre composant personnalisé? Si vous vous assurez de l'enregistrer d'abord, puis de modifier une nouvelle instance pour vos besoins et lorsque vous avez terminé, redéfinissez l'ancienne Transform.

+0

Non, je ne sais pas. Le composant personnalisé JComponents vient de se peindre sur le contexte graphique de la nouvelle image. ils ont fait tout le positionnement de bits de bas niveau eux-mêmes en utilisant le rectangle transmis. – redBeard

0

Je voudrais essayer d'appeler la méthode paint(), pas paintComponents(). Peut-être parce que vous définissez le texte du volet de l'éditeur, le texte n'a pas été correctement analysé et le document n'est pas dans un état final lorsque vous essayez de peindre le composant. Ou peut-être parce que vous définissez dynamiquement les limites des composants que vous rencontrez des problèmes. Essayez d'encapsuler la méthode super.paint() dans un SwingUtilities.invokeLater().

La classe ScreenImage est ce que j'utilise pour créer des images. Mais je l'ai toujours utilisé pour créer des images de GUI statiques. C'est-à-dire que je ne modifie pas les limites des composants en même temps que je tente de créer une image.

+0

Hmmm, n'a pas fonctionné. Mêmes résultats ..... – redBeard

0

La disposition des composants Swing se produit généralement paresseusement plutôt que de façon immédiate, ce qui peut provoquer votre comportement intermittent. Vous pouvez essayer d'appeler directement scrollPane.doLayout() - généralement, c'est une mauvaise idée, mais cela devrait garantir que le scrollPane est déployé avant de le peindre.

Pour peindre également sur une image hors écran, vous devez probablement appeler printAll (g) plutôt que paintComponents (g) car cela évite les problèmes de double tampon.

+0

Hmm, pas de changement. mêmes résultats .... – redBeard

0

Trouvé une solution !! Vos commentaires au sujet de la «planification des événements de peinture» ont résonné dans ma tête pendant un moment. J'ai eu un problème comme celui-ci il y a quelques années et j'ai oublié cela. La vieillesse le fera ...

La solution consiste à envelopper la méthode 'draw()' dans un 'SwingUtilities.invokeAndWait()'. Voila! Ma méthode 'export()' ressemble maintenant à:

public void export(File file, final int width, final int height) 
    throws IOException 
{ 

    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
    final Graphics2D g2 = image.createGraphics(); 

    // Must wait for the bloody image to be drawn as Swing 'paint()' methods 
    // merely schedule painting events. The 'draw()' below may not complete 
    // the painting process before the 'write()' of the image is performed. 

    // thus, we wait.... 

    try { 
     SwingUtilities.invokeAndWait(new Runnable() { 
      public void run() { 
       draw (g2, new Rectangle (0, 0, width, height)); 
      } 
     }); 
     ImageIO.write(image, "png", file); 
    } catch (FileNotFoundException e) { 
     throw new IOException ("Unable to export chart to (" 
       + file.getAbsolutePath() + "): " + e.getLocalizedMessage()); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
     throw new IOException ("Unable to export chart to (" 
       + file.getAbsolutePath() + "): " + e.getLocalizedMessage()); 
    } catch (InvocationTargetException e) { 
     e.printStackTrace(); 
     throw new IOException ("Unable to export chart to (" 
       + file.getAbsolutePath() + "): " + e.getLocalizedMessage()); 
    } finally { 
     g2.dispose(); 
    } 
} 

Whew!

+0

Cela va accrocher l'interface graphique si appelé sur l'EDT! Ce qui me fait penser que le problème est vraiment que le code d'exportation appelle la peinture sur un thread non-EDT. Probablement, quelque part au fond des entrailles de Swing, une méthode a déterminé qu'il n'était pas sur l'EDT et de faire un appel plus tard, ce qui retarde la peinture réelle. –

Questions connexes