Ver Mensaje Individual
  #27  
Antiguo 13-03-2013
Avatar de cesarsoftware
cesarsoftware cesarsoftware is offline
Miembro
 
Registrado: nov 2006
Posts: 241
Reputación: 20
cesarsoftware Va por buen camino
Gracias por responder ricardo, suponia que ese era el efecto de inherited, pero confrmado queda claro.

Al final con el movimiento conjunto de ventanas el tema esta solucionado y un poco mas afinado
en este video se ve una muestra del efecto con topes incluidos
http://www.youtube.com/watch?v=yHiEy...ature=youtu.be

Hago un resumen de lo necesario, o lo que es lo mismo, la receta para cocinarlo

Formulario Padre o principal:

1 manejador de mensaje del movimiento de la pantalla principal
Código Delphi [-]
  private
    // Mover objetos DCx
    procedure WMWindowPosChanging(var Message: TWMWindowPosChanging); message WM_WINDOWPOSCHANGING;
3 variables publicas
Código Delphi [-]
  public
    // Posiciones relativas a la pantalla principal de los objetos DCx
    PxArriba: word;
    PxAbajo: word;
    PxDcha: word;
En el OnCreate (por ejemplo) calcular los margenes
en mi caso tengo abajo una TStatusBar
Código Delphi [-]
  PxArriba := GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU) + GetSystemMetrics(SM_CYFRAME) - 1;
  PxAbajo := StatusBar.Height + GetSystemMetrics(SM_CYFRAME);
  PxDcha := GetSystemMetrics(SM_CXFRAME);

Al crear las ventanas hijas darle informacion sobre los limites para que no se pasen
Código Delphi [-]
  // Posiciones relativas a la pantalla principal
  DCx[i].PxArriba := FormRemoto.PxArriba;
  DCx[i].PxAbajo := FormRemoto.PxAbajo;
  DCx[i].PxDcha := FormRemoto.PxDcha;
  // posciones relativas respecto al padre (se guardan en una tabla)
  DCx[i].Left := StrToIntDef(SGmaquinas.Cells[4, i + 1], 1);
  DCx[i].Top := StrToIntDef(SGmaquinas.Cells[5, i + 1], 1);

El manejador que mueve las ventanas hijas cuando se mueve el padre
Código Delphi [-]
procedure TFormRemoto.WMWindowPosChanging(var Message: TWMWindowPosChanging);
var
  i, t: integer;
begin
  t := Length(DCx);
  if t = 0 then
    Exit;
  for i := 0 to t - 1 do
  begin
    if DCx[i] = nil then
      Continue;
    // DCx[i].Forma.Top es la nueva posicion de la ventana hija
    // DCx[i].Top es la posicion relativa de la ventana hija respento al padre, partiendo de 0,0
    DCx[i].Forma.Top := Self.Top + PxArriba + DCx[i].Top;
    DCx[i].Forma.Left := Self.Left + PxDcha + DCx[i].Left;
  end;
  inherited;
end;

Formulario hijo (semitrasparente con alphablendvalue)
unas variables publicas y los procedimientos de movimiento de raton
al final he deshechado los mensaje windows porque sale un movimiento "mas fino" de esta forma
Código Delphi [-]
  public // Variables de entrada publicas
    Forma: TForm;                 // Formulario contenedor
    FormularioPadre: TWinControl; // Parent
    PxArriba: word;               // SM_CYCAPTION + SM_CYMENU + SM_CYFRAME;
    PxAbajo: word;                // 19(StatuBar.Height) + SM_CYFRAME;
    PxDcha: word;                 // GetSystemMetrics(SM_CXFRAME);
    Left, Top: word;              // Posicion
    procedure LedOnMouseDown(Sender: TObject; Button: TMouseButton;
                             Shift: TShiftState; X, Y: Integer); // 1ª posicion
    procedure LedOnMouseMove(Sender: TObject; Shift: TShiftState;
                             X, Y: Integer); // mover panel
    procedure LedOnMouseUp(Sender: TObject; Button: TMouseButton;
                           Shift: TShiftState; X, Y: Integer); // nueva posicion

Crear los formularios hijos en tiempo de ejecucion
Código Delphi [-]
  Forma := TForm.CreateNew(FormularioPadre, 0); // CreateNew si no queremos usar un archivo .DFM
  Forma.Position := poDesigned;
  Forma.BorderStyle := bsNone;
  Forma.Left := FormularioPadre.Left + PxDcha + Left; // posicion relativa al inicio
  Forma.Top := FormularioPadre.Top + PxArriba + Top;
  if Icono = False then
  begin
    Forma.Width := 206;
    Forma.Height := 256;
  end
  else
  begin
    Forma.Width := 26;
    Forma.Height := 26;
  end;
  Forma.Color := clHotLight;
  Forma.Visible := Visible;
  Forma.AlphaBlend := True;
  Forma.AlphaBlendValue := 210;
  Forma.ShowHint := True;
  Forma.Hint := 'Left-Click y arrastre para mover';
  Forma.OnMouseDown := LedOnMouseDown;
  Forma.OnMouseMove := LedOnMouseMove;
  Forma.OnMouseUp := LedOnMouseUp;
