Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 22-05-2003
Avatar de orfeo
orfeo orfeo is offline
Miembro
 
Registrado: may 2003
Posts: 99
Poder: 21
orfeo Va por buen camino
problemas la hacer un cast de un TStringGrid(DBGrid)

Hola, tengo una procediminto <procedure stringGridFill(grid:TStringGrid)> que anda bien para StringGrid este solo hace que las columnas se auto-ajusten dependiendo del largo de los string que muestra.
Quiero usar la misma funcion para una DBgrid, por ejemplo:

DBGrid1.DataSource.DataSet.DisableControls;
TStringGrid(DBGrid1).DefaultRowHeight:=60;
DBGrid1.DataSource.DataSet.EnableControls;

este codigo anda, entonces lo que yo hago es:

DBGrid1.DataSource.DataSet.DisableControls;
stringGridFill(TStringGrid(DBGrid1)) (x)
DBGrid1.DataSource.DataSet.EnableControls;

pero en la linea (x) salta un error de direccionamiento, y no es dentro del procedure, ya que es antes de llegar al begin de stringGridFill, por eso me da a penzar que hay algo mal, en el cast..

que es?
Responder Con Cita
  #2  
Antiguo 22-05-2003
__cadetill __cadetill is offline
Miembro
 
Registrado: may 2003
Posts: 3.387
Poder: 24
__cadetill Va por buen camino
que error te da? Porque lo acabo de probar y me funciona sin problemas
Responder Con Cita
  #3  
Antiguo 22-05-2003
andres1569 andres1569 is offline
Miembro
 
Registrado: may 2003
Posts: 908
Poder: 21
andres1569 Va por buen camino
Hola:

Por lo que cuentas, tiene toda la pinta de que el método al que llamas pertenece sólo a la clase TStringGrid y no al ascendiente común TCustomGrid. El compilador te deja pasar la sentencia, pero falla en la ejecución. Con DefaultRowHeight eso no ocurría porque sí es común a ambas clases, auqneu esté protegido para una y public para la otra.

Revisa el código de la VCL, a ver si el TCustomGrid tiene implementado dicho método.

Un saludo
Responder Con Cita
  #4  
Antiguo 22-05-2003
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
Orfeo:

Esto, TStringGrid(DBGrid1).DefaultRowHeight:=60;

*jamás* debe hacerse.

TDBGrid y TStringGrid no están en la misma línea de la jerarquía de clases. En general cuando haces el "casting"

TUnaClase(Objeto)

Objeto debe ser de una clase ancestra de TUnaClase como en

Código:
var
  WinControl: TWinControl;

begin
  TEdit(WinControl){...};
end;
En tu caso la clase TStringGrid no es un ancestro de la clase TDBGrid.

// Saludos
Responder Con Cita
  #5  
Antiguo 23-05-2003
andres1569 andres1569 is offline
Miembro
 
Registrado: may 2003
Posts: 908
Poder: 21
andres1569 Va por buen camino
Hola:

Roman escribió:

Cita:
Esto, TStringGrid(DBGrid1).DefaultRowHeight:=60;

*jamás* debe hacerse.
Me parece demasiado categórico decir que jamás debe hacerse. Para mí es un truco muy válido cuando se sabe que la propiedad/método al que se accede pertenece a un ancestro común, como es el caso. Nos valemos de una clase que sí tiene dicha propiedad como public y que hace de "wrapper", y en realidad funciona. Se supone que si está implementada en el ancestro común es porque define un comportamiento común y válido para todas sus clases descendientes, aunqeu lo hagamos valer a través de un intermediario.

Quizás una forma más ortodoxa sería heredar un componente de TDBGrid y promover dicha propiedad a la sección public, o en caso de un método virtual, redefinirlo como public, pero es un trabajo extra que podemos evitar.

Por supuesto, este truco está supeditado a conocer de antemano la declaración de las clases que estamos manejando (para eso está el código fuente), pero eso sucede con el uso diario de componentes, su implementación puede variar de una versión a otra, y de hecho sucede, pero esa es una información de la que dispone el programador.

Ya ves, Roman, siempre dispuesto a replicarte. Espero tu contraréplica.

Un slaudo
Responder Con Cita
  #6  
Antiguo 23-05-2003
Avatar de delphi.com.ar
delphi.com.ar delphi.com.ar is offline
Federico Firenze
 
Registrado: may 2003
Ubicación: Buenos Aires, Argentina *
Posts: 5.932
Poder: 26
delphi.com.ar Va por buen camino
Cita:
Posteado originalmente por andres1569
Me parece demasiado categórico decir que jamás debe hacerse. Para mí es un truco muy válido cuando se sabe que la propiedad/método al que se accede pertenece a un ancestro común, como es el caso.
Pero Román tiene toda la razón, el problema es que un TStringGrid no es ancestro de TDBGrid, así es la jerarquía:
TDBGrid -> TCustomDBGrid -> TCustomGrid
TStringGrid -> TDrawGrid -> TCustomGrid
__________________
delphi.com.ar

