Пользовательский JComponent со встроенными компонентами Swing, не расположенными в экспортированном изображении - PullRequest
0 голосов
/ 27 августа 2010

У меня странная проблема при попытке экспортировать пользовательские Java JPanels в файл PNG.Процесс экспорта компонентов, которые я писал до сих пор, работал безупречно.

Мои JPanels включают в себя написанные пользователем JComponents (например, переопределите paintComponent (Graphics g) и напишите, что мне нужно).

Процесс экспорта выглядит следующим образом (из расширенного JPanel, который у меня есть):

 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();
     }
}

Приведенный выше метод 'draw ()' вызывает перерисовку всех дочерних компонентов JPanel с использованиемновый размер изображения для экспорта.Работает очень хорошо.

Проблема, с которой я столкнулся сегодня, состоит в том, что у меня есть один пользовательский JPanel, который включает некоторые компоненты Swing (JScrollPane, обертывающий JEditorPane).Этот JPanel включает в себя один из моих пользовательских JComponents, а затем этот второй JComponent с JScrollPane.

Примерно в 75% случаев этот второй JComponent с JScrollPane неправильно позиционируется в экспортированном изображении, когда я выполняюэкспорт.Он расположен в точке (0, 0), а его размер соответствует тому, как он выглядит на экране.Метод draw () для этого JComponent выглядит следующим образом:

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);
}

Но примерно в 25% случаев это работает - этот JComponent с полосой прокрутки правильно расположен на моем экспортированном изображении.Перерисовать компонент работает.

Как будто здесь происходит какая-то двойная буферизация, которую я не могу извлечь ....

Идеи?

Ответы [ 4 ]

0 голосов
/ 27 августа 2010

Нашли решение !!Ваши комментарии о «планировании событий живописи» немного прозвенели в моей голове.У меня была такая проблема несколько лет назад, и я забыл об этом.Старость сделает это ....

Решение состоит в том, чтобы заключить метод draw () в SwingUtilities.invokeAndWait ().Вуаля!Мой метод 'export ()' теперь выглядит так:

    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();
    }
}

Вот так!

0 голосов
/ 27 августа 2010

Я бы попытался вызвать метод paint (), а не paintComponents ().

Возможно, из-за того, что вы устанавливаете текст в панели редактора, текст не был правильно проанализирован, а Document не находится вокончательное состояние при попытке нарисовать компонент.Или, может быть, потому что вы динамически устанавливаете границы компонентов, у вас есть проблемы.Попробуйте обернуть метод super.paint () в SwingUtilities.invokeLater ().

Класс ScreenImage - это то, что я использую для создания изображений.Но я всегда использовал его для создания изображений статических графических интерфейсов.То есть я не изменяю границы компонентов одновременно пытаясь создать образ.

0 голосов
/ 27 августа 2010

Компоновка компонентов Swing обычно происходит лениво, а не сразу, что может быть причиной вашего неустойчивого поведения.Вы можете попробовать вызвать scrollPane.doLayout () напрямую - обычно это плохая идея, но она должна гарантировать, что scrollPane будет размечен до того, как вы его нарисуете.

Также для рисования за пределами экрана вы, вероятно, должны вызывать printAll (g), а не paintComponents (g), поскольку это позволяет избежать проблем двойной буферизации.

0 голосов
/ 27 августа 2010

Изменяете ли вы каким-либо изменением объект Transform предоставленного объекта Graphics в вашем пользовательском компоненте?Если вы сначала сохраните его, а затем измените новый экземпляр для своих целей, а когда закончите, верните старую трансформацию обратно.

...