Pregunta

Estoy intentando sincronizar el desplazamiento de dos componentes TDBGrid en una aplicación VCL Forms, tengo dificultades para interceptar el WndProc de cada componente de la cuadrícula sin algunos problemas de pila.Intenté enviar mensajes WM_VSCROLL bajo eventos de desplazamiento, pero esto todavía resulta en una operación incorrecta.Debe funcionar para hacer clic en la barra de desplazamiento, así como para resaltar una celda o un botón del mouse hacia arriba o hacia abajo.La idea es tener dos cuadrículas una al lado de la otra que muestren una especie de diálogo coincidente.

Intentó

SendMessage( gridX.Handle, WM_VSCROLL, SB_LINEDOWN, 0 );

También

procedure TForm1.GridXCustomWndProc( var Msg: TMessage );
begin
Msg.Result := CallWindowProc( POldWndProc, gridX.Handle, Msg.Msg, Msg.wParam, Msg.lParam );

   if ( Msg.Msg = WM_VSCROLL ) then 
   begin
      gridY.SetActiveRow( gridX.GetActiveRow );
      gridY.Perform( Msg.Msg, Msg.wParam, Msg.lParam );
      SetScrollPos( gridY.Handle, SB_VERT, HIWORD( Msg.wParam ), True );
   end;
end;

Y

procedure TForm1.GridxCustomWndProc( var Msg: TMessage );
begin
   if ( Msg.Msg = WM_VSCROLL ) then 
   begin
      gridY.SetActiveRow( gridX.GetActiveRow );
      gridY.Perform( Msg.Msg, Msg.wParam, Msg.lParam );
      SetScrollPos( gridY.Handle, SB_VERT, HIWORD( Msg.wParam ), True );
   end;
   inherited WndProc( Msg );
end;

La primera es solo una solución temporal, la segunda genera lecturas de memoria no válidas y la tercera genera un desbordamiento de pila.Entonces ninguna de estas soluciones parece funcionar para mí.¡Me encantaría recibir comentarios sobre cómo realizar esta tarea!Gracias de antemano.

ACTUALIZAR:Solución

  private
    [...]
    GridXWndProc, GridXSaveWndProc: Pointer;
    GridYWndProc, GridYSaveWndProc: Pointer;
    procedure GridXCustomWndProc( var Msg: TMessage );
    procedure GridYCustomWndProc( var Msg: TMessage );

procedure TForm1.FormCreate(Sender: TObject);
begin
  GridXWndProc := classes.MakeObjectInstance( GridXCustomWndProc );
  GridXSaveWndProc := Pointer( GetWindowLong( GridX.Handle, GWL_WNDPROC ) );
  SetWindowLong( GridX.Handle, GWL_WNDPROC, LongInt( GridXWndProc ) );

  GridYWndProc := classes.MakeObjectInstance( GridYCustomWndProc );
  GridYSaveWndProc := Pointer( GetWindowLong( GridY.Handle, GWL_WNDPROC ) );
  SetWindowLong( GridY.Handle, GWL_WNDPROC, LongInt( GridYWndProc ) );
end;

procedure TForm1.GridXCustomWndProc( var Msg: TMessage );
begin
   Msg.Result := CallWindowProc( GridXSaveWndProc, GridX.Handle, Msg.Msg, Msg.WParam, Msg.LParam );
   case Msg.Msg of
      WM_KEYDOWN:
      begin
         case TWMKey( Msg ).CharCode of VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT:
            GridY.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
         end;
      end;
      WM_VSCROLL:
         GridY.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
      WM_HSCROLL:
         GridY.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
      WM_MOUSEWHEEL:
      begin
         ActiveControl := GridY;
         GridY.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
      end;
      WM_DESTROY:
      begin
         SetWindowLong( GridX.Handle, GWL_WNDPROC, Longint( GridXSaveWndProc ) );
         Classes.FreeObjectInstance( GridXWndProc );
      end;
  end;
end;

procedure TForm1.GridXMouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
begin
   GridY.SetActiveRow( GridX.GetActiveRow );
end;

