2011-08-19 18 views
7

Tengo un TScrollBox que tiene un RichEdit que es más grande que el scrollbox, por lo que ambas barras de desplazamiento laterales aparecen en el scrollbox. Entonces tengo una función DoTask que llama al RichEdit.SetFocus.¿Cómo puedo desactivar el comportamiento de deslizamiento en la vista de TScrollBox?

Cuando me desplazo hacia abajo hasta donde quiero ver parte del control de texto, y luego llamo al DoTask, ScrollBox se desplazará automáticamente a la parte superior de RichEdit. ¿Cómo puedo evitar eso?

+0

Sí, está claro. –

+1

no usar el cuadro de desplazamiento parece ser la solución obvia ya que tiene más barras de desplazamiento de las necesarias –

+0

@David: si el RichEdit es el único componente en el scrollbox, estoy de acuerdo. Por supuesto que no sabemos si es así. Poner un único componente que tenga sus propias barras de desplazamiento en un scrollbox sería un poco ... extraño, de hecho. –

Respuesta

6

Como quiera, he aquí algunas sugerencias:

  • Override SetFocusedControl en la forma:

    function TForm1.SetFocusedControl(Control: TWinControl): Boolean; 
    begin 
        if Control = RichEdit then 
        Result := True 
        else 
        Result := inherited SetFocusedControl(Control); 
    end; 
    

    O:

    type 
        TCustomMemoAccess = class(TCustomMemo); 
    
    function TForm1.SetFocusedControl(Control: TWinControl): Boolean; 
    var 
        Memo: TCustomMemoAccess; 
        Scroller: TScrollingWinControl; 
        Pt: TPoint; 
    begin 
        Result := inherited SetFocusedControl(Control); 
        if (Control is TCustomMemo) and (Control.Parent <> nil) and 
        (Control.Parent is TScrollingWinControl) then 
        begin 
        Memo := TCustomMemoAccess(Control); 
        Scroller := TScrollingWinControl(Memo.Parent); 
        SendMessage(Memo.Handle, EM_POSFROMCHAR, Integer(@Pt), Memo.SelStart); 
        Scroller.VertScrollBar.Position := Scroller.VertScrollBar.Position + 
         Memo.Top + Pt.Y; 
        end; 
    end; 
    
  • Interpose TScrollBox:

    type 
        TScrollBox = class(Forms.TScrollBox) 
        protected 
        procedure AutoScrollInView(AControl: TControl); override; 
        end; 
    
    procedure TScrollBox.AutoScrollInView(AControl: TControl); 
    begin 
        if not (AControl is TCustomMemo) then 
        inherited AutoScrollInView(AControl); 
    end; 
    

    O:

    procedure TScrollBox.AutoScrollInView(AControl: TControl); 
    begin 
        if (AControl.Top > VertScrollBar.Position + ClientHeight) xor 
         (AControl.Top + AControl.Height < VertScrollBar.Position) then 
        inherited AutoScrollInView(AControl); 
    end; 
    

o usar ninguna combinación creativa de todo lo anterior. Cómo y cuándo te gustaría que se desplazara solo tú lo sabes.

+0

Supongo que un ayudante de clase para TScrollBox, en lugar de un intercalador, también haría el truco. No puedo verificar eso, sin embargo. –

+1

No creo que eso funcione, @Rudy. No puede anular los métodos virtuales con ayudantes de clase. El sitio de llamada original del método no sabe que existe la clase auxiliar, por lo que continuará llamando al método original. –

+0

@Rob: tienes razón. El sitio de llamada original no usará el método de ayuda. –

2

la solución más simple sería

var a, b : Integer; 
begin 
    a := ScrollBox1.VertScrollBar.Position; 
    b := ScrollBox1.HorzScrollBar.Position; 
    richEdit1.SetFocus; 
    ScrollBox1.VertScrollBar.Position:=a ; 
    ScrollBox1.HorzScrollBar.Position:=b ; 
end; 
1

Sin hackear VCL/derivar componentes personalizados solo hay una solución: TForm.SetFocusedControl anula + restablece las posiciones de las barras de desplazamiento como se dijo anteriormente. Una cosa que agregué es deshabilitar/habilitar ventana redibujar para evitar feos saltos. Aquí está mi último fragmento:

sbContainer es TScrollBox y NoScrCtrl es un control que se coloca en su interior y se enfoca, pero no queremos que se despliegue en la vista.

function TForm1.SetFocusedControl(Control: TWinControl): Boolean; 
var hpos, vpos: integer; 
begin 
    if Control = NoScrCtrl then 
    begin 
    sbContainer.Perform(WM_SETREDRAW, WPARAM(False), 0); 
    hpos := sbContainer.HorzScrollBar.Position; 
    vpos := sbContainer.VertScrollBar.Position; 
    Result := inherited SetFocusedControl(Control); 
    sbContainer.HorzScrollBar.Position := hpos; 
    sbContainer.VertScrollBar.Position := vpos; 
    sbContainer.Perform(WM_SETREDRAW, WPARAM(True), 0); 
    sbContainer.Refresh; 
    end 
    else 
    Result := inherited SetFocusedControl(Control); 
end; 
Cuestiones relacionadas