![]() |
![]() |
![]() |
![]() |
![]() |
FTP | ![]() |
![]() |
CCD | ![]() |
![]() |
Buscar | ![]() |
![]() |
Trucos | ![]() |
![]() |
Trabajo | ![]() |
![]() |
Foros | ![]() |
|
Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
![]() |
|
Herramientas | Buscar en Tema | Desplegado |
#1
|
|||
|
|||
![]() Estoy intentando añadir propiedades a TField pero me da error.
He hecho lo siguiente y me da error: type TmyField = class(TField) private FGrid: String; protected procedure setGrid(const value : string); public constructor Create(AOwner: TComponent); override; published property Grid: string read FGrid write SetGrid; end; implementation constructor TmyField.Create(AOwner: TComponent); begin inherited Create(AOwner); end; procedure TmyField.setGrid(const value : string); begin FGrid := Value; end; Me da error al asignar la variable value a FGrid. Alguien me puede ayudar? Gracias de antemano |
#2
|
||||
|
||||
Probé tu código y no me marca ningún error.
¿Cuál es el error que te marca? // Saludos |
#3
|
|||
|
|||
Yo tengo una aplicación en la cual me crea los campos en tiempo de ejecución y le quiero añadir una propieda para que me diga si el campo lo muestro en el grid o no. Yo pongo '0' para no y '1' para que sí lo muestre.
Tengo este código que es el que me crea el campo y el error me lo da al asignar un valor a esa nueva propiedad. var Field : TmyField; begin Field := TmyField.Create(Nil); TField(Field) := TStringField.Create(Nil); Field.FieldKind := (fkData); Field.FieldName := 'NOMBRE'; ··· /* Aquí es donde me dá el error */ Field.Grid := 1; Field.DataSet := Tabla; end; Gracias. |
#4
|
||||
|
||||
Aún no nos dices cuál es el error
A juzgar por el código que pones tendría que ser un error durante la compilación ya que intentas asignar a Field.Grid un entero siendo que Field.Grid es de tipo String. Cita:
// Saludos |
#5
|
|||
|
|||
![]() Efectivamente
Field.Grid := '1'; y el error que me da es Access violation at address 0040463E in module 'nombre_programa'. Read of address 000000F8. No se si te servirá de algo. Gracias |
#6
|
||||
|
||||
Hey! No me había dado cuenta de algo, en tu código pones
Código:
Field := TmyField.Create(Nil);
TField(Field) := TStringField.Create(Nil);
Field.FieldKind := (fkData);
Field.FieldName := 'NOMBRE';
No sé qué intentabas hacer pero la primera referencia (a TMyField) se pierde de manera que Field, aunque esté declarado como TMyField es un TStringField, que no tiene la propiedad Grid, de ahí que al tratar de usar Field.Grid se intente referenciar una propiedad inexistente y por tanto se genera el "Access Violation" Si necesitas un StringField quizá te convenga más derivar tu clase de TStringField: Código:
TMyField = class(TStringField) ... end; |
#7
|
|||
|
|||
Es cierto no me había dado cuenta yo tampoco de que me creaba 2 veces el Field.
Pero ahora mi pregunta es la siguiente, ¿cómo puedo hacer que redeclarándome en un solo objeto de tipo TField pueda crear campos TStringField, TIntegerField, TMemoField, etc? Si me respondes sería fantástico. Gracias otra vez. |
#8
|
||||
|
||||
Cita:
Sin embargo, para tu caso particular, si lo único que requieres es una propiedad que te indice si se muestra o no en un Grid, puedes usar la propiedad Tag. Todos los descendientes de TComponent, que incluye a TField y todos sus descendientes, tienen una propiedad Tag que Delphi no usa, es para que el programador la use como desee. Es de tipo LongInt de manera que basta que veas si su valor es 1 ó 0 para saber si lo muestras o no en el Grid. // Saludos |
#9
|
|||
|
|||
Buenas de nuevo roman.
La propiedad Tag no me sirve puesto que no solo quiero añadir una propiedad a TField sino que quiero añadir unas cuantas. Estuve pensando y creo que lo que busco o no se puede o es muy dificil. He encontrado otra posible solución que sería la siguiente: Field := TmyField.Create(Nil); Field.SetDataType(ftString); /* o cualquier otro tipo */ el problema que ahora me surge es que no le puedo dar un tamaño a ese campo que me creo. Field.Size := 5; /* da error */ también he probado con otras dos posiblidades: Field.SetSize(5); Field.CheckTypeSize(5); pero también me fallan. Si tienes alguna solución a mi problema encantado de poder realizarlo. Gracias. |
#10
|
|||
|
|||
Hola:
Creo que para lo que pretendes hacer, no es buena idea heredar nuevas clases puesto que esos objetos TField te los crea Delphi por defecto y por muchos casts que hagas a tus clases definidas, las propiedades que hay son las que hay. Puedes utilizar la propiedad tag que te comenta Román de dos formas para lo que pretendes. En primer lugar te defines un tipo record que almacenará las variables (aquí no le llamo propiedades) que quieres asociar a cada TField. Luego te propongo dos ideas: 1) Defines un tipo puntero que apunte a dicho record, y aprovechas la propiedad tag, que es de tipo integer y ocupa 4 bytes, lo mismo que cualquier puntero, para almacenar una referencia a dicho puntero (haciendo un moldeado de tipo de Integer a Pointer para que el compilador dé su visto bueno). De hechjo, es una de las funcionalidades que se indican en la ayuda de Delphi para la propiedad tag: Código:
PInfoField = ^TInfoField; TInfoField = record EnGrid : Boolean; EnVerde : Boolean; NumColumna : Integer; ... end; // Para asociar esa información a un objeto TField procedure AsiociaInfo (AField: TField; EG, EV: Boolean; NC: Integer); var PInfo : PInfoField; begin GetMem (PInfo, SizeOf(TInfoField)); PInfo^.EnGrid := EG; PInfo^.EnVerde := EV; PInfo^.NumColumna := NC; ... AField.Tag := Integer(PInfo); end; procedure MuestraDatos (AField: TField); var P : PInfoField; begin P := PInfoField(AField.Tag); if P.EnGrid then ShowMessage ('Engrid'); if P.EnVerde then ShowMessage ('EnVerde'); ShowMessage (IntToStr(P.NumColumna)); end; // Acordarse de liberar memoria de estos registros al cerrar aplicación procedure LiberarMemoriaFields; var j : Integer; P : PInfoField; begin for j:=0 to DataSet.FieldCount - 1 do // esta es una manera algo burda de comprobar que hay Info asociada if DataSet.Fields[j].Tag <> 0 then begin P := PInfoField(DataSet.Fields[j].Tag); FreeMem (P, SizeOf(TInfoField)); end; end; Código:
TInfoField = record EnGrid : Boolean; EnVerde : Boolean; NumColumna : Integer; ... end; var ListInfo : Array of TInfoField; // Para asociar esa información a un objeto TField procedure AsiociaInfo (AField: TField; EG, EV: Boolean; NC: Integer); begin SetLength (ListInfo, Length(ListInfo) + 1); with ListInfo[High(ListInfo)] do begin EnGrid := EG; EnVerde := EV; NumColumna := NC; ... end; AField.Tag := High(ListInfo); end; procedure MuestraDatos (AField: TField); var P : TInfoField; begin P := ListInfo[AField.Tag]; if P.EnGrid then ShowMessage ('Engrid'); if P.EnVerde then ShowMessage ('EnVerde'); ShowMessage (IntToStr(P.NumColumna)); end; Suerte
__________________
Guía de Estilo Última edición por andres1569 fecha: 01-10-2003 a las 17:02:21. |
#11
|
||||
|
||||
¡Ah! Esto es excelente andre1569, yo ya nada más añadiría que una tercera opción sería usar Tag para apuntar a un objeto:
Código:
type TMyFieldData = class { propiedades extra } end; ... { Crear los campos } Field := TStringField.Create(Self); MyFieldData := TMyFieldData.Create; MyFieldData.Propiedad := valor; Field.Tag := LongInt(MyFieldData); ... { Usar las propiedades } Valor := TMyData(Field.Tag).Propiedad; ... { Liberar objetos } TMyFieldData(Field.Tag).Free; |
#12
|
|||
|
|||
Gracias a los 2 por responderme.
Me han gustado mucho las tres propuestas, pero la que mejor me ha parecido es la de roman, ya la estoy poniendo en práctica y va genial. Gracias a los dos. Si encontrais una solución más eficiente no estaría de más ponerla. Saludos |
#13
|
||||
|
||||
¡Buen día a todos!
Acabo de leer todos los mensajes de este interesante tema planteado atinadamente por Altp. Esta misma pregunta: Cita:
En aquel entonces me dije: "Debe haber una forma de aplicar esto en TField y que repercuta automáticamente en todos sus descendientes..." Pues hasta ahora creo que tuve razón, porque siento que "debe haber una forma", sólo que todavía el lenguaje Object Pascal de Delphi no la tiene. Para mi fue como descubrir ese enorme hueco que tiene la tabla períodica de los elementos químicos. A esta característica inexistente hasta hoy en día (2 de octubre de 2003) le llamo herencia virtual. Y según el ejemplo que plantea en este caso, pienso que podría aplicarse de la siguiente forma (entre otras posibles): Código:
Type
Complement Class TField
Private
FGrid :String;
Protected
Procedure SetGrid (Const Value :String);
Public
Constructor Create (AOwner :TComponent); Override;
Published
Property Grid :String Read FGrid Write SetGrid;
End;
...
Creo que esta característica elevaría significativamente la potencia del lenguaje Object Pascal (que ya de por si es potente). Estoy seguro de que ya se ha considerado por parte de los ingenieros de Borland. Por lo pronto, a buscar otras alternativas para estos casos. Espero esto sea de utilidad, seguimos en contacto. Al González ![]() |
![]() |
|
|
![]() |
|