Прокручиваемый композит с медленным перерисовыванием контента выглядит некрасиво - PullRequest
7 голосов
/ 09 августа 2011

Я реализую компонент Ганта для SWT, и для его перерисовки требуется немного времени (например, 200 мс для всей видимой части диаграммы).

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

Это выглядит не очень хорошо.Есть ли способ обойти это?Понятен ли этот вопрос?

РЕДАКТИРОВАТЬ : Вот «маленькая» тестовая программа, которая точно описывает описанное поведение.Вам нужен только SWT в classpath для его запуска.

package de.ikoffice.gui;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class SlowRepaintProblem {

    public Color[] colors = new Color[501];

    public SlowRepaintProblem() {
        Display display = Display.getDefault();
        for( int i=0; i<=500; i++ ) {
            int r = ( i * 10 ) % 256;
            int g = ( i * 20 ) % 256;
            int b = ( i * 30 ) % 256;
            colors[i] = new Color(display,r,g,b);
        }

        Shell shell = new Shell(display);
        shell.setText("SlowRepaintTest");
        ScrolledComposite comp = new ScrolledComposite(shell,
                SWT.H_SCROLL | SWT.V_SCROLL | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND);
        SlowRepaintingCanvas canvas = new SlowRepaintingCanvas(comp,SWT.NONE| SWT.NO_BACKGROUND);
        comp.setContent(canvas);
        canvas.setSize(5000,5000);

        // Layouting
        shell.setLayout(new GridLayout());        
        comp.setLayoutData(new GridData(GridData.FILL_BOTH));
        shell.setBounds(50, 50, 800, 600);

        // Showing the control
        shell.open();
        while (!shell.isDisposed()) {
            try {
                if (!shell.getDisplay().readAndDispatch()) {
                    shell.getDisplay().sleep();
                }
            } catch (Throwable e) {
                String message = e.getMessage();
                if( message == null || !e.getMessage().equals("Widget is diposed") ) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

    public static void main(String[] args) {
        new SlowRepaintProblem(); // Evil constructor call to start main program flow.
    }

    class SlowRepaintingCanvas extends Canvas {

        public SlowRepaintingCanvas(Composite parent, int style) {
            super(parent, style);

            addPaintListener(new PaintListener() {
                @Override
                public void paintControl(PaintEvent e) {
                    GC gc = e.gc;
                    Rectangle r = gc.getClipping();
                    gc.setAlpha(255);
//                    gc.setBackground(ColorUtils.WHITE);
//                    gc.fillRectangle(r);

                    int x = r.x - (r.x % 10);
                    int width = (r.width + r.x - x) - (r.width + r.x - x) % 10 + 10;
                    int y = r.y - (r.y % 10);
                    int height = (r.height + r.y - y) - (r.height + r.y - y) % 10 + 10;

                    gc.setAlpha(128);
                    for( int i = x; i < x+width; i+= 10 ) {
                        gc.setBackground(colors[i/10]);
                        gc.fillRectangle(i, r.y, 10, r.height);  
                    }
                    for( int j = y; j < y+height; j+= 10 ) {
                        gc.setBackground(colors[j/10]);
                        gc.fillRectangle(r.x, j, r.width, 10);  
                    }
                }
            });
        }

    }

}

Ответы [ 2 ]

7 голосов
/ 09 августа 2011

SWT-рисование очень быстрое, и отсутствие интерфейса обычно можно отследить до медленных методов рисования.Следовательно, попробуйте оптимизировать алгоритм, который рисует вашу диаграмму!Одним из подходов может быть кэширование - нарисуйте содержимое диаграммы в изображение:

Image cache = new Image(Display.getCurrent(), width, height);
GC gc = new GC(cache);

и перекрасьте только необходимые части изображения при прокрутке:

gc.drawImage(cache, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight);

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

HTH

0 голосов
/ 17 августа 2011

Я принял предложение Хенрика использовать Image для буферизации живописи и внедрил его в свой SSCCE. Теперь я вижу гораздо меньше мерцания в моей системе.

        addPaintListener(new PaintListener() {
            @Override
            public void paintControl(PaintEvent e) {
                GC gc = e.gc;
                Rectangle r = gc.getClipping();

                int x = r.x - (r.x % 10);
                int width = (r.width + r.x - x) - (r.width + r.x - x) % 10 + 10;
                int y = r.y - (r.y % 10);
                int height = (r.height + r.y - y) - (r.height + r.y - y) % 10 + 10;

                Image image = new Image(gc.getDevice(),width,height);
                GC igc = new GC(image);

                // Without buffering, this code was necessary to prevent "ghost"
                // scrollbars on window resize, but with buffering it is no longer
                // required...it does affect the visual results however.
                //igc.setAlpha(255);
                //igc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK));
                //igc.fillRectangle(image.getBounds());

                igc.setAlpha(128);
                for( int i = x; i < x+width; i+= 10 ) {
                    igc.setBackground(colors[i/10]);
                    igc.fillRectangle(i-x, 0, 10, height);  
                }
                for( int j = y; j < y+height; j+= 10 ) {
                    igc.setBackground(colors[j/10]);
                    igc.fillRectangle(0, j-y, width, 10);  
                }

                gc.drawImage(image, x, y);
                igc.dispose();
                image.dispose();
            }
        });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...