Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 21-02-2008
Jose_Pérez Jose_Pérez is offline
Miembro
 
Registrado: may 2003
Posts: 156
Poder: 22
Jose_Pérez Va por buen camino
Componentes magnéticos.

Hola a tod@s:

He conseguido hacer dos componentes (de tipos diferentes) "magnetizados", de forma que cuando muevo (arrastrar y soltar) cualquiera de ellos en tiempo de diseño, se mueve su correspondiente compañero a la posición deseada.

Para hacerlo he capturado el mensaje WM_MOVE.

El problema está cuando selecciono los dos componentos y los muevo a la vez. Entonces se dispara dos veces el método de captura del mensaje WM_MOVE: cuando es movido por su compañero, y su propio evento WM_MOVE. Al llamarse dos veces el evento, el efecto de los cálculos hacen que los componentes se situen en un lugar diferentes a donde los solté.

Sé que en el apartado de ejemplos había algo parecido realizado con Forms, aunque no sé si resuelve el problema de mover los dos a la vez. En cualquier caso, parece ser que ha cambiado el diseño de la web, y no lo consigo encontrar.

¿Alguien tiene esto resuelto?

Recuerden que todo esto es en tiempo de diseño.

Saludos y gracias.

Última edición por Jose_Pérez fecha: 21-02-2008 a las 16:08:27.
Responder Con Cita
  #2  
Antiguo 22-02-2008
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Normalmente el componente magnético tiene una propiedad que indica el control al que se encuentra adherido, en uno de ellos podrías tener una variable "moving" a modo de bandera, para detener uno de los dos.

Quizás te interese más el mensaje wm_poschanging (dicho de memoria)

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #3  
Antiguo 26-02-2008
Jose_Pérez Jose_Pérez is offline
Miembro
 
Registrado: may 2003
Posts: 156
Poder: 22
Jose_Pérez Va por buen camino
Gracias por tu respuesta Lepe. Cuando tenga tiempo lo probaré.

Un apunte de entrada: hay que tener en cuenta que TComonenteA mueve a TComponeteB y viceversa.
Responder Con Cita
  #4  
Antiguo 04-03-2008
Jose_Pérez Jose_Pérez is offline
Miembro
 
Registrado: may 2003
Posts: 156
Poder: 22
Jose_Pérez Va por buen camino
Hola de nuevo:

Después de darles muchas vueltas finalmente he conseguido resolver el problema. Voy a intentar explicar la solución lo mejor que pueda, porque la verdad es que hay que saber primero como se comporta el mensaje WM_MOVE para comprender la solución; finalmente he decidido capturar este mensaje y no WM_WINDOWPOSCHANGING propuesto por Lepe, ya que pensaba (sin haberlo probado a fondo) que a efectos prácticos era lo mismo uno que otro.

El problema estaba en que cada componente (TComponenteA y TComponenteB) respondían a su correspondiente mensaje WM_MOVE sin tener en cuenta la respuesta del otro. De ese modo cuando, en tiempo de diseño, seleccionaba y arrastraba los dos componente a la vez se liaban los cálculos.

Para comprobar el orden de llamada incluí varios ShowMessage en el código. Así pude comprobar, para mi sorpresa, que el modo en que se sucedían los mensajes WM_MOVE no era el que yo esperaba. Este es el orden (recuerden siempre que estamos hablando de tiempo de diseño y que estamos arrastrando los dos componentes a la vez):

1.- Se ejecuta la respuesta al mensaje WM_MOVE en TComponenteA. Aquí se modifican las propiedades Left y Top de TComponenteB.

2.- Primera sorpresa: se ejecuta dos veces la respuesta al mensaje WM_MOVE en TComponenteB: uno para Left (desplazamiento horizontal) y otro para Top (desplazamiento vertical).

3.- Segunda sorpresa: Se ejecuta una tercera respuesta al mensaje WM_MOVE en TComponenteB, que correspondería al momento en que se suelta el componente en el form. Para empeorar las cosas, en este momento el propio Delphi suma (o resta) las propiedades Top y Left del componente según el desplazamiento.

Vamos, un lio.

El principal problema era saber si el evento correspondía al punto 2 o al 3, sin necesidad de que los componentes se comunicaran a través de eventos o propiedades. Al final utilicé la función GetTickCount, del API, para medir el tiempo en milésimas de segundo entre una llamada y otra. ¡Ojo, hay que calcular un tiempo para Left y otro para Top, porque no siempre el desplazamiento es en diagonal! Tras hacer pruebas, vi que la diferencia de tiempo entre el punto 2 y 3 era 0.

Y este es el resultado...

Código Delphi [-]
  TComponenteA = class(TPadre)
  private
    FTop: Integer;
    FLeft: Integer;
    FTickCountTop: Cardinal;
    FTickCountLeft: Cardinal;
    procedure WMMove(var Msg: TMessage); message WM_MOVE;
    function GetComponenteB: TComponent;
  protected
    { Protected declarations }
  public
    Constructor Create(AOwner: TComponent); Override;
  published
    {Published declarations}
  end;

Constructor TComponenteA.Create(AOwner: TComponent);
Begin

  Inherited Create(AOwner);

  FTop:=Top;
  FLeft:=Left;

  FTickCountTop:=GetTickCount;
  FTickCountLeft:=FTickCountTop;

End;

procedure TComponenteA.WMMove(var Msg: TMessage);
var
  MoveTickCountTop: Cardinal;
  MoveTickCountLeft: Cardinal;
  DiferenciaTickCount: Cardinal;
