Page 1 of 1

Redimensionando un Scroll

PostPosted: Wed Aug 13, 2014 7:44 pm
by antolin
Buenas a todos.

Tengo un control que posee un Scroll vertical. He implementado una función que lo redimensiona al mismo tiempo que el Dialogo en el que se encuentra, y todo perfecto. La pega está en el Scroll, parpadea mucho, porque a cada vez que cambiao el valor de ::oVScroll:nWidth el Scroll se borra y se redibuja creando un parpadeo muy feo. He optado por incluir la clausula:

::oVScroll:bEraseBkGnd := { || NIL }

Y, el cuerpo del Scroll ya no parpadea, pero si sus botones. Algo es algo. ¿Hay alguna forma de acceder a los objetos BUTTON del Scroll? ¿Conocéis otro forma de redimensionar un Scroll que no sea cambiar los valores de su nWidth? ¿O hay alguna manera de dibujar el Scroll en un DC Compatible??

Gracias

Un saludo.

Re: Redimensionando un Scroll

PostPosted: Thu Aug 14, 2014 3:30 pm
by Antonio Linares
Antolin,

Tendrias que plantearte el implementarle el pintado a "doble buffer" que es la única manera de evitar los parpadeos.

Tienes muchos ejemplos en las clases de FWH. Busca por:

local aInfo := ::DispBegin()

... pintado estandard ...

::DispEnd( aInfo )

Re: Redimensionando un Scroll

PostPosted: Thu Aug 14, 2014 5:13 pm
by antolin
Ya Antonio, había pensado algo así, el problema es que la clase TScrollBar no tiene mucho donde trabajar. Por ejemplo, no tiene un Método Paint(), y no sé como se pinta. Con eso ya estaría solucionado.

Gracias por la respuesta

Re: Redimensionando un Scroll

PostPosted: Thu Aug 14, 2014 5:14 pm
by cnavarro
Antolin
Puedes poner un pequeño ejemplo para probarlo?

Re: Redimensionando un Scroll

PostPosted: Thu Aug 14, 2014 7:15 pm
by antolin
Por cierto, ¿alguien sabe donde se dibuja el Scroll? Porque lo único cierto es que en el Create() se crea su Window pero ¿dónde se dibuja?

Re: Redimensionando un Scroll

PostPosted: Thu Aug 14, 2014 10:20 pm
by Antonio Linares
Antolin,

Lo pinta el propio Windows es por esto que tienes que definir el método Paint() para tomar el control tu, generando el doble buffer, llamando al procedimiento original de pintado y restaurando el doble buffer.

Tienes un ejemplo aqui:

Code: Select all  Expand view

METHOD Paint() CLASS TButtonBmp

   local aInfo := ::DispBegin()  // creamos el doble buffer

   CallWindowProc( ::nOldProc, ::hWnd, WM_PAINT, ::hDC, 0 )  // llamada al procedimiento original de Windows

   ::DispEnd( aInfo )

return 1  
 

Re: Redimensionando un Scroll

PostPosted: Fri Aug 15, 2014 9:17 am
by antolin
Ok Antonio, muchas Gracias.

Re: Redimensionando un Scroll

PostPosted: Fri Aug 15, 2014 9:29 am
by antolin
Por cierto Antonio, RETURN 1 ¿es por algo en concreto? Muchas Clases retornan NIL.

Un saludo

Re: Redimensionando un Scroll

PostPosted: Fri Aug 15, 2014 9:37 am
by Antonio Linares
Si, el 1 significa que nosotros ya hicimos lo que habia que hacer y que no hay nada mas que hacer.

Es decir, el trabajo esta hecho y terminado, y por lo tanto no hay que llamar al procedimiento por defecto de Windows (que añadiría más trabajo a lo hecho)

Re: Redimensionando un Scroll

PostPosted: Fri Aug 15, 2014 10:12 am
by antolin
Todos los días aprendemos cosas nuevas. Muchas gracias.

Re: Redimensionando un Scroll

PostPosted: Fri Sep 12, 2014 4:36 pm
by antolin
Bueno, pues creo que lo he conseguido. Ya no parpadea el Scroll cuado redimensiono mi control. Lo he hecho de esta manera:

1. HE modificado la clase TScrollBar añadiendo el data: hCDC y el siguiente metodo Paint()

