Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Scroll en DBGrid (https://www.clubdelphi.com/foros/showthread.php?t=78180)

marcial 26-03-2012 22:58:34

Scroll en DBGrid
 
Hola a todos:
Trabajo con Delphi5
Necesito hacer lo siguiente y no se si se puede:
Tengo un DBGrid que en pantalla NO saca (por espacio) todos los campos de una tabla. Entonces busco que cuando el ratón llegue a la última/primera columna del DBGrid haga un scroll horizontal automático hacia la derecha o la izquierda sacando el resto de las columnas de la tabla.
Gracias por vuestra ayuda.

Casimiro Notevi 26-03-2012 23:59:56

Hola, recuerda poner tus preguntas en los foros adecuados, este es "Conexión con bases de datos", y la pregunta no tiene mucho que ver con eso ;)


P.d.: Lo muevo a 'varios'

lmpadron 27-03-2012 00:28:54

deberías explicarte mejor porque no entiendo que es lo que quieres hacer !!! ;)

ecfisa 27-03-2012 00:33:58

Hola.

A ver si así hace mas o menos lo que buscas... :rolleyes:
Código Delphi [-]
   ...
   private
     procedure MMouseEvent(var Msg: TMsg; var Handled: Boolean);
   end;
...
implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := MMouseEvent;
end;

procedure TForm1.MMouseEvent(var Msg: TMsg; var Handled: Boolean);
var
  P: TPoint;
begin
  P:= ScreenToClient(Mouse.CursorPos);
  if PtInRect(DBGrid1.BoundsRect,P) then
  begin
    if P.X = DBGrid1.Left + GetSystemMetrics(SM_CXVSCROLL) then
      SendMessage(DBGrid1.Handle, WM_HSCROLL, SB_LINELEFT, 0);
    if P.X = DBGrid1.Left+DBGrid1.Width - GetSystemMetrics(SM_CXVSCROLL) then
      SendMessage(DBGrid1.Handle, WM_HSCROLL, SB_LINERIGHT, 0);
  end;
end;
...

Saludos.

ecfisa 27-03-2012 00:55:34

Hola.

Me quede pensando que agregando un detalle te puede servir para más de un TDBGrid en el mismo form:
Código Delphi [-]
  private
     procedure MMouseEvent(var Msg: TMsg; var Handled: Boolean);
  end;

....

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := MMouseEvent;
end;

procedure TForm1.MMouseEvent(var Msg: TMsg; var Handled: Boolean);
var
  P: TPoint;
  WControl: TWinControl;
  G: TDBGrid;
  i: Integer;
begin
  WControl:= FindVCLWindow(Mouse.CursorPos);
  if Assigned(WControl) and (WControl is TDBGrid) then
  begin
    G:= TDBGRid(WControl);
    P:= ScreenToClient(Mouse.CursorPos);
    if P.X = G.Left + GetSystemMetrics(SM_CXVSCROLL) then
      for i:= G.Columns.Count-1 downto G.SelectedIndex do
        SendMessage(G.Handle, WM_HSCROLL, SB_LINELEFT, 0);
    if P.X = G.Left + G.Width - GetSystemMetrics(SM_CXVSCROLL) then
      for i:= G.SelectedIndex to G.Columns.Count-1 do
        SendMessage(G.Handle, WM_HSCROLL, SB_LINERIGHT, 0);
  end
end;

Saludos.

marcial 27-03-2012 09:43:18

Ecfisa, muchas gracias por responder
Es "casi" perfecto, lo que pasa es que por ejemplo si una tabla tiene 15 campos y el DBGrid sólo visualiza 5, al llegar a las barras de scroll verticales se mueve automáticamente hasta el último campo de la tabla (sin visualizar los intermedios). Lo ideal sería que cuando el cursor se posicionara sobre la primera/última columna visible (sin llegar a las del scroll vertical-derecha o fijas-izquierda), se moviese una columna mas a la izquierda o derecha.
Eso si que sería perfecto.
Muchas gracias y perdón por el abuso.

ecfisa 27-03-2012 20:07:41

Hola marcial.

Entonces creo que el primer código que adjunté se hacercaba más a lo que buscabas.

El problema que veo es que comparando la coordenada X del mouse por la igualdad, te desplazará una columna cuando ingresa a la zona de desplazamiento pero también cuando sale. Esto se soluciona comparando por mayor y menor, pero cualquier movimiento que haga con el mouse una vez en el area de desplazamiento, por pequeño que sea, provocará el scroll. En resumidas cuentas: Es imposible de manejar para el usuario.
Así que la solución es detectar si el puntero del mouse está dentro de las zonas de desplazamiento o nó. Si ya se encuentra dentro no debe realizar el scroll.