procedure TForm1.GridYCustomWndProc( var Msg: TMessage );
begin
   Msg.Result := CallWindowProc( GridYSaveWndProc, GridY.Handle, Msg.Msg, Msg.WParam, Msg.LParam );
   case Msg.Msg of
      WM_KEYDOWN:
      begin
         case TWMKey( Msg ).CharCode of VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT:
            GridX.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
         end;
      end;
      WM_VSCROLL:
         GridX.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
      WM_HSCROLL:
         GridX.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
      WM_MOUSEWHEEL:
      begin
         ActiveControl := GridX;
         GridX.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
      end;
      WM_DESTROY:
      begin
         SetWindowLong( GridY.Handle, GWL_WNDPROC, Longint( GridYSaveWndProc ) );
         Classes.FreeObjectInstance( GridYWndProc );
      end;
   end;
end;

procedure TForm1.GridYMouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
begin
   GridX.SetActiveRow( GridY.GetActiveRow );
end;

Gracias a Sertac Akyuz por la solución.Cuando se integran en una aplicación de formularios VCL mediante cuadrículas, se imitarán entre sí al desplazarse y resaltar el registro seleccionado.

¿Fue útil?

Solución

Probablemente esté implementando la anulación del mensaje para ambas redes.Gridx se desplaza a Gridy, que a su vez se desplaza a Gridx, que a su vez ... Entonces.Puede proteger el código de desplazamiento superficial al rodear el bloque con las banderas.

type
  TForm1 = class(TForm)
    [..] 
  private
    FNoScrollGridX, FNoScrollGridY: Boolean;
    [..]

procedure TForm1.GridXCustomWndProc( var Msg: TMessage );
begin
  Msg.Result := CallWindowProc(POldWndProc, gridX.Handle, Msg.Msg, Msg.wParam, Msg.lParam );

  if ( Msg.Msg = WM_VSCROLL ) then 
  begin
    if not FNoScrollGridX then
    begin
      FNoScrollGridX := True
      gridY.SetActiveRow( gridX.GetActiveRow );
      gridY.Perform( Msg.Msg, Msg.wParam, Msg.lParam );
//      SetScrollPos( gridY.Handle, SB_VERT, HIWORD( Msg.wParam ), True );
    end;
    FNoScrollGridX := False;
  end;
end;

Código Similiar para la Gridia.Por cierto, no necesitas los Setscrollpos.


Editar:

TForm1 = class(TForm)
  [..]
private
  GridXWndProc, GridXSaveWndProc: Pointer;
  GridYWndProc, GridYSaveWndProc: Pointer;
  procedure GridXCustomWndProc(var Msg: TMessage);
  procedure GridYCustomWndProc(var Msg: TMessage);
  [..]

procedure TForm1.FormCreate(Sender: TObject);
begin
  [..]

  GridXWndProc := classes.MakeObjectInstance(GridXCustomWndProc);
  GridXSaveWndProc := Pointer(GetWindowLong(GridX.Handle, GWL_WNDPROC));
  SetWindowLong(GridX.Handle, GWL_WNDPROC, LongInt(GridXWndProc));

  GridYWndProc := classes.MakeObjectInstance(GridYCustomWndProc);
  GridYSaveWndProc := Pointer(GetWindowLong(GridY.Handle, GWL_WNDPROC));
  SetWindowLong(GridY.Handle, GWL_WNDPROC, LongInt(GridYWndProc));
end;

procedure TForm1.GridXCustomWndProc(var Msg: TMessage);
begin
  Msg.Result := CallWindowProc(GridXSaveWndProc, GridX.Handle,
      Msg.Msg, Msg.WParam, Msg.LParam);

  case Msg.Msg of
    WM_KEYDOWN:
      begin
        case TWMKey(Msg).CharCode of
          VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT:
            GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
        end;
      end;
    WM_VSCROLL: GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
    WM_MOUSEWHEEL:
      begin
        ActiveControl := GridY;
        GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
      end;
    WM_DESTROY:
      begin
        SetWindowLong(GridX.Handle, GWL_WNDPROC, Longint(GridXSaveWndProc));
        Classes.FreeObjectInstance(GridXWndProc);
      end;
  end;
end;

