Wednesday, 22 July 2009

Implementando automated linked objects con Delphi parte II

Como podéis comprobar la aplicación sigue adelante. En éste caso he mejorado todo el tema de las propiedades y su edición implementando un MVC (Modelo vista controlador) en el TBox. Ahora existe un TBoxView que se encarga de la visualización y de manejar los eventos de éste y mediante el TBoxManager crearemos el controlador para el TBox. Si observamos la nueva distribución de clases en nuestra aplicación tenemos:

Nuestro modelo Tbox es gestionado por el TboxManager y visualizado por el TBoxView. Encontraréis muchas referencias sobre éste patrón (MVC) en diversos libros y en las referencias que dejaré en éste artículo. El problema del diseño original es que al querer modificar las propiedades de la Tbox desde la pantalla, eso requiere que modifiques directamente este objeto y no debería de ser así. Para eso se crea un visualizador, que es el que gestiona la vista de la Tbox sobre la pantalla, y las modificaciones de estado se gestionan sobre el manager y así de vuelta al modelo. De esta manera tenemos separados la lógica de programa, la interfaz de usuario y la lógica de control. En mi caso el visor se implementa sobre un TImage, y se controlan los eventos sobre éste.

Aquí os dejo el siguiente build de la aplicación Thundax Geometric Links v1.0.0 build 20. Comprovaréis que la aplicación ha augmentado su tamaño (más de 5 Mb), eso es debido al componente RTTI que carga mucha parte de la VCL de DevExpress. Aquí os dejo unas imágenes para que podáis ver el resultado:

Aún queda mucho trabajo por hacer y muchos módulos por encajar pero ya llegará. Ya lo iréis viendo!.

Veamos un poco la codificación creada:

Creación de la aplicación MVC:




procedure TForm1.FormCreate(Sender: TObject);
begin
BoxP := TBoxPainter.Create(image1);
BoxL := TLinkPainter.Create(image1, SourceBox, TargetBox);
BoxW := TBoxView.Create(image1, SourceBox, TargetBox, BoxP, BoxM, BoxL);
BoxM := TBoxManager.Create(SourceBox, TargetBox);
BoxW.OffsetBox := offsetBox;
BoxW.SetInspector(cxRTTIInspector1);
BoxW.Draw();
end;




Modificación de la clase TBox:




TVertex = class(TPersistent)
private
Fx: integer;
Fy: integer;
procedure Setx(const Value: integer);
procedure Sety(const Value: integer);
published
property x: integer read Fx write Setx;
property y: integer read Fy write Sety;
public
constructor Create(x: integer; y: integer); overload;
constructor Create(point: TPoint); overload;
function getPoint(): TPoint;
procedure setPoint(point: TPoint);
end;

TBox = class(TPersistent)
private
FColor: TColor;
FSize: integer;
FOffset: integer;
FDirection: TDirection;
FlinkColor: TColor;
Flink: TVertex;
Fcenter: TVertex;
Fvertex: array[0..3] of TVertex;
FIntersection: TVertex;
FColisionColor: TColor;
FDrawColor: TColor;
function getIntersectionPoint(): TVertex;
procedure SetColor(const Value: TColor);
procedure SetOffset(const Value: integer);
procedure SetSize(const Value: integer);
procedure SetDirection(const Value: TDirection);
procedure SetlinkColor(const Value: TColor);
procedure SetcenterPoint(const Value: TVertex);
procedure SetlinkPoint(const Value: TVertex);
procedure Setvertex(Index: integer; value: TVertex);
function Getvertex(Index: integer): TVertex;
procedure SetLink(point: TVertex);
procedure SetColisionColor(const Value: TColor);
procedure SetDrawColor(const Value: TColor);
published
property vertex0: TVertex index 0 read Getvertex write Setvertex;
property vertex1: TVertex index 1 read Getvertex write Setvertex;
property vertex2: TVertex index 2 read Getvertex write Setvertex;
property vertex3: TVertex index 3 read Getvertex write Setvertex;
property center: TVertex read Fcenter write SetcenterPoint;
property link: TVertex read Flink write SetlinkPoint;
property Direction: TDirection read FDirection write SetDirection;
property intersection: TVertex read getIntersectionPoint;
property Offset: integer read FOffset write SetOffset;
property Size: integer read FSize write SetSize;
property Color: TColor read FColor write SetColor;
property linkColor: TColor read FlinkColor write SetlinkColor;
property ColisionColor: TColor read FColisionColor write SetColisionColor;
property DrawColor: TColor read FDrawColor write SetDrawColor;
public
function BetweenX(point: TPoint): boolean; overload;
function BetweenY(point: TPoint): boolean; overload;
function BetweenX(point: TVertex): boolean; overload;
function BetweenY(point: TVertex): boolean; overload;
procedure SetCentre(vertex: TPoint);
procedure SetLinkDirection(up, down, left, right: boolean);
function PointInside(point: TPoint): boolean;
constructor Create(centerPoint: TPoint; Size: integer; Offset: integer; Color: integer; linkColor: integer; ColisionColor: integer);
destructor Destroy(); override;
end;




Implementación de los eventos de Mouse en la vista:




procedure TBoxView.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if FTargetBox <> nil then
if FTargetBox.pointInside(point(x, y)) then
begin
activeDragTarget := true;
cxRTTIInspector1.InspectedObject := nil;
cxRTTIInspector1.InspectedObject := FTargetBox;
end;
if FSourceBox <> nil then
if FSourceBox.pointInside(point(x, y)) then
begin
activeDragSource := true;
cxRTTIInspector1.InspectedObject := nil;
cxRTTIInspector1.InspectedObject := FSourceBox;
end;
if (not activeDragSource) and (not activeDragTarget) then
cxRTTIInspector1.InspectedObject := nil;
end;

procedure TBoxView.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if activeDragTarget then
begin
FTargetBox.SetCentre(Point(x, y));
Draw();
end;
if activeDragSource then
begin
FSourceBox.SetCentre(Point(x, y));
Draw();
end;
end;

procedure TBoxView.Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
activeDragTarget := false;
activeDragSource := false;
end;



  • Enlaces de Interés:
Framework MVC para Delphi por EazySoft. Descarga directa del eMVC.
MVP por Joanna Carter. Descarga directa del MVPSource.
Java Model View Controller.

2 comments:

  1. Has utilizado algun framework de MVC de los que hay el link, o te has creado tu el framework?

    ReplyDelete
  2. Al principio pensaba en utilizar el eMVC desarrollado para Delphi, pero no me convencía. El eMVC utiliza un patrón Observer y para lo que yo quería hacer no funcionaba muy bien. Al final decidí crearme mi propio framework MVC estandarizado en la visualización en un Canvas, y su edición mediante RTTI.

    ReplyDelete