Creo que el código que buscas sería:
Código Delphi [-]
procedure TForm1.MMouseEvent(var Msg: TMsg; var Handled: Boolean);
{$J+} 
const InZD: Boolean = False; 
{$J-}
var
  P: TPoint;
  WControl: TWinControl;
  G: TDBGrid;
  ZD: Integer;
begin
  WControl:= FindVCLWindow(Mouse.CursorPos);  // ¿ Esta sobre un TWinControl ?
  if Assigned(WControl) and (WControl is TDBGrid) then // ¿ Es tambien un TDBGrid ? 
  begin
    P:= ScreenToClient(Mouse.CursorPos);  // Obtener posición del mouse
    G:= TDBGRid(WControl);                     
    ZD:=  GetSystemMetrics(SM_CXVSCROLL);  // Ancho zona desplazamiento 
    if (P.X < G.Left + ZD) and not InZD then  // Ingresa zona desplazamiento izquierda    
      SendMessage(G.Handle, WM_HSCROLL, SB_LINELEFT, 0);
    if (P.X > G.Left + G.Width - ZD) and not InZD then  // Ingresa zona desplazamiento derecha
      SendMessage(G.Handle, WM_HSCROLL, SB_LINERIGHT, 0);
    InZD:= (P.X < G.Left + ZD) or (P.X > G.Left + G.Width - ZD); // ¿ En zona desplazamiento ?
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := MMouseEvent;
end;
De este modo el usuario tiene que volver a la zona de no desplazamiento y reingresar a la de desplazamiento para que se produzca el scroll (izquierdo o derecho).

Saludos.

marcial 28-03-2012 11:15:06

Solucionado. Muy bien explicado. Da gusto encontrar profesores así.
Muchas Gracias

marcial 28-03-2012 11:58:39

De hecho, y gracias a tu inestimable ayuda he mezclado tus códigos y he añadido algo hasta que ha quedado a mi gusto.
Reitero nuevamente mi agradecimiento porque sólo no podría haberlo hecho.

Código Delphi [-]
procedure TForm1.MMouseEvent(var Msg: TMsg; var Handled: Boolean);
{$J+}
const InZD: Boolean = False;
{$J-}
var
  P, PP: TPoint;
  WControl: TWinControl;
  G: TDBGrid;
  ZD, i: Integer;
begin
  WControl:= FindVCLWindow(Mouse.CursorPos);  // ¿ Esta sobre un TWinControl ?
  if Assigned(WControl) and (WControl is TDBGrid) then // ¿ Es tambien un TDBGrid ?
  begin
    P:= ScreenToClient(Mouse.CursorPos);  // Obtener posición del mouse
    G:= TDBGRid(WControl);
    ZD:=  GetSystemMetrics(SM_CXVSCROLL);  // Ancho zona desplazamiento
    if (P.X < G.Left + ZD) and not InZD then  // Ingresa zona desplazamiento izquierda
         for i:= G.Columns.Count-1 downto G.SelectedIndex do
                begin
                PP := ScreenToClient(Mouse.CursorPos);
                if pp.x <> p.x then exit;
                SendMessage(G.Handle, WM_HSCROLL, SB_LINELEFT, 0);
                sleep(100);
                end;
    if (P.X > G.Left + G.Width - ZD) and not InZD then  // Ingresa zona desplazamiento derecha
      for i:= G.SelectedIndex to G.Columns.Count-1 do  //Así no hay que ingresar en la zona de desplazamiento columna a columna
                begin
                PP := ScreenToClient(Mouse.CursorPos); 
                if pp.x <> p.x then exit;  //Chequea que la posición haya cambiado con respecto de la inicial para salir del buche

                SendMessage(G.Handle, WM_HSCROLL, SB_LINERIGHT, 0);
                sleep(100);  // Una pequeña pausa a gusto del consumidor para que el scroll no sea tan rápido
                end;
    InZD:= (P.X < G.Left + ZD) or (P.X > G.Left + G.Width - ZD); // ¿ En zona desplazamiento ?

  end;
end;

ecfisa 29-03-2012 00:25:13

Hola marcial.

Primero que nada, me alegro que el código te haya servido como base :).

Ahora que veo que deseas un scroll continuo con retraso de tiempo, te pongo otra alternativa más simple:
Código Delphi [-]
procedure TForm1.MMouseEvent(var Msg: TMsg; var Handled: Boolean);
var
  P: TPoint;
  WControl: TWinControl;
  G: TDBGrid;
  ZD: Integer;