procedure TForm1.GridYCustomWndProc(var Msg: TMessage);
begin
  Msg.Result := CallWindowProc(GridYSaveWndProc, GridY.Handle,
      Msg.Msg, Msg.WParam, Msg.LParam);

  case Msg.Msg of
    WM_KEYDOWN:
      begin
        case TWMKey(Msg).CharCode of
          VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT:
            GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
        end;
      end;
    WM_VSCROLL: GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
    WM_MOUSEWHEEL:
      begin
        ActiveControl := GridX;
        GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
      end;
    WM_DESTROY:
      begin
        SetWindowLong(GridY.Handle, GWL_WNDPROC, Longint(GridYSaveWndProc));
        Classes.FreeObjectInstance(GridYWndProc);
      end;
  end;
end;

Otros consejos

Tengo una solución parcial, pero ahora completa (al menos para dos TMEMO) ...

Me refiero a parcial, porque solo escucha cambios en un TMEMO, pero no en el otro ...

Me refiero a trabajo completo porque no depende de lo que se hace ...

Es tan simple como el mismo valor de desplazamiento horizontal en una nota, ya que está en el otro ...

No es nada relacionado con los mensajes, pero como estaba tratando de obtener una solución de trabajo al atrapar mensajes WM_HSCROLL, etc. Dejé el código porque funciona ... Intentaré mejorarlo más tarde ... para Ejemplo de captura solo WM_PAINT, o de otras maneras ... Pero por ahora, lo puse, ya que lo tengo, ya que funciona ... y no encontré a ningún lado algo aún mejor ...

Aquí está el código que funciona:

// On private section of TForm1
Memo_OldWndProc:TWndMethod; // Just to save and call original handler
procedure Memo_NewWndProc(var TheMessage:TMessage); // New handler

// On implementation section of TForm1    
procedure TForm1.FormCreate(Sender: TObject);
begin
     Memo_OldWndProc:=Memo1.WindowProc; // Save the handler
     Memo1.WindowProc:=Memo_NewWndProc; // Put the new handler, so we can do extra things
end;

procedure TForm1.Memo_NewWndProc(var TheMessage:TMessage);
begin
     Memo_OldWndProc(TheMessage); // Let the scrollbar to move to final position
     Memo2.Perform(WM_HSCROLL
                  ,SB_THUMBPOSITION+65536*GetScrollPos(Memo1.Handle,SB_HORZ)
                  ,0
                  ); // Put the horizontal scroll of Memo2 at same position as Memo1
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
     Memo1.WindowProc:=Memo_OldWndProc; // Restore the old handler
end;

Funciona para todas las formas de hacer que se desplazara para cambiar ...

Notas:

  • Sé que es horrible atrapar todos los mensajes, pero al menos funciona ...
  • Este es mi primer intento exitoso de tener dos TMemos con sincronizados Barra de desplazamiento horizontal ...
  • Entonces, si alguien puede mejorarlo un poco (no atrapa todos los mensajes) por favor hacerlo y publicarlo.
  • solo hace que Memo1 esté en la sincronización horizontal con la barra de memo2, pero no Memo2 para estar en sincronización con memo1
  • Presione las teclas arriba, abajo, izquierda, derecha, Rousewheel, etc ... sea lo que sea QUIERE PERO EN MEMO2 PARA VERLO EN LA ACCIÓN

Intentaré mejorarlo por: Al hacer algo en Memo2, Memo1 Scroll sigue sincronizado ...

Creo que puede funcionar para casi cualquier control que tenga una barra de desplazamiento, no solo TMEMO ...

como le dije ...

Aquí es una solución mejor (no definitiva) en términos de eficiencia, código limpio y bidireccional ... cambiando a cualquiera que afecte al otro ...

Por favor, lee los comentarios sobre el código para entender qué hace cada oración ... Es bastante complicado ... pero la idea principal es la misma que antes ... Establezca la otra barra de desplazamiento horizontal de TMEMO, ya que está en el TMEMO Donde el usuario está actuando ... No importa qué usuario haga, mueva el mouse y seleccione Texto, presione la izquierda, la derecha, la casa, las teclas de extremo, use la rueda horizontal del mouse (no todas tiene una), arrastre la parte de Srollbar, presione en cualquier parte de la barra de desplazamiento horizontal, etc ...

La idea principal es ... El objeto debe volver a pintarse, así que luego ponga el otro objeto Barra de desplazamiento horizontal idéntico a este ...