Dedique el tiempo suficiente para formular su pregunta si pretende que alguien dedique su tiempo en contestarla.
Responder Con Cita
  #7  
Antiguo 23-05-2003
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
Andrés, me parece que nos estamos confundiendo. Si una clase ancestra dispone de un método protegido entonces desde luego que es válido hacer el casting usando la clase ancestra. Pero en este caso, como ya lo mostró delphi.com.ar, las clases en cuestión no están en la misma línea jerárquica. Es como hacer que un primo mío se haga pasar por mí. Esto, si bien puede funcionar en algunos casos porque el primo por casualidad tenga un método del mismo nombre, puede llevar a problemas de violación de acceso.

Sí, quizá en algún momento nos ahorre trabajo, pero cuando nos acostumbremos a este tipo de trucos y la aplicación comience a fallar nos costará más trabajo hallar la causa.

// Saludos
Responder Con Cita
  #8  
Antiguo 23-05-2003
andres1569 andres1569 is offline
Miembro
 
Registrado: may 2003
Posts: 908
Poder: 21
andres1569 Va por buen camino
Hola:

Delphi.com.ar escribió:

Cita:
Pero Román tiene toda la razón, el problema es que un TStringGrid no es ancestro de TDBGrid, así es la jerarquía:
TDBGrid -> TCustomDBGrid -> TCustomGrid
TStringGrid -> TDrawGrid -> TCustomGrid
No he dicho en ningún momento que un TStringGrid sea un ancestro de TDBGrid, sino que ambos tienen un ancestro común, TCustomGrid. El caso es que la propiedad DefaultRowHeight está definida en ese ancestro, pero sólo es accesible desde "fuera" por el programador final que usa un TStringGrid, al ser public en esta clase.

Cuando hacemos el cast TStringGrid(DBGrid1) simplemente engañamos al compilador para que no proteste pero la instrucción/propiedad que se ejecuta es la del ancestro (probadlo si queréis), la del TCustomGrid, no la del TStringGrid (eso si podría ser una fuente de complicaciones). De esa forma accedemos a una propiedad que pertenece plenamente a nuestra clase.

Roman escribió:
Cita:
Esto, si bien puede funcionar en algunos casos porque el primo por casualidad tenga un método del mismo nombre, puede llevar a problemas de violación de acceso.
En este caso no hay casualidad sino que el método está definido en el TCustomGrid. Eso sí, no creo que nadie deba utilizar este truco confiando en la casualidad, sino cerciorándose de que se accede a un método soportado.

Saludos
Responder Con Cita
  #9  
Antiguo 23-05-2003
Avatar de delphi.com.ar
delphi.com.ar delphi.com.ar is offline
Federico Firenze
 
Registrado: may 2003
Ubicación: Buenos Aires, Argentina *
Posts: 5.932
Poder: 26
delphi.com.ar Va por buen camino
Cita:
Posteado originalmente por andres1569
Hola:
No he dicho en ningún momento que un TStringGrid sea un ancestro de TDBGrid, sino que ambos tienen un ancestro común, TCustomGrid. El caso es que la propiedad DefaultRowHeight está definida en ese ancestro, pero sólo es accesible desde "fuera" por el programador final que usa un TStringGrid, al ser public en esta clase.
Ok, tienes razón en que no has dicho eso, pero igualmente sigo de acuerdo con Román, porque al castear este objeto a una clase que no pertenece a su jerarquía, es como si le estuvieras poniendo un molde no apto con su forma.
Para hacer esto es conveniente crear una clase intermedia, heredada de TDBGrid, que ya posea esta propiedad, por ejemplo:

TMyDbGrid = class(TDBGrid)
public
property DefaultRowHeight;
end;

Y si quieres puedes castear a esta clase tu grid sin problemas.

Saludos!
__________________
delphi.com.ar

Dedique el tiempo suficiente para formular su pregunta si pretende que alguien dedique su tiempo en contestarla.

Última edición por delphi.com.ar fecha: 23-05-2003 a las 23:10:10.
Responder Con Cita
  #10  
Antiguo 23-05-2003
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
Ok Andrés, aquí te va un pequeño relato

El señor Bor Land definió tres clases:

Código:
TGrid = class
private
  FRowHeight: Integer;

protected
  RowHeight: Integer read FRowHeight write FRowHeight;

public
  constructor Create; // Establece RowHeight a valor inicial
end;

TDbGrid = class(TGrid)
end;

TStringGrid = class(TGrid)
private
  Font: TFont;

public
  constructor Create; // crea Font
  destructor Destroy; override; // libera Font;

  // publica RowHeight (y la redefine)
  property RowHeight: Integer read GetHeight write SetHeight;
TStringGrid debía redefinir RowHeight para cambiar el tamaño del font al cambiar la altura del renglón pero sin perder la funcionalidad anterior (no mucha en este caso pero es un cuento)