Code: Select all  Expand view
METHOD Paint()  CLASS TScrollBar
   IF ::hCDC = NIL
      CallWindowProc( ::nOldProc, ::hWnd, WM_PAINT, ::hDc, 0 )
   ELSE
      CallWindowProc( ::nOldProc, ::hWnd, WM_PAINT, ::hCDC,0 )
   ENDIF
RETURN 1
 

2. Al definir el Scroll hay que poner: oVScroll:bEraseBkGnd := { || NIL }

3. Cuando se redimensiona el control, hay que pintarlo en un DC compatible:

Code: Select all  Expand view
FUNCTION ResizeCtrl( PARAMETROS... )
   ...
   ...
   oDlg:GetDc()
        PaintInCDC(oDlg,oDlg:hDc)
   oDlg:ReleaseDc()
   ...
   ...
RETURN NIL

FUNCTION PaintInCDC(oDlg,hDc)
   LOCAL hCC     := CreateCompatibleDc(hDc)
   LOCAL hBmp    := CreateCompBmp(hDc,oDlg:nWidth,oDlg:nHeight)
   ...
   SelectObject(hCC,hBmp)
   oDlg:EraseBkGnd(hCC)
   ...
   // AQUI PINTAMOS EL CONTROL
   ...
   IF ::oVSCroll # NIL
      ...
      ...  // AQUI definir/calcular nTop, nLeft, nWidth, nHeight, nMin y nMax
      ...  // O TRAERLOS COMO PARAMETROS CON ESTA FUNCION
      ...  // TAMBIEN PODRIAN VENIR EN UNA ARRAY DENTRO DE oDlg:Cargo
      ...
      oVScroll:lRedraw := .F.
      oVScroll:hCDC := hCC
      oVScroll:Move(nTop,nLeft,nWidth,nHeight,.F.)
      oVScroll:SetRange(nMin,nMax)
      oVScroll:Refresh()
      oVScroll:hCDC := NIL
      oVScroll:lRedraw := .T.
      ...
   ENDIF
   ...
   BitBlt(hDc,0,0,oDlg:nWidth,oDlg:nHeight,hCC,0,0,SRCCOPY)
   *
   DeleteDc(hCC)
   DeleteObject(hBmp)
RETURN NIL
 

Si analizais este código vereis que hay que tomar una serie de precauciones:

1. Al definir el Scroll hay que hacer: oVScroll:bEraseBkGnd := { || NIL } para evitar que este se borre a la vista cada vez que desplazamos o modificamos el Scroll.

2. Para desplazar o redimensionar el Scroll hay que utilizar el métofo Scroll:Move( ...,.F. ). Con el último parámetro en .F. para que no se redibuje por su cuenta. Atención, cuando hacemos oVScroll:nTop o oVScroll:nWidth, el Scroll también se desplaza o redimensiona, pero parpadea porque seguramente el sistema utiliza el ::hDc del Scroll para repintarlo por su cuenta.

3. Si vamos a cambiar el range del Scroll tenemos que poner oVScroll:lRedraw := .F. para que el SetRange() no repinte el Scroll por su cuenta.

4. Hay que reponer oVScroll:hCDC := NIL y oVScroll:lRedraw := .T. para que el Scroll pueda redibujarse cuando se repinta el control de forma normal, por ejemplo al abrir y cerrar algún dialogo por encima.

Aun así, de vez en cuando el Scroll parpadea, pero muy levemente. Pero ya no es el continuo borrado y repintado que ocurría antes. La mejora es patente.

Espero os sea útil

Un saludo.

Re: Redimensionando un Scroll

PostPosted: Sun Sep 14, 2014 7:02 pm
by antolin
Perdón no me he dado cuenta.

En algunas versiones de FWH CreateCompatibleDc() viene como CraeteCDC() y CreateCompBmp es invento mio porque no tengo el CreateCompatibleBitmap(), que a lo mejor si lo teneis, o no, en cuyo caso así se implementa en Borland C++:

Code: Select all  Expand view
HB_FUNC( CREATECOMPBMP )    //  CreateCompBmp( HDC hDc, int nWidth, int nHight )
   {
   hb_retnl( ( LONG ) CreateCompatibleBitmap( ( HDC ) hb_parnl( 1 ), ( LONG ) hb_parnl( 2 ), ( LONG ) hb_parnl( 3 ) ) ) ;
   }
 


Un saludo