begin

  inherited;

  If GetComponenteB=Nil Then
     begin
     FTop:=Top;
     FLeft:=Left;
     exit;
     end;

  If (FTop<>Top) Then
     begin

     MoveTickCountTop:=GetTickCount;
     DiferenciaTickCount:=MoveTickCountTop-FTickCountTop;
     FTickCountTop:=MoveTickCountTop;

     If DiferenciaTickCount=0 Then Top:=FTop;

     (GetComponenteB As TComponenteB).Top:=Top;

     end;

  If (FLeft<>Left) Then
     begin

     MoveTickCountLeft:=GetTickCount;
     DiferenciaTickCount:=MoveTickCountLeft-FTickCountLeft;
     FTickCountLeft:=MoveTickCountLeft;

     If DiferenciaTickCount=0 Then Left:=FLeft;

     (GetComponenteB As TComponenteB).Left:=Left+((GetComponenteB As TComponenteB).Width-1);

     end;

  FTop:=Top;
  FLeft:=Left;

end;

Function TComponenteA.GetComponenteB: TComponent;
var
  Padre: TWinControl;
begin

  Padre:=Parent;
  While Not (Padre is TForm) Do
        Padre:=Padre.Parent;

  // FNombreComponenteB sería un string con el nombre del componente.
  // En este ejemplo no está dfeclarado. El resto se los dejo a ustedes  

  If Padre.FindComponent(FNombreComponenteB)<>Nil Then
     Result:=Padre.FindComponent(FNombreComponenteB)
     else
     Result:=Nil;

end;

Última edición por Jose_Pérez fecha: 17-03-2008 a las 12:33:30.
Responder Con Cita
  #5  
Antiguo 04-03-2008
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Ahora que has explicado un poco más el tema, se vé las cosas de otra forma .

¿no puedes usar SetBounds en lugar de Left y Top? Ahí solo se produce el mensaje wm_windowposchanged:
Código Delphi [-]

procedure TControl.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
  if CheckNewSize(AWidth, AHeight) and
    ((ALeft <> FLeft) or (ATop <> FTop) or
    (AWidth <> FWidth) or (AHeight <> FHeight)) then
  begin
    InvalidateControl(Visible, False);
    FLeft := ALeft;
    FTop := ATop;
    FWidth := AWidth;
    FHeight := AHeight;
    UpdateAnchorRules;
    UpdateExplicitBounds;
    Invalidate;
    Perform(WM_WINDOWPOSCHANGED, 0, 0);
    RequestAlign;
    if not (csLoading in ComponentState) then Resize;
  end;
end;

la "Segunda sorpresa" puede ser por tener activada la opción "Align To Grid" en las opciones de Delphi.

Lo que no queda claro, es el por qué no quieres tener enlazados ambos componentes con propiedades, es lo que se suele hacer como norma. Fíjate en el TDatasource que tiene una propiedad Dataset de forma pública:
Código Delphi [-]
published
  property AdosadoA :TControl read Fcontrol write FControl;
En tiempo de diseño, eliges en el inspector de objetos el control al que se desea adosar. Esto tiene varias ventajas:

- Puedes acceder de un control a otro para modificar sus propiedades, sin tener que buscarlo (Findcomponent es un bucle que puede tener 60 o 100 iteraciones por los campos persistentes, paneles, etc).
- Usando Notification puedes poner a nil esa propiedad cuando el usuario elimina el "componente B" de la ventana (en tiempo de diseño, claro)
Código Delphi [-]
procedure TComponentA.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (AComponent = ComponentB) and 
   (Operation = opRemove) then
  begin
     ComponentB := nil ; // propiedad publica
  end;
end;
Esto ya es un poco más lioso, pero bueno.

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #6  
Antiguo 05-03-2008
Jose_Pérez Jose_Pérez is offline
Miembro
 
Registrado: may 2003
Posts: 156
Poder: 22
Jose_Pérez Va por buen camino
Hola Lepe:

No he tenido tiempo de probar nada de lo que me dices, pero probablemente sea otra forma de hacerlo.

Cita:
Empezado por Lepe Ver Mensaje
la "Segunda sorpresa" puede ser por tener activada la opción "Align To Grid" en las opciones de Delphi.
No creo que sea ese el motivo. En cualquier caso habrá que tenerlo en cuenta.

Por cierto, probando el componente he visto que en el evento Create hay que inicializar las variables FTickCountTop y FTickCountLeft a 0, de lo contrario, al crearse el componente toma los valores 0 para Top y Left en la respuesta al mensaje WM_MOVE.

Código Delphi [-]
Constructor TComponenteA.Create(AOwner: TComponent);
Begin

  Inherited Create(AOwner);

  FTop:=Top;
  FLeft:=Left;

  FTickCountTop:=0;
  FTickCountLeft:=0;

End;

Última edición por Jose_Pérez fecha: 05-03-2008 a las 15:14:56.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Componentes Petolansa Varios 5 23-08-2007 17:34:22
Componentes MDO Tauro78 Firebird e Interbase 1 21-01-2007 04:19:32
componentes xp supermilloriver OOP 2 28-07-2005 17:50:52
Componentes USB HARD-SOFT Varios 0 26-08-2004 13:00:05
Formulario magneticos ElCherchu Varios 2 13-05-2003 16:14:45


La franja horaria es GMT +2. Ahora son las 17:31:42.


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
Copyright 1996-2007 Club Delphi