Código:
function TStringGrid.GetRowHeight: Integer;
begin
  Result := inherited RowHeight;
end;

procedure TStringGrid.SetRowHeight(Value: Integer);
begin
  inherited RowHeight := Value;
  Font.Height := Value;
end;
Tiempo después llega un programador que necesita un DBGrid pero desafortunadamente la propiedad RowHeight está protegida. Entonces lee la documentación y se cerciora de que el ancestro TGrid tiene la propiedad y piensa: "debo derivar una clase de TDbGrid para desprotegerla". Pero también nota que otro descendiente de TGrid, TStringGrid, publica la propiedad y piensa: "¡Ah! ¡Más fácil! Mejor hago un "casting".

La documentación nada dice acerca de Font pues es una propiedad privada que no interesa al público en general.

Como DbGrid es una instancia de TDbGrid no posee el campo Font, así que ¿qué sucederá cuando nuestro protagonista escriba:

TStringGrid(DbGrid).RowHeight := 60;

?

¡¡Una violación de acceso!!

Y colorín colorado, este cuento se ha acabado

// Saludos

Última edición por roman fecha: 23-05-2003 a las 22:28:50.
Responder Con Cita
  #11  
Antiguo 24-05-2003
andres1569 andres1569 is offline
Miembro
 
Registrado: may 2003
Posts: 908
Poder: 21
andres1569 Va por buen camino
Hola foreros:

¡ Me habéis convencido en un 99 %!

El ejemplo de Roman, aunque sea un cuento y no se corresponda con la implementación de DefaultRowHeight en la VCL (Bor Land debe ser un primo de Borland), ilustra que este truco puede ser una fuente potencial de errores al redefinirse el método Set de la propiedad, por mucho que la propiedad sea común a todos. En las pruebas que he hecho, Delphi toma el primer camino conocido, si la propiedad sólo se ha promovido de sección, se ejecuta el código del ancestro y no saltan errores; en cambio, si la propiedad se promueve de sección y además se accede desde un método no común (como el ejemplo de Roman), ya se entra en un terreno sembrado de minas, puesto que se ejecuta el código de la clase que utilizamos para "castear". Si fuera un método virtual, "a secas", y se redefiniera no ocurriría nada malo porque se ejecutaría el método del ancestro (el casting, aunque ilegal según la OOP, tendría un efecto de polimorfismo real). Si fuera un método virtual y abstracto a la vez (lo lógico sería que sí estuviera redefinido en la clase que lo publica), al hacer el casting se ejecutaría igualmente el código del ancestro, saltando un "Abstract error", pero esto ya es afinar demasiado.

Hasta ahora me había parecido un truco válido y fiable, aunque la teoría OOP diga que no se debe moldear salvo a un ascendente, creía que no había peligro al ejecutarse el código ancestral. Sopesando ahora sus pros y sus contras, os doy la razón en que no es un truco recomendable.

Como señala Delphi.Com.Ar, lo mejor es derivar una clase.

Si alguien pregunta, ¿y cuál es el 1% que no te convence? Pues que con TStringGrid(DBGrid1).DefaultRowHeight = 60; logramos el efecto deseado sin errores y sin mucho código, aunque no se atenga a la ortodoxia.

Gracias por vuestras explicaciones.

Saludos

PD: ... y fueron felices y comieron perdices
Responder Con Cita
  #12  
Antiguo 24-05-2003
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
Voy contra el 1%

Cita:
Posteado originalmente por andres1569
Hola foreros:

¡ Me habéis convencido en un 99 %!

¿y cuál es el 1% que no te convence? Pues que con TStringGrid(DBGrid1).DefaultRowHeight = 60; logramos el efecto deseado sin errores y sin mucho código, aunque no se atenga a la ortodoxia.
El villano de la obra, Mr. B. Orlando decide en su versión 8 agregar funcionalidad a TStringGrid y redefine la propiedad DefaultRowHeight...

Epílogo: El lobo se come a caperucita

// Saludos

pd: Andrés, esto último es nada más para bromear un poquillo. Siempre es grato contender contigo ya que de los debates en buenos términos siempre se aprenden cosas nuevas.
Responder Con Cita
  #13  
Antiguo 27-05-2003
Avatar de orfeo
orfeo orfeo is offline
Miembro
 
Registrado: may 2003
Posts: 99
Poder: 21
orfeo Va por buen camino
En realidad, todos tenian razon con lo del cast, el problema es que en mi codigo en un momento dado, accede a cols[i] y este no esta definido en en algun ancestro de DBgrid, parece que solo se define en stringGrid (aunque no me fije).

Ahora el problema es que nesecito acceder a un DBGrid como si fuese una matriz, osea col[i,j], por eso voy a postear otro mensaje en el foro.

Gracias

Última edición por orfeo fecha: 27-05-2003 a las 04:37:37.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

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


La franja horaria es GMT +2. Ahora son las 23:08:21.


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