...
crear los componentes vcl y asigarno a la forma y los evento si es necesario
  Lnumero := TLabel.Create(Forma);
  Lnumero.Parent := Forma;
  Lnumero.Top := LedOn.Top + 5;
  Lnumero.Left := LedOn.Left + 6;
  Lnumero.Height := 13;
  Lnumero.Width := 12;
  Lnumero.Transparent := True;
  Lnumero.Caption := IntToStr(Numero);
  Lnumero.ShowHint := True;
  Lnumero.Hint := LedOn.Hint;
  Lnumero.Visible := Icono;
  Lnumero.OnMouseDown := LedOnMouseDown;
  Lnumero.OnMouseMove := LedOnMouseMove;
  Lnumero.OnMouseUp := LedOnMouseUp;
...

y los manejadores de eventos
Código Delphi [-]
procedure TcapturadorDCx.LedOnMouseDown(Sender: TObject; Button: TMouseButton;
                                        Shift: TShiftState; X, Y: Integer);
begin
  // Capturar posicion inicial del ratón al comenzar a mover
  oldLeft := X;
  oldTop := Y;
  // Solo si es Shape LedOn
  if Sender is TForm then
    Exit;
  // Cambiar estado a icono o detalle
  if Button = mbRight then
  begin
    if Icono = True then
      SetIcono(False)
    else
      SetIcono(True);
    Exit;
  end;
  // comprobar si ha pulsado doble-click
  if ssDouble in Shift = False then
    Exit;
  // Encender o Apagar el capturador
  if DCx = nil then
    ActivaDCx // si no ha sido activado
  else
    if DCx.abierto = True then
      DesactivaDCx
    else
      if (DCx.conectando = False) and (Conectando = False) then
        ActivaDCx; // si las tarea DCx y el objeto TcapturadorDCx estan parados
end;

procedure TcapturadorDCx.LedOnMouseMove(Sender: TObject; Shift: TShiftState;
                                        X, Y: Integer);
var
  nX, nY: integer;
begin
  if ssLeft in Shift = False then
    Exit;
  // Controlar los limites
  // Izquierda
  if Forma.Left < (FormularioPadre.Left + PxDcha) then
  begin
    Forma.Left := FormularioPadre.Left + PxDcha;
    SetCursorPos(Forma.Left + X, Forma.Top + Y);
  end;
  // Derecha
  if (Forma.Left + Forma.Width) > (FormularioPadre.Left + FormularioPadre.Width - PxDcha) then
  begin
    Forma.Left := (FormularioPadre.Left + FormularioPadre.Width) - Forma.Width - PxDcha;
    SetCursorPos(Forma.Left + X, Forma.Top + Y);
  end;
  // Arriba
  if Forma.Top < (FormularioPadre.Top + PxArriba) then
  begin
    Forma.Top := FormularioPadre.Top + PxArriba;
    SetCursorPos(Forma.Left + X, Forma.Top + Y);
  end;
  // Abajo
  if (Forma.Top + Forma.Height) > (FormularioPadre.Top + FormularioPadre.Height - PxAbajo) then
  begin
    Forma.Top := (FormularioPadre.Top + FormularioPadre.Height) - Forma.Height - PxAbajo;
    SetCursorPos(Forma.Left + X, Forma.Top + Y);
  end;
  // Mover el objeto
  if X < oldLeft then
  begin
    nX := oldLeft - X;
    Forma.Left := Forma.Left - nX;
  end
  else
  begin
    nX := X - oldLeft;
    Forma.Left := Forma.Left + nX;
  end;
  if Y < oldTop then
  begin
    nY := oldTop - Y;
    Forma.Top := Forma.Top - nY;
  end
  else
  begin
    nY := Y - oldTop;
    Forma.Top := Forma.Top + nY;
  end;
end;

procedure TcapturadorDCx.LedOnMouseUp(Sender: TObject; Button: TMouseButton;
                                      Shift: TShiftState; X, Y: Integer);
begin
  Left := Forma.Left - (FormularioPadre.Left + PxDcha);
  Top := Forma.Top - (FormularioPadre.Top + PxArriba);
  Movido(Sender);
end;

procedure TcapturadorDCx.Movido(Sender: TObject);
begin
  // Sincronizar si tiene tarea asignada
  if Assigned(FOnMovido) then
    FOnMovido(Self);
end;

Ala, un pasito mas, gracias a todos.

Última edición por cesarsoftware fecha: 13-03-2013 a las 19:25:11.
Responder Con Cita