begin
  WControl:= FindVCLWindow(Mouse.CursorPos);
  if Assigned(WControl) and (WControl is TDBGrid) then
  begin
    P:= ScreenToClient(Mouse.CursorPos);
    G:= TDBGRid(WControl);
    ZD:=  GetSystemMetrics(SM_CXVSCROLL);
    while (P.X >= G.Left) and (P.X <= G.Left+ZD) do
    begin
      P:= ScreenToClient(Mouse.CursorPos);
      SendMessage(G.Handle, WM_HSCROLL, SB_LINELEFT, 0);
      Sleep(250);
    end;
    while (P.X >= G.Left+G.Width-ZD) and (P.X <= G.Left+G.Width) do
    begin
      P:= ScreenToClient(Mouse.CursorPos);
      SendMessage(G.Handle, WM_HSCROLL, SB_LINERIGHT, 0);
      Sleep(250);
    end;
  end;
end;

Saludos.

marcial 30-03-2012 13:36:37

Muchas gracias. Como siempre, mejor que el mio.

ecfisa 30-03-2012 14:15:24

Cita:

Empezado por marcial (Mensaje 428887)
Muchas gracias. Como siempre, mejor que el mio.

Hola.

Yo no diría mejor... sólo un modo diferente que dá un código más simple.

Saludos.:)

lmpadron 30-03-2012 15:01:03

Saludos ecfisa, podría traducir este código a c usted o alguien mas? Seria magnífico !!!

ecfisa 30-03-2012 16:01:02

Cita:

Empezado por lmpadron (Mensaje 428892)
Saludos ecfisa, podría traducir este código a c usted o alguien mas? Seria magnífico !!!

Hola impadrón.

Código:

void __fastcall TForm1::MMouseEvent(TMsg &msg, bool &Handled){
TPoint tp;
int i;
  TWinControl *wc =  FindVCLWindow(Mouse->CursorPos);
  if (wc != NULL) {
    tp = Form1->ScreenToClient(Mouse->CursorPos);
    TDBGrid *g = static_cast<TDBGrid*> (wc);
    int ZD = GetSystemMetrics(SM_CXVSCROLL);
    while(tp.x >= g->Left && tp.x <= g->Left+ZD) {
      tp = Form1->ScreenToClient(Mouse->CursorPos);
      SendMessage(g->Handle, WM_HSCROLL, SB_LINELEFT, 0);
      Sleep(250);
    };
    while (tp.x >= g->Left+g->Width-ZD && tp.x <= g->Left+g->Width) {
      tp = Form1->ScreenToClient(Mouse->CursorPos);
      SendMessage(g->Handle, WM_HSCROLL, SB_LINERIGHT, 0);
      Sleep(250);
    };
  }
};

void __fastcall TForm1::FormCreate(TObject *Sender)
{
  Application->OnMessage = MMouseEvent;
}


Saludos. :)

PD: No me trates de usted. (la próxima vez que lo hagas te traduzco a Visual Basic :p:D )

marcial 30-03-2012 20:02:06

Hola de nuevo:
Parece que la felicidad nunca es completa.
Resulta que aplico el código y va perfectamente pero....cuando en el programa existe un componente Application Event para controlar la rueda del ratón con este código en el evento On Message:
Código Delphi [-]
 if Msg.message = WM_MOUSEWHEEL then
   begin
     Msg.message := WM_KEYDOWN;
     Msg.lParam := 0;
     if Msg.wParam > 0 then
       Msg.wParam := VK_UP
     else
       Msg.wParam := VK_DOWN;
     Handled := False;
   end;

Resulta que el maravilloso código de ecfisa no funciona.

¿Habría alguna manera de poder utilizar los dos a la vez?

marcial 30-03-2012 20:16:08

Vaya, si que se puede. Lo dejo por si a alguien le interesa:

En las Private Declarations
Código Delphi [-]
    { Private declarations }
    procedure DBGrid1PillaLaRueda(var Message: TMessage);
       procedure MMouseEvent(var Msg: TMsg; var Handled: Boolean); {SCROLL DEL DBGRID}


Despues de los Uses y antes de {SR *.DFM}
Código Delphi [-]
type
TomaInvento = class(TControl);


El el OnCreate de la Form
Código Delphi [-]
DBGrid1.WindowProc := DBGrid1PillaLaRueda;
   Application.OnMessage := MMouseEvent; {PARA EL SCROLL DEL DBGRID}

El procedure del Scroll Vertical
Código Delphi [-]
procedure TForm3.DBGrid1PillaLaRueda(var Message: TMessage);
 var
   Cuanto : short;
 begin

   if (Message.Msg = WM_MOUSEWHEEL) then begin
     Cuanto:=HIWORD(Message.WParam);
     Cuanto:=Cuanto div 120;
     DbGrid1.DataSource.DataSet.MoveBy(-Cuanto);

   end else TomaInvento(DBGrid1).WndProc(Message);
 end;

Y por último, después del procedure Vertical, el procedure de Ecfisa para el Scroll Horizontal

Así tenemos los Scroll Vertical y Horizontal sin usar las Barras de Desplazamiento

Muchas gracias


La franja horaria es GMT +2. Ahora son las 07:47:19.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi