Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Delphi y OO (https://www.clubdelphi.com/foros/showthread.php?t=72616)

Paulao 02-03-2011 00:38:31

Delphi y OO
 
No se como si usa una Property. Tengo una property que lee y escribe en una variable TString y otra en una TStrinList. Pues no se donde esta StringList es llenada, pues todo es object. Tengo duda con Property.

No consigo usar el Break Point en mi Delphi XE. En ninguno proyecto funciona, ninguno mismo.

Como pober mis DCU en un Folder y mi EXE en otro, pues en el Delphi XE no se como configurar. Gracias a todos.

Delphius 02-03-2011 02:15:23

Hola Paulao,
Para poder ayudarte apropiadamente sería de mucha ayuda que nos comentes como está diseñada la clase. ¿Puedes mostrarnos al menos una parte de su código?

Respecto lo de problemas con Delphi XE no puedo asesorarte, no utilizo dicha versión.

Saludos,

Neftali [Germán.Estévez] 02-03-2011 09:54:46

Hola Paulao, para el tema de las propiedades, es mejor que nos pongas código de cómo están definidas, tal y como ha dicho Delphius, de otra forma es difícil saber qué necesitas.

Para el tema de los breakpoints, mejor seguir en el hilo original y no mezclar.

Paulao 02-03-2011 14:41:32

Esta primera Unit es las classes que uso y la otra llamada Main es el programa. Este programa solo tiene un Form(Main). El haz referencia a otras classes, pero solo puzo una por el espacio y creo que una solo es lo suficiente, ok? Voy hacer en dos post, pues estas mui largo en un unico post.

Código Delphi [-]
unit IndexDocument;

interface

uses StdCtrls;

type
  TIndexDocument = class
  private
    fMovedFileName: string;
    fPaginaOK: Boolean;
    fFinishedFileName: string;
    fTipoEdicao: string;
    fDataEdicao: TDateTime;
    fTipoPagina: string;
    fPagina: string;
    fOriginalFileName: string;
    fProximaPagina: string;
    fNumeroEdicao: Integer;
    fRuimFileName: string;
    fIndex: Integer;
    fImagem: TObject;
    fID: Int64;
    fFileMovido: Boolean;
    procedure SetPagina(const Value: string);
    function GetDestinationFileName: string;
  public
    procedure CalcularFileNames(const SrcPath, DstPath: string);
    function MoveFile: Boolean;
    procedure UndoMove;
    property OriginalFileName: string read fOriginalFileName write fOriginalFileName;
    property DataEdicao: TDateTime read fDataEdicao write fDataEdicao;
    property Pagina: string read fPagina write SetPagina;
    property TipoEdicao: string read fTipoEdicao write fTipoEdicao;
    property NumeroEdicao: Integer read fNumeroEdicao write fNumeroEdicao;
    property TipoPagina: string read fTipoPagina write fTipoPagina;
    property PaginaOK: Boolean read fPaginaOK write fPaginaOK;
    // Propriedades calculadas
    property FinishedFileName: string read fFinishedFileName;
    property MovedFileName: string read fMovedFileName;
    property RuimFileName: string read fRuimFileName;
    property ProximaPagina: string read fProximaPagina;
    property DestinationFileName: string read GetDestinationFileName;
    // Propriedades de ligação
    property Index: Integer read fIndex write fIndex;
    property Imagem: TObject read fImagem write fImagem;
    property ID: Int64 read fID write fID;
    // Utilidades
    property FileMovido: Boolean read fFileMovido;
  end;

implementation

uses Util, DateUtils, SysUtils;

{ TIndexDocument }

procedure TIndexDocument.CalcularFileNames(const SrcPath, DstPath: string);
var
  srPath: string;
  Ano, Mes, Dia: string;

  function FileNameNew: string;
  begin
    Result := Ano + Mes + Dia + '-'
      + IntToStr(NumeroEdicao) + '-'
      + TipoEdicao + '-' + Pagina + '-'
      + TipoPagina
      + ExtractFileExt(OriginalFileName);
  end;

  function BuildFileName(const FileName: string; Mv: Boolean): string;
  begin
    if Mv then
      Result := DstPath + 'MV\'
    else
      Result := DstPath + 'RU\';
    Result := FileNewLocation(SrcPath, srPath, Result);
    if Mv then
      Result := Result + FileName
    else
      Result := Result + FileNameNew;
  end;

  function BuildOkFileName: string;
  begin
    Result := DstPath + 'OK\';
    Result := FileNewLocation(SrcPath, srPath, Result);

    Result := Result + Ano + '\' + Mes + '\' + Dia + '\' + Pagina + '\';
    Result := Result + FileNameNew;
  end;

var
  oriName: string;
begin
  Ano := StrZero(YearOf(DataEdicao), 4);
  Mes := StrZero(MonthOf(DataEdicao), 2);
  Dia := StrZero(DayOf(DataEdicao), 2);

  srPath := ExtractFilePath(OriginalFileName);
  oriName := ExtractFileName(OriginalFileName);

  fMovedFileName := BuildFileName(oriName, true);
  fRuimFileName := BuildFileName(oriName, false);
  fFinishedFileName := BuildOkFileName;
end;

function TIndexDocument.GetDestinationFileName: string;
begin
  if PaginaOK then
    Result := FinishedFileName
  else
    Result := RuimFileName;
end;

function TIndexDocument.MoveFile: Boolean;
begin
  if not fFileMovido then
  begin
    ForceDirectories(ExtractFilePath(MovedFileName));
    fFileMovido := Util.MoveFile(OriginalFileName, MovedFileName, true);
  end;
  Result := fFileMovido;
end;

procedure TIndexDocument.SetPagina(const Value: string);
var
  A, B, C: string;
  pagNum: Integer;
begin
  LastNumberParts(Value, A, B, C);
  if not tryStrToInt(B, pagNum) then
    raise Exception.Create('Número da página inválido');

  // Página atual
  B := StrZero(pagNum, 3 - Length(A));
  fPagina := A + B + C;

  // Próxima página
  B := StrZero(pagNum + 1, 3 - Length(A));
  fProximaPagina := A + B + C;
end;

procedure TIndexDocument.UndoMove;
begin
  if PaginaOK then
    Util.DeleteFile(FinishedFileName)
  else
    Util.DeleteFile(RuimFileName);
  if fFileMovido then
    fFileMovido := not Util.MoveFile(MovedFileName, OriginalFileName, true);
end;

end.

Paulao 02-03-2011 14:47:23

1 Archivos Adjunto(s)
Anejo las Unit Main y la Unit con las classes. No fue possible ponere aca, pues tine mas que 20000 caracteres.

coso 02-03-2011 16:52:32

Hola paolo,

no te he acabado de entender, pero si lo que quieres es crear una propiedad tipo TStrings se hace de este modo


Código Delphi [-]

type ...

private
 SS : TStrings;
...
protected SetSS(s : TStrings);
...
published
 property MiStrings : TStrings read SS write SetSS;

end;

...
implementation
...

constructor MiClase.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
SS := TStringList.Create;
...
end;

destructor MiClase.Destroy;
begin
SS.Free;
end;

procedure SetSS(S : TStrings);
begin
SS.Assign(S);
end;

Hay algo en la ayuda de Delphi, por si he puesto algun error. Un saludo.

Paulao 02-03-2011 17:15:29

No, realmente mi gustaria de entender esto. Si es lo mismo que las variables de instancia en Java y etc... Para sirve las property, su uso y etc...

roman 02-03-2011 18:45:10

Cita:

Empezado por Paulao (Mensaje 392443)
No, realmente mi gustaria de entender esto. Si es lo mismo que las variables de instancia en Java y etc... Para sirve las property, su uso y etc...

A ver, advierto que no he leido lo anterior así que quizá repita o diga algo que no viene del todo al caso.

Hasta donde entiendo y recuerdo, las propiedades (property) en delphi no tienen equivalente en Java. Sólo he visto algo parecido en PHP 5, y tiene sus bemoles.

Podríamos decir, aunque no es del todo cierto, que una propiedad es una forma elegante de acceder a una variable de instancia privada.

En Java puedes tener, por poner un ejemplo, la clase Persona con un campo privado (variable de instancia) llamado nombre. En este tipo de lenguajes, para acceder a tal variable, lo usual es definir métodos de acceso como getNombre (para leer el valor) y setNombre (para establecer el valor). Así, podrías tener un código de este estilo:

Código:

nombre = p.getNombre();

// o bien

p.setNombre("roman");

siendo p una variable de tipo Persona. Siendo nombre una variable privada de la clase Persona, no puedes, por ejemplo, hacer esto:

Código:

p.nombre = "roman";
En delphi, también puedes tener tu clase TPersona y una variable de instancia privada FPersona y correspondientes métodos de acceso:

Código Delphi [-]
TPersona = class
private
  FNombre: String;

public
  function GetNombre(): String;
  procedure SetNombre(S: String);
end;

Podrías hacer uso de los métodos al igual que en Java:

Código Delphi [-]
Nombre := P.GetNombre();

// o bien

P.SetNombre('roman');

Pero, en delphi puedes hacer algo mucho mejor. Puedes declarar una propiedad pública Nombre que use esos métodos de acceso:

Código Delphi [-]
TPersona = class
private
  FNombre: String;

public
  function GetNombre(): String;
  procedure SetNombre(S: String);

  (* read indica el método para leer el valor      *)
  (* write indica el método para escribir el valor *)
  property Nombre: String read GetNombre write SetNombre;
end;

En código puedes usar directamente dicha propiedad:

Código Delphi [-]
P.Nombre := 'roman';

Sintácticamente hablando -y ésta es la gran ventaja- es como si "accedieras" directamente al campo privado:

Código Delphi [-]
P.FNombre := 'roman';  // aquí el compilador marcará error pues FNombre es privada a la clase.

pero, en realidad, el compilador, cuando ve la línea

Código Delphi [-]
P.Nombre := 'roman';

genera este código: (o parecido)

Código Delphi [-]
P.SetNombre('roman');

Esto es, aunque en apariencia estamos asignando la cadena 'roman' a la variable privada FNombre, en realidad la asignación pasa por llamar a la función SetNombre.

Lo mismo si queremos conocer el valor de la variable privada:

Código Delphi [-]
Nombre := P.Nombre;

Al hacer esto, el compilador genera la llamada:

Código Delphi [-]
Nombre := P.GetNombre();

En resumen, las propiedades en delphi nos permiten acceder a atributos de un objeto como si lo hiciéramos directamente, pero siempre pasando por métodos de acceso.

La razón de esto o su finalidad pues es la misma que en Java y otros lenguajes: proteger el ingreso y egreso de datos.

Siguiendo el ejemplo, el método SetNombre podría estar definido así:

Código Delphi [-]
procedure TPersona.SetNombre(S: String);
begin
  FNombre := S;
end;

Pero también podría ser así:

Código Delphi [-]
procedure TPersona.SetNombre(S: String);
begin
  FNombre := UpperString(S);
end;

forzando así, que los nombres estén en mayúsculas.

Ahora bien, dije al principio que definir una propiedad como una forma de acceder a una variable privada no sería del todo exacto.

Un propiedad no necesariamente refleja directamente el valor de un campo del objeto. Continuando con el ejemplo, podríamos tener nuestra clase:

Código Delphi [-]
TPersona = class
private
  FNombre: String;
  FApellidos: String;

public
  function GetNombre(): String;
  procedure SetNombre(S: String);

  function GetApellidos(): String;
  procedure SetApellidos(S: String);

  property Nombre: String read GetNombre write SetNombre;
  property Apellidos: String read GetApellidos write SetApellidos;
end;

con dos propiedades: Nombre y Apellidos.

¿Qué tal si queremos saber el nombre completo de la persona?

Podríamos definir una función que haga el trabajo:

Código Delphi [-]
TPersona = class
private
  ...
public
  ...
  function GetNombreCompleto(): String;
end;

La función simplemente devolvería la concatenación del nombre y los apellidos. Podemos usar el método como siempre:

Código Delphi [-]
NombreCompleto := P.GetNombreCompleto();

Pero podemos hacerlo más elegante (y legible) definiendo una propiedad:

Código Delphi [-]
TPersona = class
private
  ...
public
  ...
  function GetNombreCompleto(): String;

  property NombreCompleto: String read GetNombreCompleto:
end;

con la cual el código se hace más limpio:

Código Delphi [-]
NombreCompleto := P.NombreCompleto;

En este caso, NombreCompleto es un atributo de la clase TPersona, pero no hay una variable de instancia que refleje su valor. Más aún, al no haber declarado un método Set (cláusula write), la propiedad es de sólo lectura; no hay manera, como es lógico, de asignar un valor a P.NombreCompleto.

Así pues, las propiedades en delphi no son más que aditamentos sintácticos o sintactic sugar, es decir, elementos de sintaxis que son prescindibles pero que hacen la vida más sencilla.

Nota, por último, que la declaración de la clase puede hacerse aún más prolija si se mueven los métodos de acceso a una sección privada:

Código Delphi [-]
TPersona = class
private
  FNombre: String;
  FApellidos: String;

  function GetNombre(): String;
  procedure SetNombre(S: String);

  function GetApellidos(): String;
  procedure SetApellidos(S: String);

  function GetNombreCompleto(): String;

public
  property Nombre: String read GetNombre write SetNombre;
  property Apellidos: String read GetApellidos write SetApellidos;
  property NombreCompleto: String read GetNombreCompleto:
end;

// Saludos

Delphius 02-03-2011 19:09:27

Se puede decir más fuerte pero no más claro amigo Roman. Tiene usted un 10 sobresaliente felicitado :):D

No está demás decir que todo lo dicho está perfectamente expresado en un libro ampliamente citado aquí y en otros lugares: La Cara Oculta de Delphi 4. Es más, hasta diría que en en anteriores ocasiones te lo hemos sugerido a ti Paulao. En el FTP está disponible para su descarga.

Saludos,

Casimiro Notevi 02-03-2011 20:55:39

Más claro... no se puede :)

olbeup 03-03-2011 08:21:16

Roman, es una pasada, hace honor a tu legado.
Cita:

La calidad de las respuestas es directamente proporcional a la calidad de la pregunta
Un saludo.

P.D.: Aquí y ahora hemos aprendido los que sabían y los que sabían bastante.

Paulao 03-03-2011 12:57:33

Roman, muchas gracias por el post. Este me lo dio un gran adelanto en mis dudas. Resolvio la duda con relacion a Property en Delphi. Gracias a usted y a los demas que me lo ayudaron en es negocio. Gracias!


La franja horaria es GMT +2. Ahora son las 12:10:49.

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