Esta primera parte es solo para agregar cosas a la clase TMEMO, solo está creando una nueva clase derivada, pero con el mismo nombre de clase, pero solo para la unidad dentro de la declaración.

Agregue esto a la sección de la interfaz, antes de su declaración TFRE, por lo que su TFRE verá esta nueva clase TMEMO en lugar de una normal:

type
    TMemo=class(StdCtrls.TMemo) // Just to add things to TMemo class only for this unit
    private
       BusyUpdating:Boolean; // To avoid circular stack overflow
       SyncMemo:TMemo; // To remember the TMemo to be sync
       Old_WindowProc:TWndMethod; // To remember old handler
       procedure New_WindowProc(var Mensaje:TMessage); // The new handler
    public
       constructor Create(AOwner:TComponent);override; // The new constructor
       destructor Destroy;override; // The new destructor
    end;

Esta siguiente parte es la implementación de declaraciones anteriores de esa nueva clase de TMEMO.

Agregar esto a la sección de implementación en cualquier lugar que prefieras:

constructor TMemo.Create(AOwner:TComponent); // The new constructor
begin
     inherited Create(AOwner); // Call real constructor
     BusyUpdating:=False; // Initialize as not being in use, to let enter
     Old_WindowProc:=WindowProc; // Remember old handler
     WindowProc:=New_WindowProc; // Replace handler with new one
end;

destructor TMemo.Destroy; // The new destructor
begin
     WindowProc:=Old_WindowProc; // Restore the original handler
     inherited Destroy; // Call the real destructor
end;

procedure TMemo.New_WindowProc(var Mensaje:TMessage);
begin
     Old_WindowProc(Mensaje); // Call the real handle before doing anything
     if  BusyUpdating // To avoid circular stack overflow
       or
         (not Assigned(SyncMemo)) // If not yet set (see TForm1.FormCreate bwlow)
       or
         (WM_PAINT<>Mensaje.Msg) // If not when need to be repainted to improve speed
     then Exit; // Do no more and exit the procedure
     BusyUpdating:=True; // Set that object is busy in our special action
     SyncMemo.Perform(WM_HSCROLL,SB_THUMBPOSITION+65536*GetScrollPos(Handle,SB_HORZ),0); // Send to the other TMemo a message to set its horizontal scroll as it is on this TMemo
     BusyUpdating:=False; // Set that the object is no more busy in our special action
end;

Ahora la última parte, dígale a cada TMEMO, ¿cuál es la otra nota que tiene que estar en sincronización?

En su sección de implementación, para el formulario Crear evento Agregue algo como esto:

procedure TForm1.FormCreate(Sender: TObject);
begin
     Memo1.SyncMemo:=Memo2; // Tell Memo1 what TMemo must sync (Memo2)
     Memo2.SyncMemo:=Memo1; // Tell Memo2 what TMemo must sync (Memo1)
end;

Recuerde que hemos agregado SyncMemo Miembro a nuestra nueva clase de TMEMO especial, estuvo allí solo para esto, díganse unos a otros cuál es el otro.

Ahora, una pequeña configuración tanto para que TMEMO JSUT deje que esto funcione perfectamente:

  • Deja que ambos barras de desplazamiento de TMEMO sean visibles
  • Deja que Wordwrap False en ambos TMEMO
  • Ponga mucho texto (lo mismo para ambos), líneas largas y muchas líneas

Ejecutarlo y ver cómo ambas barras de desplazamiento horizontal están siempre en sincronización ...

  • Si mueve una barra de desplazamiento horizontal, la otra barra de desplazamiento horizontal Mueve ...
  • Si va en el texto a la derecha o hacia la izquierda, el inicio de la línea o la línea, etc ..., sin importar dónde se encuentre en el otro ... la horizontal El desplazamiento de texto está en sincronización.

El problema por qué esta no es una versión final es que:

  • Las barras de desplazamiento (Horizontal en mi caso) no se pueden ocultar ... Dado que si se oculta, cuando se llama a Getscrollpos, devuelve cero, por lo que hace que no esté sincronizado.

Si alguien sabe cómo emular escondido o hacer que GetscrollPOS no devuelva cero, comente, lo único que necesito para solucionar para la versión final.

