2010-07-21 22 views
5

Estoy tratando de sincronizar el desplazamiento de dos componentes TDBGrid en una aplicación de formularios VCL, tengo dificultades para interceptar el WndProc de cada componente de cuadrícula sin algunos problemas de pila. He intentado enviar mensajes WM_VSCROLL bajo eventos de desplazamiento, pero esto todavía resulta en una operación incorrecta. Tiene que funcionar para hacer clic en la barra de desplazamiento, así como para resaltar una celda, o un botón para subir o bajar el mouse. La idea es tener dos cuadrículas una junto a la otra mostrando una especie de diálogo de coincidencia.Desplazamiento sincronizado Componentes Delphi

Probamos

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; 

El primero es solo una solución temporal, el segundo da como resultado lecturas de memoria no válidas y el tercero da como resultado un desbordamiento de pila. Entonces, ninguna de estas soluciones parece funcionar para mí. ¡Me encantaría obtener información sobre cómo lograr esta tarea! Gracias por adelantado.

ACTUALIZACIÓN: 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 para la solución. Cuando se integran en una aplicación de formularios de VCL utilizando cuadrículas, se mimetizarán mutuamente al desplazarse y resaltarán el registro seleccionado.

Respuesta

3

Probablemente esté implementando la anulación de mensaje para ambas cuadrículas. GridX desplaza GridY, que a su vez desplaza a GridX, que a su vez ... SO. Puede proteger el código de desplazamiento superficial rodeando el bloque con 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 similar para GridY. Por cierto, no necesitas el SetScrollPos.


edición:

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; 
+0

Obtengo errores de desbordamiento de pila cuando trato de usar 'WndProc heredado (Msg)' Además, cuando tengo el código como lo he mostrado obtengo lecturas inválidas de memoria y otros errores de tiempo de ejecución. ¿No estoy seguro de si esta es la única forma de llevar a cabo la tarea? – wfoster

+0

¿Qué 'WndProc heredado' ?, le dio una parte del código que reemplaza al' WindowProc' de una grilla. ¿Dónde anulas el 'WndProc'? Por favor edite la pregunta para mostrar el código relevante. –

+0

Mis disculpas, véanse las ediciones – wfoster

3

Tengo una solución de trabajo parcial, pero ahora lleno (al menos para dos TMemo) ...

me refiero parcial, ya que sólo escuchar los cambios en uno TMemo pero no en el otro ...

quiero decir completo de trabajo, ya que no depende de lo que se hace ...

es tan simple como poner un mismo horizonte tal desplazamiento en un Memo tal como está en el otro ...

No tiene nada que ver con los mensajes, pero como estaba tratando de obtener una solución de trabajo atrapando los mensajes WM_HSCROLL, etc. dejé el código porque funciona ... intentaré mejorarlo más tarde ... por ejemplo, capturando solo WM_PAINT, o de otras maneras ... pero por ahora, lo puse como lo tengo, ya que funciona ... y lo hice no encontrar en ninguna parte algo mejor ...

Este es 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 de desplazamiento para cambiar ...

Notas:

  • Sé que es horrible trampa todos los mensajes, pero al menos funciona ...
  • este es mi primer intento exitoso de tener dos TMemos con sincronizado horizontal scrollb ar ...
  • Entonces, si alguien puede mejorarlo un poco (no atrapar todos los mensajes) por favor hágalo y publíquelo.
  • que sólo tiene Memo1 estar en sincronía horizontal con Memo2 bar, pero no Memo2 para estar en sintonía con Memo1
  • Pulse las teclas arriba, abajo, izquierda, derecha, la rueda del ratón, etc ... lo que usted quiere, pero en Memo2 a verlo en acción

voy a tratar de mejorarlo: cuando se hace algo en Memo2, Memo1 desplazamiento todavía estar en sincronización ...

creo que puede funcionar para cualquier control que allmost tiene una ScrollBar, no solo TMemo ...

2

como le dije ...

Aquí es una solución mejor (no uno final) en términos de eficiencia, código limpio y bidireccional ... cambiando en cualquiera afecta a la otra ...

Por favor, lea los comentarios sobre el código para entender qué significa cada oración ... es bastante complicado ... pero la idea principal es la misma que antes ... configure la otra barra de desplazamiento horizontal TMemo tal como está en el TMemo donde el usuario está actuando ... no importa lo que haga el usuario, mueva el mouse y seleccione texto, presione las teclas izquierda, derecha, inicio, fin, use la rueda horizontal del mouse (no todas tienen una), arrastre la barra de sroll, presione en cualquier parte del barra de desplazamiento horizontal, etc ...

La ma en la idea es ... el objeto necesita ser re-pintado, entonces ponga el otro objeto barra de desplazamiento horizontal idéntica a esta ...

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 declarada.

Añadir esto a la interfaz sección, antes de que su declaración TForm, por lo que su TForm verá esta nueva clase TMemo en lugar de uno 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; 

La siguiente parte es la implementación de las declaraciones anteriores de que la nueva clase TMemo .

añadir esto a la sección de aplicación en cualquier lugar que prefieres:

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, se dicen unos TMemo lo que es el otro de notas que se tiene que estar en sincronización.

En su sección de implementación, para el Form1 Crear evento de añadir 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 añadido miembro de SyncMemo a nuestra nueva clase especial TMemo, que estaba allí sólo para esto, dicen unos a otros lo uno es el otro.

Ahora un poco de configuración tanto para TMemo jsut a dejar este trabajo a la perfección:

  • Deje que ambas barras de desplazamiento TMemo sean visibles
  • Vamos WordWrap falsa en tanto TMemo
  • Poner una gran cantidad de texto (misma para ambos), las largas colas y una gran cantidad de líneas

