2011-08-09 9 views
7

Estoy implementando un componente Gantt para SWT y esto tarda un poco en volver a pintar (como, 200 ms para toda la parte visible del diagrama).Compuesto desplazado con contenido lento para volver a pintar se ve feo

Ahora, cuando me desplazo, solo vuelvo a pintar lo que se necesita con respecto al rectángulo de recorte. Esto hace que la aplicación se vea muy mal cuando me desplazo rápidamente, porque la parte todavía visible después del desplazamiento parece ser movida primero por el sistema operativo, y cuando terminé de pintar la parte restante (la parte que se ha vuelto visible durante el desplazamiento), inmediatamente comienza un nuevo paso de desplazamiento, moviendo la mitad de mi diagrama hacia la derecha y me permite volver a pintar la otra mitad. De hecho, parece que mi diagrama parpadea en el medio durante el desplazamiento.

Esto no se ve muy bien. ¿Hay alguna forma de evitar esto? ¿Es comprensible esta pregunta?

EDIT: Aquí hay un programa de prueba "pequeño" que muestra exactamente el comportamiento descrito. Solo necesita SWT en el classpath para ejecutarlo.

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

    } 

} 
+0

Después de leer la pregunta y los comentarios en la primera respuesta, no hay manera de cómo ayudarle sin [SSCCE] (http://sscce.org/). No tiene que exponer su código de diagrama de Gantt, simplemente haga SSCCE con cualquier cg ficticio y use la misma técnica de desplazamiento para mostrarnos el problema exactamente. – Sorceror

+0

Bien, intentaré crear un ejemplo de trabajo mínimo que muestre el problema. – Daniel

+0

¿Ha probado las técnicas [double-buffering y page-flipping] (http://download.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html), y está diciendo que no están trabajando para usted? –

Respuesta

7

La pintura SWT es muy rápida y la interfaz de usuario que falta puede rastrearse hasta métodos de pintura lentos. ¡Por lo tanto, intente optimizar el algoritmo que dibuja su diagrama! Un enfoque podría ser el almacenamiento en caché - extraer el contenido del diagrama en una imagen:

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

y volver a pintar sólo las partes de imagen necesarios cuando se desplaza:

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

Una vez que los cambios de diagramas - y sólo entonces - repintar la caché imagen usando su método de pintura complejo.

HTH

+0

Bien, lo intentaré. – Daniel

+0

No funciona también. Todavía se ve tan feo como antes, ya que hacer la copia de la imagen parece ser tan lento como renderizarlo manualmente. – Daniel

+0

¿Ha sincronizado la región de recorte con los atributos en drawImage(), es decir, ha copiado solo la subregión necesaria de la imagen en caché en lugar de pintar la entera? – Henrik

0

Me tomó la sugerencia de Henrik utilizar un Image para amortiguar la pintura y la pusieran en práctica en su SSCCE. Veo mucho menos parpadeo ahora en mi sistema.

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

Vaya, solo lea el historial de comentarios en la respuesta de Henrik más de cerca, parece que ya probó un buffer de imagen y no ayudó lo suficiente? Dejaré mi respuesta aquí de todos modos en caso de que alguien más lo encuentre útil ... –

+0

Pero tienes razón. Mucho menos parpadeo aquí. Extrañamente, si aplico la misma técnica a mi Gantt, se vuelve 3 veces más lenta. Tendré que ver si tengo otro error. – Daniel

Cuestiones relacionadas