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 08-09-2008
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Cita:
Empezado por gushynet Ver Mensaje
Antes que nada agradecer las respuestas ya que me han sido de gran ayuda.

Despues de una semana probando las ideas propuestas he conseguido implementar un contenedor generico pero con ciertas restricciones que no he podido quitar.

Hare un pequeño resumen de lo que he hecho:

- He implementado una clase llamada TElemento que es el tipo de objeto que aceptan o devuelven los metodos del contenedor(bueno,los que lo necesitan).

- Esta clase tiene dos metodos abstractos llamados Asignar y Comparar.

- Por otra parte tengo una clase llamada TContenedor, que es la clase base de los posibles contenedores que se implementen. Esta clase no es funcional.

- A partir de TContenedor he definido TListaSimple que implementa una lista simple enlazada en memoria dinamica.

- En el caso concreto de TListaSimple los nodos que almacena son de tipo TNodo cuya estructura consiste en tres campos:

- ID: un entero
- Elemento: TElemento
- Siguiente: puntero a elementos de tipo TNodo.

El contenedor funciona si los objetos que se quieren introducir descienden de TElemento (primera restriccion).

El proceso que sigo para añadir un elemento es el siguiente:

- creo un objeto del mismo tipo que el pasado por parametro. En este punto me ha surgido una duda:

Al González me sugirio la siguiente sintaxis:

Código Delphi [-]o2 := TClaseBase(o1.ClassType).crear(...)


pero no funciona asi que probe la referencia de la clase en lugar de la clase base:

Código Delphi [-]type TClaseBaseClass = class of TClaseBase; ...... o2 := TClaseBaseClass(o1.ClassType).crear(...)


y si funciona. Mi duda es porque funciona asi y no como me sugirio AI Gonzalez ya que encuentro mas coherente y mas intuitiva su solucion que como yo lo he hecho. Que diferencia hay entre usar TClaseBase y TClaseBaseClass?

- Despues de asignar el elemento, lo inserto en la lista dinamica en funcion del campo ID que previamente he calculado y ya esta.



La segunda restriccion es que los objetos que se quieran almacenar en el contenedor deben disponer de los metodos Asignar y Comparar de lo contrario la historia se viene abajo ya que los uso dentro del contenedor de ahi que el usuario que quiera usar el contenedor con su jerarquia de clases debe hacer que su clase base sea descendiente de TElemento que es el que tiene definido de forma abstracta estos metodos. El usuario tiene que preocuparse de implementarlos en sus clases.

Lo que busco para que el contenedor sea totalmente generico y yo ser el hombre mas feliz del mundo mundial es eliminar estas dos restricciones.

La primera restriccion se me ocurrio eliminarla haciendo que en lugar de ser TElemento la clase base para que el contenedor funcione fuese TObject, pero me encontre con el problema de que ni Asignar ni Comparar estan definidos en TObject con lo que tampoco pude eliminar la segunda restriccion.

Supongo que no puedo redefinir la clase TObject añadiendole Asignar y Comparar como metodos abstractos, porque significaria que tendria que dar por sentado que el programador que use mi contenedor tiene redefinido en su aplicacion la clase TObject con los metodos abstractos mencionados cosa que no tendria por que saber ni hacer para poder usar el contenedor.

Y en este punto me he quedado. Al fin y al cabo lo que busco es solucionarle la papeleta al programador y que tenga que saber lo minimo sobre el contenedor para usarlo, y creo que el hecho de que el usuario del contenedor tenga que redefinir los metodos Asignar y Comparar ademas de hacer que sus clases base desciendan de TElemento hace que el objetivo que busco se quede por el camino, para mi gusto son muchas las cosas que tiene que conocer el usuario para usar el contenedor.


Una duda mas:

Sea la siguiente funcion:

Código Delphi [-]function TListaSimple.Actual():TElemento var E:TElemento; begin E := TElemento.create(); E.Asignar(PActual.Elemento); result := E; end;


PActual es un puntero a un nodo de la lista. Esta funcion se complementa con los procedimientos Primero, Ultimo, Siguiente y Anterior para movernos por la lista.

Mi duda es la siguiente: el objeto E es un puntero cuyo espacio (el que ocupa el puntero no a lo que apunta) se libera cuando la funcion termina, es decir, como un tipo simple. Mi pregunta es si a lo que apunta tambien es liberado o soy yo el que tiene que preocuparse de liberar el espacio ocupado por E con el metodo destroy debido a que no es un tipo simple como un entero sino un objeto. Si es asi, significa que esta funcion, a no ser que el que llame a esta funcion se preocupe, cada vez que se llama deja perdido en memoria un espacio equivalente a algo de tipo TElemento o descendiente.


Beno, por ultimo (tranquilidad que no son mas dudas y no sera porque no tenga mas ) agradecer de nuevo las respuestas y la pagina que me han recomendado y por supuesto la paciencia mostrada con las "novelas" que he enviando como mensajes.

Un saludo.

Salud y Delphi
Disculpa, no logro entender apropiadamente lo que expones aqui con lo anterior. No se si lo que creo entender es correcto: ¿Dices que tienes un objeto que guarda una lista con los elementos, y que sea esta lista la que se copie o asigne a los diferentes objetos?

No se porqué empleas una lista enlazada de nodos, contando ya con con clases te facilitan el trabajo (como ser por ejemplo TObjectList).
Por otro lado, el que tu implementes tu Nodo, te obliga a ti a liberar la memoria... cada New() que haces, deberá en algún momento corresponder con un Dispose().
Por otro lado, no estoy seguro pero tengo entendido que si por casualidad en tu TNodo, el "campo" Elemento es del tipo TObject (o descenciente de éste). Un New() de un TNodo y/o un Dispose() ni crea ni elimina dicho objeto.

A me parece que lo más certero es lo que comenta roman.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #2  
Antiguo 08-09-2008
gushynet gushynet is offline
Miembro
 
Registrado: ago 2008
Posts: 26
Poder: 0
gushynet Va por buen camino
buenas de nuevo. Veamos, lo del contenedor generico lo he hecho mas que nada para entender mejor los conceptos relacionados con la poo.

Lo que explica Roman es basicamente lo que he hecho y funciona bien siempre y cuando los objetos que quiera almacenar en el contenedor sean de tipo TElemento o desendiente ya que este objeto tiene las operaciones de asignar y comparar abstractas. Estos metodos los uso dentro del contenedor, concretamente en el metodo que se encarga de añadir un elemento a la lista.


La lista dinamica que implemento usa new y dispose de manera correcta. Ese no es el problema. La lista y en concreto el metodo para añadir un elemento lo que hace es duplicar el elemento pasado por paramero y la funcion asignar es la que realmente asigna los valores al nuevo elemento creado de ahi la necesidad de que los elementos que se quieran guardar en el contenedor deban tener el metodo implementado sino no sabria como asignar el valor de las propiedades de un objeto a otro ya que en principio el contenedor solo se limita a almacenarlos.

Este TElemento es encapsulado en el Nodo que como mencione en el mensaje anterior tiene tres campos, uno de ellos de tipo TElemento. Este campo apunta al objeto duplicado, por lo que el nodo lo que guarda es la ubicacion del objeto en memoria, no el objeto en si.

El metodo para eliminar un nodo de la lista es:

1. busco el elemento en la lista con ayuda de la funcion comparar.
2. una vez encontrado uso el destroy para el elemento al que esta apuntando el campo del Nodo de tipo TElemento.
3. por ultimo libero el nodo de memoria con dispose atualizando tambien los enlaces de la lista que se hayan visto afectados.

En definitiva, el contenedor funciona con objetos de tipo TElemento y desendientes. Y lo que yo quiero es no obligar al usuario a que su jerarquia de clases cuelgue de TElemento para poder usar el contenedor pero si no lo hago asi no podria usar los metodos antes descritos. Y creo que de la forma que lo he hecho aunque funcione ni es eficiente ni elegante.

Con respeto al comentario de Delphius, tienes razon, delphi proporciona clases para lo que busco, pero como se suele decir si quieres lapas hay que mojarse el culo, y pense que la mejor manera de entender la poo en delphi es haciendome yo mismo un contenedor generico y viendo todas las dificultades que se me pueden presentar. En mi caso me quedo mejor con las cosas si le doy vueltas y vueltas hasta encontrar la solucion o al menos el camino para la solucion que si me lo dan todo hecho y mastiado. Soy un masoquista de la programacion que le vamos a hacer.


Con respecto al supuesto despiste cometido por AI Gonzales nada mas agradecerte tu confucion ya que gracias a ello he encontrado un uso a las referencias de clase aunque sigo pensando que tu respuesta me sigue pareciendo mas logica aunque no funcionace



Gracias de antemano por las respuestas. Y bueno, siguo en mi linea de pedir disculpas por lo extenso de las respuestas.


Un saludo.
Responder Con Cita
  #3  
Antiguo 08-09-2008
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Yo tengo una opinión. Realmente, eso de querer trabajar indistintamente con cualquier objeto, sin depender de qué clase sea, a final de cuentas, ya se aleja de lo que es la POO. En ésta hay clases y jerarquías de clases, y uno espera tal o cual comportamiento de acuerdo a la jerarquía. Hacer clonaciones genéricas (si bien puede tener su uso), y, en general, intentar trabajar de manera arbitraría con cualquier objeto, está ya muy lejos del polimorfismo, no hay ningún comportamiento que puedas esperar o predecir porque en realidad no tienes objetos sino meros contenedores de datos.

Pero como digo, es sólo una opinión

// Saludos
Responder Con Cita
  #4  
Antiguo 08-09-2008
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por gushynet Ver Mensaje
...despiste cometido por AI Gonzales...
¿Y ese quién es?
Responder Con Cita
  #5  
Antiguo 08-09-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.561
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por Al González Ver Mensaje
¿Y ese quién es?
Es una nueva clase generada desde la ghClone

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #6  
Antiguo 08-09-2008
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Cita:
Empezado por roman Ver Mensaje
Yo tengo una opinión. Realmente, eso de querer trabajar indistintamente con cualquier objeto, sin depender de qué clase sea, a final de cuentas, ya se aleja de lo que es la POO. En ésta hay clases y jerarquías de clases, y uno espera tal o cual comportamiento de acuerdo a la jerarquía. Hacer clonaciones genéricas (si bien puede tener su uso), y, en general, intentar trabajar de manera arbitraría con cualquier objeto, está ya muy lejos del polimorfismo, no hay ningún comportamiento que puedas esperar o predecir porque en realidad no tienes objetos sino meros contenedores de datos.

Pero como digo, es sólo una opinión

// Saludos
Pues yo comparto tu visión roman.

Me parece que hay algo en el modelo del dominio que está analizando y diseñando gushynet que niebla o entorpece la comprensión real y el propósito de cada clase.

Si pudieramos conocer con más detalles, ya no con una comprensión micro sobre este problema en particular, sino como algo macro (la clase) tal vez podríamos llegar a formular alternativas.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #7  
Antiguo 08-09-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.561
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por Delphius Ver Mensaje
Pues yo comparto tu visión roman.

Me parece que hay algo en el modelo del dominio que está analizando y diseñando gushynet que niebla o entorpece la comprensión real y el propósito de cada clase.

Si pudieramos conocer con más detalles, ya no con una comprensión micro sobre este problema en particular, sino como algo macro (la clase) tal vez podríamos llegar a formular alternativas.

Saludos,
Yo tal vez estoy confundiendome acerca de lo que se habla en este hilo, pero el nuevo Delphi trae algo que se llama generics and anonymous methods.

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #8  
Antiguo 09-09-2008
gushynet gushynet is offline
Miembro
 
Registrado: ago 2008
Posts: 26
Poder: 0
gushynet Va por buen camino
El mensaje es el siguiente ya que aqui tuve problemas con el formateo del codigo

Última edición por gushynet fecha: 09-09-2008 a las 10:54:49. Razón: formato mal establecido
Responder Con Cita
  #9  
Antiguo 09-09-2008
gushynet gushynet is offline
Miembro
 
Registrado: ago 2008
Posts: 26
Poder: 0
gushynet Va por buen camino
buenas de nuevo. Antes que nada pedir discupas por no haber presentado al nuevo usuario AI Gonzalez


Creo que lo mejor llegados a este punto, como sugiere un compañero que ha participado en este hilo(el nombre lo dejamos, que no quiero cambiarselo a mas nadie ) es poner parte del codigo.

Primero pondre parte de la jerarquia de clases cuya clase base es TElemento.

A continuacion pondre la clase TContenedor que es la clase base de la jerarquia de contenedores que quiero implementar.

Vamos pues:

Clase TElemento

Código Delphi [-]
unit Clase_TElemento;

interface

  type TElemento = class(TObject)

    protected
      ResultOp : boolean;
      
    public
      function Comparar(E:TElemento):boolean;virtual;abstract;
      procedure Asignar(E:TElemento);virtual;abstract;
      function Resultado():boolean;
  end;
  type TElementoClass = class of TElemento;
implementation

  //----------------------------------------------------------------------------
  function TElemento.Resultado():boolean;
  begin
    Result := ResultOp;
  end;
  //----------------------------------------------------------------------------
  
end.



Clase TParrafo

Código Delphi [-]
unit Clase_TParrafo;

interface
  uses Clase_TElemento;

  type TParrafo = class(TElemento)

    protected
      parrafo:AnsiString;
      ResultOp:boolean;
    private
      procedure SetContenido(p:AnsiString);
    public
      property contenido:AnsiString read parrafo write SetContenido;
      constructor create();virtual;
      function Comparar(E:TElemento):boolean;override;
      procedure Asignar(E:TElemento);override;
      
  end;

implementation

  //----------------------------------------------------------------------------
  constructor TParrafo.Create();
  begin
    inherited create();
    parrafo := '';
    ResultOp := false;
  end;
  //----------------------------------------------------------------------------
  function TParrafo.Comparar(E:TElemento):boolean;
  begin
    ResultOp := false;
    if parrafo = TParrafo(E).parrafo then
      ResultOp := true;
    Result := ResultOp;
  end;
  //----------------------------------------------------------------------------
  procedure TParrafo.Asignar(E:TElemento);
  begin
    ResultOp := false;
    if parrafo <> TParrafo(E).parrafo then
    begin
      parrafo := TParrafo(E).parrafo;
      ResultOp := true;
    end;
  end;
  //----------------------------------------------------------------------------
  procedure TParrafo.SetContenido(p: string);
  begin
    parrafo := p;
  end;
  //----------------------------------------------------------------------------
end.



Clase TPregunta
Código Delphi [-]
unit Clase_TPregunta;

interface
  uses Clase_TParrafo;
  type TPregunta = class(TParrafo)
  
  end;
implementation

end.


Clase TRespuesta

Código Delphi [-]
unit Clase_TRespuesta;

interface

  uses Clase_TParrafo;

  type TRespuesta = class(TParrafo)

  end;
  
implementation

end.


Clase TTematica

Código Delphi [-]
unit Clase_TTematica;

interface

  uses Clase_TElemento,Clase_TParrafo;

  type TTematica = class(TParrafo)

    private
      descr:AnsiString;
      procedure SetDescripcion(d:AnsiString);
    public
      property descripcion:AnsiString read descr write SetDescripcion;
      constructor create();overload;override;
      constructor create(p:AnsiString;d:AnsiString);overload;
      function Comparar(E:TElemento):boolean;override;
      procedure Asignar(E:TElemento);override;
  end;
implementation

  //----------------------------------------------------------------------------
  constructor TTematica.create();
  begin
    inherited create();
    descr := '';
  end;
  //----------------------------------------------------------------------------
  constructor TTematica.create(p: string; d: string);
  begin
    parrafo := p;
    descr := d;
  end;
  //----------------------------------------------------------------------------
  function TTematica.Comparar(E: TElemento):boolean;
  begin
    ResultOp := false;
    if (parrafo = TTematica(E).parrafo)and(descr = TTematica(E).descr) then
      ResultOp := true;
    Result := ResultOp;
  end;
  //----------------------------------------------------------------------------
  procedure TTematica.Asignar(E: TElemento);
  begin
    ResultOp := false;
    if (parrafo <> TTematica(E).parrafo)or(descr<>TTematica(E).descr) then
    begin
      parrafo := TTematica(E).parrafo;
      descr := TTematica(E).descr;
      ResultOp := true;
    end;
  end;
  //----------------------------------------------------------------------------
  procedure TTematica.SetDescripcion(d: string);
  begin
    descr := d;
  end;
  //----------------------------------------------------------------------------
end.

Ahora la clase TContenedor

Código Delphi [-]
unit Clase_TContenedor;

interface

  uses Clase_TElemento;

  type TContenedor = class(TObject)

    protected
      PrimerE : Pointer;
      ActualE : Pointer;
      ResultOp : boolean;
      NumElementos : cardinal;
      function ObtenerID():cardinal;virtual;abstract;

    public
      constructor create();
   
      procedure Add(E:TElemento);virtual;abstract;
      procedure Modificar(E1:TElemento;E2:TElemento);virtual;abstract;
      procedure Eliminar(E:TElemento);virtual;abstract;

      function Esta(E:TElemento):boolean;virtual;abstract;

      procedure Actual(E:TElemento);virtual;abstract;
      procedure Primero();
      procedure Ultimo();virtual;abstract;
      procedure Siguiente();virtual;abstract;
      procedure Anterior();virtual;abstract;

      function NElementos():cardinal;

      procedure Iniciar();virtual;abstract;

      function Resultado():boolean;


  end;

  type TObjectClass = class of TObject;
implementation

  //----------------------------------------------------------------------------
  constructor TContenedor.create();
  begin     PrimerE := nil;
    ActualE := nil;
    ResultOp := false;
    NumElementos := 0;
  end;  
  //----------------------------------------------------------------------------
  procedure TContenedor.Primero();
  begin     
        ResultOp := false;     
        if PrimerE<>nil then     
        begin       
           ActualE := PrimerE;      
           ResultOp := true;     
       end;
  end;
  //----------------------------------------------------------------------------
  function TContenedor.NElementos:cardinal;
  begin     result := NumElementos;   end;
  //----------------------------------------------------------------------------
  function TContenedor.Resultado():boolean;
  begin     result := ResultOp;   end;
  //----------------------------------------------------------------------------
end.


Y ahora la clase TListaSimple que desciende de TContenedor y dos métodos ya que esto se ha hecho demasiado largo

Código Delphi [-]
uses Clase_TElemento,Clase_TContenedor,Clase_TParrafo;

  type PTNodo = ^TNodo;
    TNodo = record
      Id : cardinal;
      Elemento : TElemento;
      siguiente : PTNodo;
    end;

  type TListaSimple = class(TContenedor)

    protected
      function ObtenerID():cardinal;override;

    public

      destructor destroy();override;//
      
      procedure Add(E:TElemento);override;
      procedure Modificar(EAnt:TElemento;ENuevo:TElemento);override;
      procedure Eliminar(E:TElemento);override;

      function Esta(E:TElemento):boolean;override;

      procedure  Actual(E:TElemento);override;

      procedure Ultimo();override;
      procedure Siguiente();override;
      procedure Anterior();override;

      procedure Iniciar();override;

  end;


Y ahora los dos proedimientos: Add y Actual

Procedimiento Add

Código Delphi [-]
procedure TListaSimple.Add(E: TElemento);
  var
    nuevo,actual,anterior:PTNodo;
    Elemento : TElemento;
    s:string;
  begin
    if Esta(E) = false then
    begin
      s := E.ClassName;
      Elemento := TElementoClass(E.ClassType).Create(); 
      TElementoClass en lugar de poner directamente
      //la clase base TElemento
      Elemento.Asignar(E);
      new(nuevo);
      nuevo.Id := ObtenerID();
      nuevo.Elemento := Elemento;
      nuevo.siguiente := nil;

      nuevo.Elemento := Elemento;
      if PrimerE = nil then
        PrimerE := nuevo
      else
      begin
        actual := PrimerE;
        anterior := nil;
        while  (actual<>nil) and (actual.Id < nuevo.Id) do
        begin
          anterior := actual;
          actual := actual.Siguiente;
        end;
        if anterior = nil then // va el primero
        begin
          nuevo.Siguiente := PrimerE;
          PrimerE := nuevo;
        end
        else
        begin
          if actual = nil then //va al final
            anterior.Siguiente := nuevo
          else //va entre dos nodos
          begin
            nuevo.Siguiente := actual;
            anterior.Siguiente := nuevo;
          end;
        end;
      end;
      NumElementos := NElementos + 1;
      ResultOp := true;
    end
    else
      ResultOp := false;
  end;


Procedimiento Actual

Código Delphi [-]
procedure TListaSimple.Actual(E:TElemento);
  begin
    ResultOp := true;
    if PrimerE <> nil then
    begin
      if ActualE <> nil then
        E.Asignar(PTNodo(PrimerE).Elemento);
    end
    else
    begin
      ResultOp := false;
    end;
  end;



Espero que ahora se entienda mejor la historia que tengo entre manos aunque entendere que despues de los largo que se ha hecho espereis a la pelicula para ver como se resuelve el problema

Un saludo y gracias por las respuestas, las anteriores a este mensaje y las posibles despues de ese mensaje

Última edición por gushynet fecha: 09-09-2008 a las 10:58:47. Razón: otros
Responder Con Cita
  #10  
Antiguo 08-09-2008
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por egostar Ver Mensaje
Es una nueva clase generada desde la ghClone

Salud OS
Ah, siendo así, más bien sería una nueva instancia.
Responder Con Cita
  #11  
Antiguo 08-09-2008
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.561
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por Al González Ver Mensaje
Ah, siendo así, más bien sería una nueva instancia.
Ah si, perdón, no se que estaba pensando

Salud OS
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
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
Apuntar a un tipo genérico Guillermo80 Varios 4 09-03-2008 11:48:22
Reutilizar código "generico" adlfv OOP 13 06-09-2005 02:01:04
Ayuda, como llamar a un procedimiento desde otro procedimiento? Ariatna Varios 1 01-02-2005 04:05:35
reporte generico piyugo Impresión 8 07-05-2004 18:20:03
Configuar Generico/solo texto en Win 2000 sperezp Impresión 0 13-01-2004 15:13:43


La franja horaria es GMT +2. Ahora son las 07:59:23.


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