Notas:

  • , obviamente, lo mismo se puede hacer con la barra de desplazamiento vertical ... solo cambia Wm_hscroll to wm_vscroll y sb_horz a sb_vert
  • Obviamente, lo mismo se puede hacer por ambos al mismo tiempo ... simplemente copiar la línea de SyncMemo.Perform Fallo dos veces y en uno, deja que WM_HSCROLL y SB_HORZ y el otro, deje que WM_VSCROLL y SB_VERT

Aquí hay un ejemplo de New_WindowProc Procedimiento para sincronizar ambas barras de desplazamiento al mismo tiempo, tal vez para personas perezosas, tal vez para las personas que le gustan la copia y la pegar:

procedure TMemo.New_WindowProc(var Mensaje:TMessage);
begin
     Old_WindowProc(Mensaje); // Call the real handle before doing anything
     if  BusyUpdating // To avoid circular stack overflow
       or
         (not Assigned(SyncMemo)) // If not yet set (see TForm1.FormCreate bwlow)
       or
         (WM_PAINT<>Mensaje.Msg) // If not when need to be repainted to improve speed
     then Exit; // Do no more and exit the procedure
     BusyUpdating:=True; // Set that object is busy in our special action
     SyncMemo.Perform(WM_HSCROLL,SB_THUMBPOSITION+65536*GetScrollPos(Handle,SB_HORZ),0); // Send to the other TMemo a message to set its horizontal scroll as it is on this TMemo
     SyncMemo.Perform(WM_VSCROLL,SB_THUMBPOSITION+65536*GetScrollPos(Handle,SB_VERT),0); // Send to the other TMemo a message to set its vertical scroll as it is on this TMemo
     BusyUpdating:=False; // Set that the object is no more busy in our special action
end;

Espero que alguien pueda solucionar el problema de la barra de desplazamiento oculta y GetScrollPOS devolviendo Zero !!!

Encontré una solución ... Sé que es bastante complicado ... pero al menos es completamente funcional ...

En lugar de tratar de ocultar la barra de desplazamiento horizontal ... hago que se muestre fuera del área visible, por lo que no se puede ver por usuario ...

la parte difícil:

  • Ponga un tablel donde está el TMEMO y ponga el TMEMO dentro del tablel
  • Ocultar bordes de tablel, ponga Borderwith como 0, y todos los biseles a BVNONE / BKNONE
  • Configurar a TMEMO alinear a Altop, no al alclient, etc ...
  • manejan tanel.onResize para hacer que TMEMO.Height sea más grande que Tpanel.Height tanto como la altura de la barra de desplazamiento horizontal (en el momento en que uso un valor constante de 20 píxeles, pero me gustaría saber cómo obtener el valor real) < / li>

Eso es todo ... hecho !!! La barra de desplazamiento horizontal está fuera del área visible ... puede poner donde quiera el tablel, dale el tamaño que desee ... que el usuario de la barra de desplazamiento horizontal no será oculta, por lo que Getscrollpos funcionará correctamente. ... Tricky lo sé, pero completamente funcional.

Aquí está el código completo para archivar que:

En la sección de la interfaz, antes de su declaración de TFRE, por lo que su TFRE verá esta nueva clase TMEMO en lugar de una normal:

type
    TMemo=class(StdCtrls.TMemo) // Just to add things to TMemo class only for this unit
    private
       BusyUpdating:Boolean; // To avoid circular stack overflow
       SyncMemo:TMemo; // To remember the TMemo to be sync
       Old_WindowProc:TWndMethod; // To remember old handler
       procedure New_WindowProc(var Mensaje:TMessage); // The new handler
    public
       constructor Create(AOwner:TComponent);override; // The new constructor
       destructor Destroy;override; // The new destructor
    end;

en la sección de implementación en cualquier lugar que prefieras:

constructor TMemo.Create(AOwner:TComponent); // The new constructor
begin
     inherited Create(AOwner); // Call real constructor
     BusyUpdating:=False; // Initialize as not being in use, to let enter
     Old_WindowProc:=WindowProc; // Remember old handler
     WindowProc:=New_WindowProc; // Replace handler with new one
end;

destructor TMemo.Destroy; // The new destructor
begin
     WindowProc:=Old_WindowProc; // Restore the original handler
     inherited Destroy; // Call the real destructor
end;

