Пользовательский рендеринг AWT - захват плавных изменений размера и устранение мерцания изменения размера

Я смотрел на это в течение нескольких месяцев и пока что это лучшее, что я придумал. .

Структура (рендеринг вне EDT) не подлежит обсуждению, поскольку наше приложение работает именно так и не будет переписываться. Приложение имеет модель макета и модель сценариев, которые интегрированы и управляют рендерингом, поэтому рендеринг должен выполняться вне модели рисования AWT.

Я пытаюсь достичь оптимального и надежного способа выполнения пользовательского рендеринга. .

Следующий SSCCE работает для нас довольно хорошо. Однако во время изменения размера кадра у него есть 2 недостатка:

  • Иногда возникает мерцание, особенно при быстром изменении размера.
  • Хак «плавного изменения размера», который вызывает изменение размера (через checkSize здесь) из вызова paint (), работает только хорошо для расширений. При уменьшении кадра он обычно не отображается до тех пор, пока не будет отпущена кнопка мыши
  • Также, но здесь не так очевидно, он иногда выдает исключения IllegalStateExceptions - можно ли просто поймать / игнорировать их?

Также полезно ввести является ли это оптимальным подходом для настраиваемого пути рендеринга за пределами EDT. Я перепробовал большинство и провел довольно обширное исследование. Эта комбинация (образ резервного буфера, стратегия двойного буфера), кажется, работает лучше всего.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferStrategy;

public class SmoothResize extends Frame implements ComponentListener, MouseMotionListener {

    public SmoothResize() {
        addComponentListener(this);
        addMouseMotionListener(this);
    }

    private boolean sizeChanged = false;
    private Dimension old = new Dimension(0, 0);
    private synchronized void checkSize(String source) {
        int width = getWidth();
        int height = getHeight();
        if (old.width == width && old.height == height)
            return;
        sizeChanged = true;
        String type =
            (old.width > width && old.height > height) ? "shrink" :
                (old.width < width && old.height < height) ? "expand" : "resize";
        System.out.println(source + " reports " + type + ": "+getWidth()+", "+getHeight());
        old.setSize(width, height);
    }

    public void componentResized(ComponentEvent arg0) { checkSize("componentResized"); }
    public void mouseMoved(MouseEvent e) { checkSize("mouseMoved"); }
    public void paint(Graphics g) { checkSize("paint"); }
    public void update(Graphics g) { paint(g); }

    public void addNotify() {
        super.addNotify();
        createBufferStrategy(2);
    }

    private synchronized void render() {
        BufferStrategy strategy = getBufferStrategy();
        if (strategy==null || !sizeChanged) return;
        sizeChanged = false;
        // Render single frame
        do {
            // The following loop ensures that the contents of the drawing buffer
            // are consistent in case the underlying surface was recreated
            do {
                System.out.println("render");
                Graphics draw = strategy.getDrawGraphics();
                Insets i = getInsets();
                int w = getWidth()-i.left-i.right;
                int h = getHeight()-i.top-i.bottom;
                draw.setColor(Color.YELLOW);
                draw.fillRect(i.left, i.top+(h/2), w/2, h/2);
                draw.fillRect(i.left+(w/2), i.top, w/2, h/2);
                draw.setColor(Color.BLACK);
                draw.fillRect(i.left, i.top, w/2, h/2);
                draw.fillRect(i.left+(w/2), i.top+(h/2), w/2, h/2);
                draw.dispose();

                // Repeat the rendering if the drawing buffer contents 
                // were restored
            } while (strategy.contentsRestored());

            // Display the buffer
            strategy.show();

            // Repeat the rendering if the drawing buffer was lost
        } while (strategy.contentsLost());
    }

    public static void main(String[] args) {
        Toolkit.getDefaultToolkit().setDynamicLayout(true);
        System.setProperty("sun.awt.noerasebackground", "true");
        SmoothResize srtest = new SmoothResize();
        //srtest.setIgnoreRepaint(true);
        srtest.setSize(100, 100);
        srtest.setVisible(true);
        while (true) {
            srtest.render();
        }
    }

    public void componentHidden(ComponentEvent arg0) { }
    public void componentMoved(ComponentEvent arg0) { }
    public void componentShown(ComponentEvent arg0) { }

    public void mouseDragged(MouseEvent e) { }
}
6
задан Charles Goodwin 26 July 2011 в 09:52
поделиться