Ejecutar y ver cómo las dos barras de desplazamiento horizontal son Allways de sincronización ...

  • Si se mueve una barra de desplazamiento horizontal, la otra barra de desplazamiento horizontal movimientos ...
  • Si vas en el texto a derecha o izquierda, línea de salida o final de línea, etc ..., no importa dónde está SelStart en el otro ... el desplazamiento de texto horizontal está sincronizado.

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

  • Las barras de desplazamiento horizontal (uno en mi caso) no se puede esconder ... ya que si uno está oculto, al llamar GetScrollPos devuelve cero, por lo que no está sincronizado.

Si alguien sabe cómo emular oculto o hacer GetScrollPos de no volver a cero, por favor, comentario, se lo único que tengo que corregir para la versión final.

Notas:

  • Obviamente, el mismo se puede hacer con la barra de desplazamiento vertical ... sólo cambiar WM_HSCROLL a WM_VSCROLL y SB_HORZ a SB_VERT
  • Obviamente, el mismo se puede hacer de dos cosas al mismo tiempo. .. simplemente copiar la línea SyncMemo.Perform dos veces y en una WM_HSCROLL let y SB_HORZ y en el otro deje WM_VSCROLL y SB_VERT

He aquí un ejemplo de procedimiento para la sincronización New_WindowProc ambas barras de desplazamiento al mismo tiempo, ma Ybe para la gente perezosa, tal vez por la gente como copia & 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 oculta una barra de desplazamiento y GetScrollPos devolver cero !!!

2

he encontrado una solución ... Sé que es bastante complicado ... pero por lo menos es completamente funcional ...

En lugar de tratar de ocultar la barra de desplazamiento horizontal ... Me lo hacen a se muestra fuera del área visible, por lo que no puede ser visto por el usuario ...

La parte difícil:

  • Ponga un TPanel donde el TMemo es y poner el TMemo dentro del TPanel
  • Ocultar fronteras TPanel, puesto BorderWith como 0, y todos bisel a bvNone/bkNone
  • Configure TMemo Align para alTop, no para alClient, etc ...
  • Maneje TPanel.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 use un valor constante de 20 píxeles, pero me gustaría saber cómo obtener el valor real)

eso es que ... hace !!! La barra de desplazamiento horizontal está fuera del área visible ... puedes colocar el TPanel donde quieras, darle el tamaño que desees ... esa barra de desplazamiento horizontal no será vista por el usuario y no estará oculta, por lo que GetScrollPos funcionará correctamente ... complicado, lo sé, pero completamente funcional.

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

En la sección de interfaz, antes de que su declaración TForm, por lo que su TForm verá esta nueva clase TMemo en lugar de uno 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 sección de implementación en cualquier lugar que prefieres:

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 sección de implementación en cualquier lugar que prefieres:

gente de TI
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; 

de THAS! Sé que es bastante complicado, pero completamente funcional.

Tenga en cuenta que he cambiado en New_WindowProc el orden de evaluar las condiciones de O ... es solo para mejorar la velocidad de todos los demás mensajes, por lo que retrasar el tratamiento de mensajes lo menos posible.

esperanza en algún momento voy a saber cómo sustituir tales 20 por el real (calculada o leido) TMemo altura de barra de desplazamiento horizontal.

+0

Puede obtener la altura predeterminada de la barra de desplazamiento con 'GetSystemMetrics', usar' SM_CYHSCROLL' como * nIndex * .. En lugar de utilizar esta pregunta como su cuaderno de tapa para su problema, ¿por qué no hace una nueva pregunta? –

1

Gracias por GetSystemMetrics y SM_CYHSCROLL, pero no es sólo lo suficientemente ... sólo tiene 3 píxeles más ...

Así que yo sólo uso: GetSystemMetrics(SM_CYHSCROLL)+3

Nota: Dos de esos píxeles podría ser porque teniendo panel de padre con BevelWidth con valor 1 pero tengo BevelInner y BevelOuter con valor bvNone por lo que no pueden; pero el pixel adicional no sé por qué.

Muchas gracias.

Si lo prefiere, simplemente se unen a ellos en un puesto grande, pero creo que es mejor no mezclarlos.

En respuesta a "Sertac Akyuz" (lo siento a hacer aquí, pero yo no sé cómo publicar ellos junto a su pregunta):

  • pongo aquí las soluciones que encontré que he encontrado ... mi intención era de no usarlo como un cuaderno de notas ...Descubrí la solución segundos antes de escribir las publicaciones
  • Creo que es mejor ver las publicaciones antiguas, en lugar de editar multiplicar veces la misma publicación ... tampoco permitirá que otros sepan la solución exacta, también lo hará hazles saber cómo llegar a esa solución.
  • Prefiero hacer las cosas de una manera como "enseñar a pescar, en lugar de dar el pescado ".
  • no he abierto una nueva pregunta sólo por el título de éste es sólo exacto lo que yo estaba tratando de hacer

Importante: descubro que una solución perfecta no se puede hacer mediante un mensaje de captura porque hay un caso que causa desplazamiento pero ningún 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 ... Solo comienza cerca del final del último 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 hay keyup, no keydown, no cambia el botón del mouse, etc.) el TMemo dow de desplazamiento n hasta que llega al final del texto ... sucede lo mismo con las volutas 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 desplazamientos no a través de mensajes WM_VSCROLLWM_HSCROLL, solo WM_PAINT (al menos en mi computadora) ... también sucede lo mismo en Grids.

Cuestiones relacionadas