procedure TMemo.New_WindowProc(var Mensaje:TMessage);
begin
     Old_WindowProc(Mensaje); // Call the real handle before doing anything
     if  (WM_PAINT<>Mensaje.Msg) // If not when need to be repainted to improve speed
       or
         BusyUpdating // To avoid circular stack overflow
       or
         (not Assigned(SyncMemo)) // If not yet set (see TForm1.FormCreate bwlow)
     then Exit; // Do no more and exit the procedure
     BusyUpdating:=True; // Set that object is busy in our special action
     SyncMemo.Perform(WM_HSCROLL,SB_THUMBPOSITION+65536*GetScrollPos(Handle,SB_HORZ),0); // Send to the other TMemo a message to set its horizontal scroll as it is on this TMemo
     BusyUpdating:=False; // Set that the object is no more busy in our special action
end;

también en la sección de implementación en cualquier lugar que prefiera:

procedure TForm1.FormCreate(Sender: TObject);
begin
     Memo1.SyncMemo:=Memo2; // Tell Memo1 what TMemo must sync (Memo2)
     Memo2.SyncMemo:=Memo1; // Tell Memo2 what TMemo must sync (Memo1)
end;

procedure TForm1.pnlMemo2Resize(Sender: TObject);
begin
     Memo2.Height:=pnlMemo2.Height+20; // Make height enough big to cause horizontal scroll bar be out of TPanel visible area, so it will not be seen by the user
end;

¡Thas es gente! Sé que es bastante complicado, pero completamente funcional.

Tenga en cuenta que he cambiado en new_windowproc el orden de evaluación de las condiciones o condiciones ... es solo mejorar la velocidad para todos los demás mensajes, así que retrasa la menor cantidad posible de todos los mensajes de tratamiento.

Espero que algún tiempo sabrá cómo reemplazar los 20 por la altura de la barra de desplazamiento horizontal real (calculada o lectura).

Gracias por GetSystemMetrics y SM_CYHSCROLL, pero no es suficiente...Sólo necesito 3 píxeles más...

Entonces solo uso: GetSystemMetrics(SM_CYHSCROLL)+3

Nota:Dos de esos píxeles podrían deberse a que tener un panel principal con BevelWidth con valor 1 pero tengo BevelInner y BevelOuter con valor bvNone puede que no;pero el píxel extra no sé por qué.

Muchas gracias.

Si lo prefieres, únelos en una publicación grande, pero creo que es mejor no mezclarlos.

En respuesta a "Sertac Akyuz" (perdón por hacerlo aquí, pero no sé cómo publicarlas junto a tu pregunta):

  • Pongo aquí las soluciones que encontré tal como las encontré...Mi intención era no usarlo como bloc de notas...Descubrí la solución apenas unos segundos antes de escribir las publicaciones.
  • Creo que es mejor ver publicaciones antiguas, en lugar de editarlas multiplicadas veces el mismo post...tampoco permitirá que otros sepan la solución exacta, también les permitirá saber cómo llegar a dicha solución.
  • Yo prefiero hacer las cosas de una manera como "enseñar a pescar, en lugar de dar el peces".
  • No abrí una nueva pregunta solo porque el título de esta es exactamente lo que estaba tratando de hacer.

Importante:Descubro que no se puede hacer una solución perfecta mediante la captura de mensajes porque hay un caso que provoca desplazamiento pero no hay mensaje. WM_VSCROLL, WM_HSCROLL (solo WM_PAINT)...está relacionado con la selección de texto con el mouse...Déjame explicarte cómo lo veo en acción...Simplemente comience cerca del final de la última línea visual y mueva el mouse un poco hacia abajo, luego detenga el movimiento del mouse y deje presionado el botón del mouse...sin hacer nada (el mouse no se mueve, no se pulsa ninguna tecla, no se pulsa ninguna tecla, no se cambia el botón del mouse, etc...) el TMemo se desplaza hacia abajo hasta llegar al final del texto...Lo mismo sucede con los desplazamientos horizontales cuando el mouse está cerca del extremo derecho de la línea visual y se mueve hacia la derecha...también lo mismo en direcciones opuestas...tales pergaminos no pasan por mensajes WM_VSCROLL WM_HSCROLL, solo WM_PAINT (al menos en mi computadora)...También sucede lo mismo en Grids.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top