Java падает при изменении размера JFrame с нарисованным bufferedImage - PullRequest
0 голосов
/ 21 июня 2019

Я делаю интерфейс, который содержит нарисованное изображение, которое имеет максимально возможный размер при сохранении соотношения сторон в JFrame.Приведенный ниже код используется для достижения этой цели:

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);

    if (image == null) {
        return;
    }

    // Calculate what image size fits within the component's bounds
    Dimension fittingImageSize = getFittingImageSize();

    // Scale the image. We use AffineTransform as it's much faster than scaledInstance(...)
    AffineTransform at = new AffineTransform();
    at.scale(fittingImageSize.getWidth() / image.getWidth(), fittingImageSize.getHeight() / image.getHeight());
    AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
    BufferedImage scaledImage = new BufferedImage((int)fittingImageSize.getWidth(), (int)fittingImageSize.getHeight(), image.getType());
    scaleOp.filter(image, scaledImage);

    // Calculate the offset        
    Point offset = getImageOffset(fittingImageSize);

    // Draw the image
    Graphics2D g2 = (Graphics2D) g;
    g2.drawImage(scaledImage, offset.x, offset.y, null);
}

Однако, когда я изменяю размер JFrame, я получаю исключение пространства в куче:

Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
    at java.awt.image.DataBufferInt.<init>(DataBufferInt.java:75)
    at java.awt.image.Raster.createPackedRaster(Raster.java:467)
    at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1032)
    at java.awt.image.BufferedImage.<init>(BufferedImage.java:333)

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

1 Ответ

0 голосов
/ 21 июня 2019

Я использовал небольшой обходной путь для предотвращения перекраски во время изменения размера компонента. Я добавил ComponentListener к соответствующему компоненту, а в методе componentResized я сделал следующее:

@Override
public void componentResized(ComponentEvent e) {
    isResizing = true;
    timer.cancel();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            isResizing = false;
            revalidate();
            repaint();
        }

    }, redrawAfterResizeDelay);
}

Затем в paintComponent я защищаю от логического isResizing: если это правда, то paintComponent возвращается рано.

Это не самое лучшее исправление, поэтому я все еще надеюсь на лучшие ответы, но в моей ситуации это приемлемое исправление.

Редактировать: вышеприведенное исправление может работать для других, но это не было основной проблемой.

Проблема была в том, как я вычислил fittingImageSize. Если ширина, разделенная на высоту компонента, будет больше, чем высота, разделенная на ширину компонента, тогда будет возвращен неправильный fittingImageSize, в результате чего приложение попытается создать BufferedImage с шириной в несколько миллионов пикселей. Это то, что привело к исключениям памяти.

...