![]() |
![]() |
| Paypal | FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
|||||||
| Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
![]() |
|
|
Herramientas | Buscar en Tema | Desplegado |
|
#1
|
|||
|
|||
|
Como crear clases correctamente?
Bueno..
No tengo mucha idea de usar clases y he intentado crear algunas. El problema es que cuando asigno varias variables de la misma clase si creo y destruyo una de las dos variables me cargo los datos de la otra. No se porque. Adjunto la unidad que he creado a ver si algun sabio de los de aqui me ayuda a ver que es lo que esta mal. Y como hacerlo mejor. Un saludo.. Código:
unit pathmovil;
interface
uses Windows,graphics,extctrls,controls,math;
CONST
MAXSEQ=512;
MAXTRAD=2;
MAXREC=50;
PIXELSMETRO=200; // un metro recorrido por el robot equivale en pantalla a 200 pixels
NULLREC=$FFFF;
type
TTipoMov=(mvStop,mvAdelante,mvAtras,mvDerecha,mvIzquierda,mvNoreste,mvsureste,mvsuroeste,mvnoroeste);
TTradMovil=record
Movi: TTipoMov;
TiempoMov : TTime;
end;
Tpathmovil = record
Origenx, Origeny, Destinox, Destinoy : Integer;
Seleccion: integer;
TiempoPath: cardinal;
CteMetro, CteGiro: Cardinal;
Tradmov: Array [1..MAXTRAD] of TTradMovil;
end;
TSecuencia =class
public
Numero : integer;
Nombre :String;
Descripcion: String;
Tiempo: cardinal;
Color: TColor;
Recorr : TpathMovil;
constructor Create;
destructor Destroy;
function Add(var MIrec:Tpathmovil):integer;
function Delete(Indice:integer):integer;
procedure SetOrigen(x,y:integer);
procedure SetDestino(xx,yy:integer);
procedure SetOriDest(x,y,xx,yy:integer);
procedure SetCtes(Ct,Cg: cardinal);
function GetDeltaX:integer;
function GetDeltay:integer;
function GetModulo:double;
// function GetAngulo:double;
function GetTimems:double;
function GetLonmetros:double;
procedure SetColor(ClColor:TColor);
procedure DibujarRecorrido(x,y:integer;Canvas:Tcanvas);
function Rotate2D(x,y:integer; alpha:double): TPoint;
private
Count:integer;
end;
implementation
constructor Tsecuencia.Create;
begin
inherited;
//Count:=0;
Numero:=0;
Nombre:='';
Descripcion:='';
Tiempo:=0;
SetOriDest(NULLREC,NULLREC,NULLREC,NULLREC);
//Metodo create de recorrido
end;
destructor Tsecuencia.Destroy;
begin
inherited;
end;
procedure TSecuencia.SetColor(ClColor:TColor);
begin
Color:=clColor;
end;
function Tsecuencia.Add(var MIrec:Tpathmovil):integer;
begin
(* inc(count);
if Count<=MAXREC then
begin
// if Recorr[Count]=nil then
// Recorr[Count]:=Tpathmovil.Create;
*)
Recorr:=Mirec;
(* result:=Count;
end
else result:=-1 *)
end;
function Tsecuencia.Delete(Indice:integer):integer;
begin
if (indice>0) or (indice<=Count) then
begin
// hacer rutina de borrado de elemento
end
else result:=-1;
end;
function Tsecuencia.GetModulo:double;
var
dx: Double;
dy: Double;
begin
dx := GetDeltax;
dy := GetDeltay;
Result := Sqrt(dx * dx + dy * dy);
end;
function TSecuencia.GetTimems:double;
begin
result:=(Getmodulo*Recorr.CteMetro)/PIXELSMETRO // cte tiempo para 9 Voltios 1metro lo recorre en 4000 msegundos
end;
function TSecuencia.GetLonmetros:double;
begin
result:=(Getmodulo/PIXELSMETRO) // 1 metro 200 pixels
end;
procedure Tsecuencia.SetOrigen(x,y:integer);
begin
Recorr.Origenx:=x;
Recorr.Origeny:=y;
end;
procedure Tsecuencia.SetDestino(xx,yy:integer);
begin
Recorr.Destinox:=xx;
Recorr.Destinoy:=yy;
end;
procedure Tsecuencia.SetOriDest(x,y,xx,yy:integer);
begin
Recorr.Origenx:=x;
Recorr.Origeny:=y;
Recorr.Destinox:=xx;
Recorr.Destinoy:=yy;
end;
procedure TSecuencia.SetCtes(Ct,Cg: cardinal);
begin
Recorr.CteMetro:=Ct;
Recorr.CteGiro:=Cg;
end;
function TSecuencia.GetDeltaX:integer;
begin
result:=(Recorr.Destinox-Recorr.Origenx);
end;
function TSecuencia.GetDeltay:integer;
begin
result:=(Recorr.Destinoy-Recorr.Origeny);
end;
procedure TSecuencia.DibujarRecorrido(x,y:integer; Canvas:Tcanvas);
begin
with Canvas do
begin
Pen.Style :=psdot;
Pen.color:=Color;
with Recorr do
begin
if Origenx<>NULLREC then
begin
MoveTo(Origenx+x,Origeny+y);
LineTo(x+Destinox,y+Destinoy);
end;
end; //with ..
end;
end;
//valores 0 a 360 antihorario o 0 180 0 -180
function Tsecuencia.Rotate2D(x,y:integer; alpha:double): TPoint;
var
sinus, cosinus : Extended;
begin
alpha:=DegToRad(alpha);
SinCos(alpha, sinus, cosinus);
result.x := Round(x*cosinus + y*sinus);
result.y := Round(-x*sinus + y*cosinus);
end;
end.
Código:
unit sprites;
interface
uses Windows,SysUtils,graphics,extctrls,pathmovil,classes;
type
TOrientacion=(orNorte,orNorEste,orEste,orSureste,orSur,orSurOeste,orOeste,OrNoroeste);
type
TSprite = class
public
x, y, xAnterior, yAnterior: Integer;
ColorTransparente: TColor;
Imagen, Mascara,buffer: TImage;
Seleccion: integer;
deltx,delty:integer;
Orientacion:TOrientacion;
Secuencia: Array [1..MAXSEQ] of TSecuencia;
constructor Create;
destructor Destroy; override;
procedure Cargar( sImagen: string );
procedure Dibujar( x,y:integer; Canvas: TCanvas );
function AddSec(MIsec:TSecuencia):integer;
function Delete(Indice:integer):integer;
private
Count: integer;
end;
implementation
constructor TSprite.Create;
begin
inherited;
Imagen := TImage.Create( nil );
Imagen.AutoSize := True;
Mascara := TImage.Create( nil );
ColorTransparente := RGB( 255, 0, 255 );
Buffer := TImage.Create( nil );
Count:=0;
end;
destructor TSprite.Destroy;
begin
Buffer.Free;
Mascara.Free;
Imagen.Free;
inherited;
end;
procedure TSprite.Cargar( sImagen: string );
var
i, j: Integer;
begin
Imagen.Picture.LoadFromFile( sImagen );
Mascara.Width := Imagen.Width;
Mascara.Height := Imagen.Height;
/// jcsoft
Buffer.Width:= Imagen.Width;
Buffer.Height := Imagen.Height;
/// jcsoft
for j := 0 to Imagen.Height - 1 do
for i := 0 to Imagen.Width - 1 do
if Imagen.Canvas.Pixels[i,j] = ColorTransparente then
begin
Imagen.Canvas.Pixels[i,j] := 0;
Mascara.Canvas.Pixels[i,j] := RGB( 255, 255, 255 );
end
else
Mascara.Canvas.Pixels[i,j] := RGB( 0, 0, 0 );
end;
procedure TSprite.Dibujar( x, y: Integer; Canvas: TCanvas );
begin
Canvas.CopyMode := cmSrcAnd;
Canvas.Draw( x, y, Mascara.Picture.Graphic );
Canvas.CopyMode := cmSrcPaint;
Canvas.Draw( x, y, Imagen.Picture.Graphic );
end;
function TSprite.AddSec(MIsec:TSecuencia):integer;
begin
if Count<=MAXSEQ then
begin
inc(count);
if Secuencia[Count]=nil then
Secuencia[Count]:=TSecuencia.Create;
miSEC.numero:=Count;
if Misec.NOmbre='' then
MIsec.Nombre:='SEC'+IntToStr(Count);
Secuencia[Count]:=Misec;
result:=Count;
end
else result:=-1
end;
function TSprite.Delete(Indice:integer):integer;
begin
if (indice>0) or (indice<=Count) then
begin
// hacer rutina de borrado de elemento
end
else result:=-1;
end;
end.
¿Podria ser porque en el programa principal declaro como privada la estructura ListaSprites? Código:
type
TForm1 = class(TForm)
........
private
ListaSprites: array [1..MAXBOTS] of TSprite;
...
|
|
#2
|
||||
|
||||
|
Yo veo un problema aqui:
Si secuencia[count] es nil, estás creando un nuevo objeto en memoria. Posteriormente haces: Secuencia[count] := Misec; eso quiere decir que el Objeto que creaste en memoria se pierde, es decir, estás creando memoria que nunca se podrá liberar. En principio hay dos soluciones que depende de tu criterio: - Copiar los datos de Misec al nuevo objeto recien creado (secuencia[Count].Nombre := Misec.Nombre) - No crear el objeto en memoria y dejar sólo la línea Secuencia[count] := Misec. Pero esto puede tener problemas si más tarde liberas el objeto... por ejemplo, el siguiente código dará problemas:
Otra variación es usar un TObjectList en lugar de arrays (busca en el foro por Tobjectlist)
__________________
Si usted entendió mi comentario, contácteme y gustosamente, se lo volveré a explicar hasta que no lo entienda, Gracias. |
|
#3
|
|||
|
|||
|
Ya intente lo de los TObjectList pero se me queda grande, ya que no controlo mucho lo de las clases y me daba Acces violation por muchos sitios. Ya pergunte sobre eso en foro varios.
LO que puse Código:
if Secuencia[Count]=nil then
Secuencia[Count]:=TSecuencia.Create; <--- misma variable asignada
Cita:
ListaSprites[SelectedSprite].Secuencia[x]:=TSecuencia.Create; TmpSec:=TSecuencia.Create; ..relleno datos en tmpSec... ListaSprites[SelectedSprite].Secuencia[x].AddSec(TmpSec); TmpSec.Free; // o Destroy??? ¿Esto es correcto? antes de usar la funcion AddSec El poner todo el codigo es para saber si he hecho alguna cosa que este mal puesta de base. PD: Ya se que hacer arrays y clases no parace muy ortodoxo. Ya me gustaria saber Delphi como algunos. pero es lo que hay... PD 2:La firma me encanta: Es lo que muchas veces suele pasar en la vida real. Última edición por alquimista fecha: 08-04-2010 a las 10:31:07. |
|
#4
|
||||
|
||||
|
Unos detallitos:
El código anterior define una referencia a un objeto. No es un objeto, sino una referencia. El objeto no existe hasta que lo creas. Con esto estás creando un objeto, no "asignando el constructor de la variable". Ahora "Variable" hace referencia al objeto recién creado.Con esto Variable1 y Variable2 hacen referencia al mismo objeto. No estás clonando (copiando) el objeto. Al ser referencias al mismo objeto, ejecutar "Variable2.Trabaja" es exactamente lo mismo que ejecutar "Variable1.Trabaja". Recuerda lo que he dicho al principio: Son referencias a objetos, no objetos. Si hemos dicho que Variable1 y Variable2 hacen referencia al mismo objeto, resulta lógico pensar que tras ejecutar "Variable1.Free" tampoco podemos usar Variable2, ya que el objeto al que referencia no existe, por lo que resulta en una violación de acceso. Por cierto: nunca hay que llamar al destructor (Destroy). Para destruir un objeto hay que utilizar "Free". En el código anterior, definimos una referencia a un objeto y luego lo creamos, pero no lo destruimos. Al terminar el procedimiento, la refencia al objeto es eliminada, pero el objeto sigue existiendo. Por eso podemos hacer cosas como la siguiente:
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi! - BAScript - Multi Language Scriptable Development Environment Última edición por Ñuño Martínez fecha: 08-04-2010 a las 12:44:55. Razón: Errores, errores y más errores... |
|
#5
|
|||
|
|||
|
Ahhh...
Claro, mi intencion era clonar el objeto para usarlo de almacenamiento temporal y al liberarlo me pasaba lo que ha explicado Nuño. ¿Y si quiero clonarlo , como se debería hacer? hay algo como Copy...? PD: Algo hemos avanzado con los conceptos de objetos... Lo reconozco he usado algun Destroy por ahi ![]() PD2: Muy buena explicacion.. concluyendo debo expresar mi nivel de Delphi con una variable Double; var Nivel ouble; .. Nivel:=0.001;![]() ![]() ![]() |
|
#6
|
||||
|
||||
|
Cita:
Sirva como ejemplo la clase "TStrings". Puede clonarse un objeto de esta clase asignando la propiedad Text, es decir:
Ahora los dos objetos contienen una copia idéntica de las cadenas, pero cada uno es independiente. Sin embargo este sistema sólo sirve para esta clase y sus derivadas (por ejemplo, TStringList).
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi! - BAScript - Multi Language Scriptable Development Environment |
|
#7
|
||||
|
||||
|
Ñuño, recuerda tambien:
Para clonar objetos está el método Assign, pero pertenece a TPersistent y puede que incluya muchas cosas que no quieras. Además debes modificar el método Assign en tu clase para que sea 100 % operativo, total, como he soltado un rollo ahí vá lo que deberías hacer: Y ahora si podemos usar un código como...
Esto que has visto es realmente lo que hace el método TPersistent.Assign(), pero es más lioso de entender por la herencia (la primera vez que vi el código de Assign no entendí nada de nada). Edito: como me quedé intrigado hice la prueba, Delphi si clona los registros con el operador ":=" obtenemos el mensaje "a.nombre es juan b.nombre es pepe"
__________________
Si usted entendió mi comentario, contácteme y gustosamente, se lo volveré a explicar hasta que no lo entienda, Gracias. Última edición por Lepe fecha: 08-04-2010 a las 19:20:16. |
|
#8
|
|||
|
|||
|
Muchas gracias por las lecciones magistrales.
A ver si con toda esa ayuda puedo terminar mi programa.. Un saludo. Una ultima pregunta: ¿Si libero ListaSprites, se libera la memoria de los objetos Secuencia que estan en ListaSprites? Código:
for i:=1 TO MAXBOTS do
if ListaSprites[i]<>nil then
ListaSprites[i].free;
Código:
type
TSprite = class
public
x, y, xAnterior, yAnterior: Integer;
ColorTransparente: TColor;
Imagen, Mascara,buffer: TImage;
Seleccion: integer;
deltx,delty:integer;
Orientacion:TOrientacion;
Secuencia: Array [1..MAXSEQ] of TSecuencia;
![]() ![]() ![]() ![]() ![]() ![]() Última edición por alquimista fecha: 09-04-2010 a las 00:57:07. |
|
#9
|
||||
|
||||
|
Cita:
Por cierto, gracias por la explicación acerca de "Assign". ![]() Cita:
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi! - BAScript - Multi Language Scriptable Development Environment |
|
#10
|
||||
|
||||
|
Una regla que es bueno recordar siempre: lo que se crea por código, se debe destruir por código.
|
|
#11
|
||||
|
||||
|
Cita:
El tema viene por esto:
aquí estamos creando nosotros la ventana, pero le decimos que Delphi la destruya automáticamente al terminar la aplicación; nosotros no tenemos que destruirla. Caso bien distinto a: donde nosotros lo creamos y nadie se hará cargo de su destrucción. Nosotros debemos destruirla en el OnClose o llamar a form2.Free
__________________
Si usted entendió mi comentario, contácteme y gustosamente, se lo volveré a explicar hasta que no lo entienda, Gracias. |
![]() |
|
|
Temas Similares
|
||||
| Tema | Autor | Foro | Respuestas | Último mensaje |
| Crear Clases propias o Usar Existentes | jorllazo | Debates | 19 | 27-04-2007 03:07:39 |
| Crear y utilizar librerías de clases | Val | OOP | 2 | 13-04-2007 17:27:11 |
| Crear clases desde Delphi | albertoP | OOP | 6 | 19-09-2006 21:47:05 |
| crear clases en delphi | alextmb | Varios | 6 | 24-04-2006 01:40:45 |
| Como usar correctamente ReplaceDialog? | clanmilano | Varios | 1 | 06-02-2006 13:41:57 |
|