en Este artículo se explica cómo escribir propiedades avanzadas, cómo escribir personalizado de streaming de esas propiedades, y sub-propiedades.
Este artículo apareció originalmente en Desarrolladores de Delphi
derechos de Autor Pinnacle Publishing, Inc. Todos los derechos reservados.
|
Este artículo es la parte dos de tres artículo sobre los componentes. Parte uno cubierto el básico de la creación de componentes, parte dos cubrirá la forma de escribir de propiedades avanzadas, cómo escribir personalizado de streaming de esas propiedades, y sub-propiedades. La parte final se cubre los bienes / editores de componentes, cómo escribir dedicado a los editores para su componente de propiedad, y cómo escribir 'ocultos' de los componentes.
Muy a menudo es necesario escribir los componentes que realizan las funciones más avanzadas. Estos componentes a menudo necesario hacer referencia a otros componentes, tener costumbre de datos de propiedad de formatos, o tienen una propiedad que posee una lista de valores en lugar de un único valor. En esta parte, vamos a explorar los diversos ejemplos que cubren estos temas, comenzando con el más sencillo.
referencias de Componentes
Algunos de los componentes de la necesidad de hacer referencia a otros componentes. TLabel por ejemplo, tiene un 'FocusControl' de la propiedad. Cuando se incluye un signo de y comercial en la propiedad 'Caption' subraya la letra siguiente ( & Hola convierte en Hola), presionando la tecla de método abreviado ALT-H en el teclado activará un evento en su etiqueta. Si el 'FocusControl' propiedad ha sido establecer el foco se pasa al control especificado.
Para tener una propiedad en su propio componente es bastante simple. Todo lo que hacemos es declarar una propiedad nueva, y establecer el tipo de propiedad a los más bajos de la clase base que se puede aceptar (TWinControl permitirá a cualquier descendiente de TWinControl para ser utilizado), pero, hay implicaciones.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TSimpleExample = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FFocusControl: TWinControl
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp procedimiento SetFocusControl(const Valor: TWinControl) virtual
& nbsp & nbsp público
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad FocusControl: TWinControl leer FFocusControl escribir SetFocusControl
& nbsp & nbsp fin
procedimiento TSimpleExample.SetFocusControl(const Valor: TWinControl)
begin
& nbsp & nbsp FFocusControl := Valor
fin
& nbsp & nbsp & nbsp & nbsp |
Tomar el ejemplo de arriba. Este es un ejemplo sencillo (de ahí el nombre del componente) de cómo escribir un componente que hace referencia a otro componente. Si usted tiene una propiedad en su componente en el Inspector de Objetos mostrará una lista desplegable con una lista de componentes que coinciden con los criterios (todos los componentes descendientes de TWinControl).
Nuestro componente puede hacer algo como
& nbsp & nbsp & nbsp & nbsp procedimiento TSimpleExample.Haceralgo
begin
& nbsp & nbsp si (Asignado(FocusControl)) y
& nbsp & nbsp & nbsp & nbsp & nbsp (FocusControl.Habilitado) entonces
& nbsp & nbsp & nbsp & nbsp FocusControl.Setfocus
fin
& nbsp & nbsp & nbsp & nbsp |
en Primer lugar se comprueba si la propiedad ha sido asignada, si es así se establezca el foco, pero hay situaciones en las que la propiedad no es Nil sin embargo, el componente puntos ya no es válida. Esto sucede a menudo cuando una propiedad hace referencia a un componente que ha sido destruido.
por Suerte Delphi nos ofrece una solución. Cada vez que un componente es destruido notifica a su propietario (el formulario) que está siendo destruido. En este punto todos los componentes de titularidad de la misma forma que se notifique de este evento. Para capturar este evento debemos sobreescribir un método estándar de TComponent llama 'Notificación'.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TSimpleExample = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FFocusControl: TWinControl
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp procedimiento de Notificación(AComponent: TComponent
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Operación: TOperation) reemplazar
& nbsp & nbsp & nbsp & nbsp procedimiento SetFocusControl(const Valor: TWinControl) virtual
& nbsp & nbsp público
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad FocusControl: TWinControl leer FFocusControl escribir SetFocusControl
& nbsp & nbsp fin
procedimiento TSimpleExample.SetFocusControl(const Valor: TWinControl)
begin
& nbsp & nbsp FFocusControl := Valor
fin
procedimiento TSimpleExample.Notificación(AComponent :TComponent
& nbsp & nbsp Operación : TOperation)
begin
& nbsp & nbsp heredado //Nunca te olvides de llamar a esta
& nbsp & nbsp si (Operación = opRemove) y
& nbsp & nbsp & nbsp & nbsp & nbsp (AComponent = FocusControl) entonces
& nbsp & nbsp & nbsp & nbsp FFocusControl := nil
fin
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp |
Ahora, cuando nuestro componente que se hace referencia es destruido se nos notifica, punto en el cual podemos poner nuestros referencia a Nil. Nota, sin embargo, que me dijo:
'cada componente de titularidad de la misma forma que se notifica a este evento también'Esto nos introduce con otro problema. Sólo se nos notifica que el componente va a ser destruido si es propiedad de la misma forma. Es posible tener nuestra propiedad punto a los componentes de otras formas (o incluso sin un dueño en todo), y cuando estos componentes son destruidos no somos notificados. Sin embargo, de nuevo hay una solución.
TComponent presenta un método llamado 'FreeNotification'. El propósito de FreeNotification es decir el componente (FocusControl) que nos mantenga en mente cuando es destruido.
Una aplicación tendría este aspecto
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TSimpleExample = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FFocusControl: TWinControl
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp procedimiento de Notificación(AComponent: TComponent
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Operación: TOperation) reemplazar
& nbsp & nbsp & nbsp & nbsp procedimiento SetFocusControl(const Valor: TWinControl) virtual
& nbsp & nbsp público
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad FocusControl: TWinControl leer FFocusControl escribir SetFocusControl
& nbsp & nbsp fin
procedimiento TSimpleExample.SetFocusControl(const Valor: TWinControl)
begin
& nbsp & nbsp si Valor <> FFocusControl entonces
& nbsp & nbsp begin
& nbsp & nbsp & nbsp & nbsp si Asignado(FFocusControl)
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FFocusControl.RemoveFreeNotification(Auto)
& nbsp & nbsp & nbsp & nbsp FFocusControl := Valor
& nbsp & nbsp & nbsp & nbsp si Asignado(FFocusControl) entonces
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FFocusControl.FreeNotification(Auto)
& nbsp & nbsp final
fin
procedimiento TSimpleExample.Notificación(AComponent: TComponent
& nbsp & nbsp Operación : TOperation)
begin
& nbsp & nbsp si (Operación = opRemove) y
& nbsp & nbsp & nbsp & nbsp & nbsp (AComponent = FocusControl)
& nbsp & nbsp & nbsp & nbsp FFocusControl := nil
fin
& nbsp & nbsp & nbsp & nbsp |
Cuando la configuración de nuestro FocusControl de la propiedad en primer lugar comprobar si ya está configurado para un componente. Si ya está configurado, necesitamos decirle a la del componente original que ya no necesitamos saber cuando es destruido. Una vez que nuestra propiedad se ha fijado el nuevo valor informamos el nuevo componente que se requiere una notificación cuando se libera. El resto de nuestro código sigue siendo el mismo que el componente que se hace referencia todavía llama a nuestro método de Notificación.
Marca
Esta sección es muy sencillo y no tomará mucho tiempo para cubrir. No me cabe duda de que usted ya está familiarizado con la creación de sus propios tipos ordinales.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TComponentOption = (coDrawLines,
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp coDrawSolid,
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp coDrawBackground)
& nbsp & nbsp & nbsp & nbsp |
Propiedades de este tipo se mostrará una lista desplegable con una lista de todos los valores posibles, pero a veces se necesitan para establecer una combinación de muchos (o todos) de estos valores. Esto es, se establece entran en juego
& nbsp & nbsp & nbsp & nbsp Tipo
& nbsp & nbsp TComponentOption = (coDrawLines,
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp coDrawSolid,
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp coDrawBackground)
& nbsp & nbsp TComponentOptions = set TComponentOption
& nbsp & nbsp & nbsp & nbsp |
la Publicación de una propiedad de tipo TComponentOptions resultaría en un [ ] aparece al lado de nuestro nombre de la propiedad. Cuando usted haga clic para expandir la propiedad, usted verá una lista de opciones. Para cada elemento en TComponentOption verá una propiedad Booleana, puede incluir / excluir elementos de su conjunto estableciendo su valor a True / False.
es sencillo comprobar y modificar elementos en un conjunto de dentro de nuestro componente como tal.
& nbsp & nbsp & nbsp & nbsp si coDrawLines en OurComponentOptions
& nbsp & nbsp entonces DrawTheLines
& nbsp & nbsp & nbsp & nbsp |
o
& nbsp & nbsp & nbsp & nbsp procedimiento Tuncomponente.SetOurComponentOptions(const Valor: TComponentOptions)
begin
& nbsp & nbsp si (coDrawSolid en Valor) y
& nbsp & nbsp (coDrawBackground en valor)
& nbsp & nbsp & nbsp & nbsp {elevar una excepción}
& nbsp & nbsp FOurComponentOptions := Valor
& nbsp & nbsp Invalidar
fin
& nbsp & nbsp & nbsp & nbsp |
Binario propiedades
A veces es necesario escribir su propia transmisión de rutinas para leer y escribir los tipos de propiedad (Esto es como el Delphi de lecturas / escrituras de las propiedades Top y Left para no visible en los componentes de la publicación de las propiedades en el inspector de objetos).
Por ejemplo, una vez me escribió un componente para dar forma a un formulario basado en una imagen de mapa de bits. Mi código en el momento de convertir un mapa de bits a una ventana de la región era muy lento y no ser, posiblemente, de cualquier uso en tiempo de ejecución. Mi solución fue convertir los datos en tiempo de diseño, y la secuencia de datos binarios que el resultado de la conversión. Para crear las propiedades binarias es un proceso de tres pasos.
1. Escribir un método para escribir los datos.
2. Escribir un método para leer los datos.
3. Decirle a Delphi que tenemos un binario de la propiedad, y de paso nuestra lectura / escritura de métodos.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TBinaryComponent = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FBinaryData : Puntero
& nbsp & nbsp & nbsp & nbsp FBinaryDataSize : DWord
& nbsp & nbsp & nbsp & nbsp procedimiento WriteData(S : TStream)
& nbsp & nbsp & nbsp & nbsp procedimiento ReadData(S : TStream)
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp procedimiento DefineProperties(Filer : TFiler) reemplazar
& nbsp & nbsp público
& nbsp & nbsp & nbsp & nbsp constructor Create(AOwner : TComponent) reemplazar
& nbsp & nbsp fin
& nbsp & nbsp & nbsp & nbsp |
DefineProperties es llamado por Delphi cuando se necesita para transmitir nuestro componente. Todo lo que tenemos que hacer es reemplazar este método, y agregar una propiedad utilizando TFiler.DefineProperty o TFiler.DefineBinaryProperty.
& nbsp & nbsp & nbsp & nbsp procedimiento TFiler.DefineBinaryProperty(const Nombre: cadena
& nbsp & nbsp ReadData, WriteData: TStreamProc HasData: Boolean)
constructor TBinaryComponent.Create(AOwner: TComponent)
begin
& nbsp & nbsp heredado
& nbsp & nbsp FBinaryDataSize := 0
fin
procedimiento TBinaryComponent.DefineProperties(Filer: TFiler)
var
& nbsp & nbsp HasData : Boolean
begin
& nbsp & nbsp heredado
& nbsp & nbsp HasData := FBinaryDataSize <> 0
& nbsp & nbsp Archivador.DefineBinaryProperty('BinaryData',ReadData,
& nbsp & nbsp & nbsp & nbsp WriteData, HasData )
fin
procedimiento TBinaryComponent.ReadData(S: TStream)
begin
& nbsp & nbsp S. Leer(FBinaryDataSize, SizeOf(DWord))
& nbsp & nbsp si FBinaryDataSize > 0 entonces begin
& nbsp & nbsp & nbsp & nbsp GetMem(FBinaryData, FBinaryDataSize)
& nbsp & nbsp & nbsp & nbsp S. Leer(FBinaryData^, FBinaryDataSize)
& nbsp & nbsp fin
fin
procedimiento TBinaryComponent.WriteData(S: TStream)
begin
& nbsp & nbsp //Esto no se llama a si FBinaryDataSize = 0
& nbsp & nbsp S. Escritura(FBinaryDataSize, Sizeof(DWord))
& nbsp & nbsp S. Escritura(FBinaryData^, FBinaryDataSize)
fin
& nbsp & nbsp & nbsp & nbsp |
en primer lugar, se anulan DefineProperties. Una vez que hemos hecho esto podemos definir una propiedad binario con los valores -
& nbsp & nbsp -BinaryData : El invisible nombre de la propiedad para ser usada.
& nbsp & nbsp -ReadData : El procedimiento que se encarga de leer los datos.
& nbsp & nbsp -WriteData : El procedimiento de los responsables de escribir los datos.
& nbsp & nbsp -HasData : Si esto es falso, el WriteData procedimiento no es llamado.
la Persistencia
Una breve explicación de la persistencia es en el orden que nos vamos a referir en las siguientes secciones. La persistencia es lo que hace posible que Delphi para leer y escribir las propiedades de todos sus componentes. TComponent se deriva de una clase que se llama TPersistent. TPersistent es simplemente un Delphi clase capaz de tener sus propiedades leído y escrito en Delphi, lo que significa que cualquier descendientes de TPersistent también tienen esta misma capacidad.
Colecciones
a Medida que el progreso a través de este artículo vamos a cubrir propiedades de componente de mayor complejidad. Las colecciones son una de las más complejas 'estándar' de Delphi tipos de propiedad. Si se le cae un TDBGrid en un formulario y un vistazo a sus propiedades en el Inspector de Objetos, usted verá una propiedad denominada 'Columnas'.
Columnas es una propiedad de colección, cuando usted haga clic en el [..] botón, aparecerá una pequeña ventana pop-up. Esta ventana es el estándar editor de propiedades para TCollection propiedades (y a los descendientes de TCollection).
cada vez que usted haga clic en el botón 'Nuevo' se encuentra con un nuevo elemento añadido (una TColumn elemento), haga clic en el elemento que se seleccione en el Inspector de Objetos, de modo que puede alterar sus propiedades y eventos. Cómo se hace esto ?
Las Columnas de la propiedad desciende de TCollection. TCollection es similar a una matriz, que contiene una lista de TCollectionItem. Porque TCollection es descendiente de TPersistent es capaz de transmitir a esta lista de elementos, del mismo modo, TCollectionItem es también descendiente de TPersistent y también pueden transmitir sus propiedades. Así que lo que tenemos es una matriz-como elemento capaces de transmitir todos sus elementos y sus propiedades.
La primera cosa a hacer a la hora de crear nuestra propia estructura basada en TCollection / TCollectionItem es definir nuestra CollectionItem.
(Véase OurCollection.pas)
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TOurCollectionItem = clase(TCollectionItem)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FSomeValue : Cadena
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp función GetDisplayName : Cadena reemplazar
& nbsp & nbsp público
& nbsp & nbsp & nbsp & nbsp procedimiento Assign(Fuente: TPersistent) reemplazar
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad SomeValue : Cadena
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer FSomeValue
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir FSomeValue
& nbsp & nbsp fin
& nbsp & nbsp & nbsp & nbsp |
Lo que hemos hecho aquí es crear un descendiente de TCollectionItem. Hemos añadido un token de propiedad llamada 'SomeValue', reemplaza el GetDisplayName (función para modificar el texto que se muestra en el editor por defecto), y finalmente reemplazado el método de Asignar a fin de permitir TOurCollectionItem a ser asignado a otro TOurCollectionItem. Si omitimos el paso final, a continuación, el método de Asignar de nuestra Colección de clase no va a funcionar !
& nbsp & nbsp & nbsp & nbsp procedimiento TOurCollectionItem.Asignar(Fuente: TPersistent)
begin
& nbsp & nbsp si Fuente se TOurCollectionItem entonces
& nbsp & nbsp & nbsp & nbsp SomeValue := TOurCollectionItem(Fuente).SomeValue
& nbsp & nbsp persona
& nbsp & nbsp & nbsp & nbsp heredado //genera una excepción
fin
función TOurCollectionItem.GetDisplayName: Cadena
begin
& nbsp & nbsp Resultado := Format('Elemento %d',[Index])
fin
& nbsp & nbsp & nbsp & nbsp |
La aplicación de TOurCollection es mucho más complejo, y requiere un poco de trabajo.
& nbsp & nbsp & nbsp & nbsp TOurCollection = clase(TCollection)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FOwner : TComponent
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp función GetOwner : TPersistent reemplazar
& nbsp & nbsp & nbsp & nbsp función GetItem(Index: Integer): TOurCollectionItem
& nbsp & nbsp & nbsp & nbsp procedimiento SetItem(Índice: Valor Entero:
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp TOurCollectionItem)
& nbsp & nbsp & nbsp & nbsp procedimiento Update(Elemento: TOurCollectionItem)
& nbsp & nbsp público
& nbsp & nbsp & nbsp & nbsp constructor Create(AOwner : TComponent)
& nbsp & nbsp & nbsp & nbsp función Agregar : TOurCollectionItem
& nbsp & nbsp & nbsp & nbsp función Insertar(Index: Integer): TOurCollectionItem
& nbsp & nbsp & nbsp & nbsp propiedad Artículos[Index: Integer]: TOurCollectionItem
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer GetItem
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir SetItem
& nbsp & nbsp fin
& nbsp & nbsp & nbsp & nbsp |
Hay una serie de elementos para cubrir con base en lo anterior la declaración de la clase, así que vamos a empezar desde la parte superior y cubrir cada una a su vez.
GetOwner es un método virtual introducido en TPersistent. Este debe ser reemplazado como el código predeterminado para este método devuelve Nil. En nuestra aplicación podemos modificar el constructor para recibir un solo parámetro (AOwner : TComponent). Guardamos este parámetro en FOwner, que luego pasa como el resultado de GetOwner (TComponent desciende de TPersistent, por lo tanto, es un resultado válido de tipo).
& nbsp & nbsp & nbsp & nbsp constructor TOurCollection.Create(AOwner: TComponent)
begin
& nbsp & nbsp heredado Crear(TOurCollectionItem)
& nbsp & nbsp FOwner := AOwner
fin
función TOurCollection.GetOwner: TPersistent
begin
& nbsp & nbsp Resultado := FOwner
fin
& nbsp & nbsp & nbsp & nbsp |
No sólo no se Cree el dueño de la tienda (que es necesaria para el Inspector de Objetos para que funcione correctamente), también le dice Delphi ¿qué clase de nuestro CollectionItem está llamando 'heredado Crear(TOurCollectionItem)'.
GetItem / SetItem se declaran de la misma manera como lo son en TCollection, pero en lugar de trabajar en TCollectionItem que trabajar en nuestra nueva clase TOurCollectionItem. Estos son utilizados en nuestros 'Elementos' de la propiedad más adelante.
Actualización como es arriba es una recta hacia adelante sustitución de la original, trabajando en nuestro nuevo CollectionItem clase en su lugar.
Añadir / Insertar son responsables de añadir elementos a la lista, estos han sido reemplazados para devolver objetos de la clase correspondiente.
por último, un 'Elementos' de la propiedad se introdujo para sustituir los Elementos originales de la propiedad, de nuevo, de modo que nos devuelve un resultado de TOurCollectionItem en lugar de TCollectionItem que nos ahorra el problema innecesario de éste el resultado de cada tiempo.
por último un ejemplo de la implantación de este tipo de propiedad en un componente de la nuestra.
& nbsp & nbsp & nbsp & nbsp TCollectionComponent = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FOurCollection : TOurCollection
& nbsp & nbsp & nbsp & nbsp procedimiento SetOurCollection(const Valor:
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp TOurCollection)
& nbsp & nbsp público
& nbsp & nbsp & nbsp & nbsp constructor Create(AOwner : TComponent) reemplazar
& nbsp & nbsp & nbsp & nbsp destructor Destruir reemplazar
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad OurCollection : TOurCollection
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer FOurCollection
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir SetOurCollection
& nbsp & nbsp fin
& nbsp & nbsp & nbsp & nbsp |
es tan simple como eso. Una vez que nuestro TCollection clase está escrito todo el trabajo duro está hecho. Nuestro constructor crea la clase de colección, el destructor de la destruye, y SetOurCollection hace esto.
& nbsp & nbsp & nbsp & nbsp constructor TCollectionComponent.Create(AOwner: TComponent)
begin
& nbsp & nbsp heredado
& nbsp & nbsp FOurCollection := TOurCollection.Create(Self)
fin
destructor TCollectionComponent.Destruir
begin
& nbsp & nbsp FOurCollection.Libre
& nbsp & nbsp heredado
fin
procedimiento TCollectionComponent.SetOurCollection(
& nbsp & nbsp const Valor: TOurCollection)
begin
& nbsp & nbsp FOurCollection.Asignar(Valor)
fin
& nbsp & nbsp & nbsp & nbsp |
Como se mencionó antes, la (Auto) pasó a la TOurCollectionItem.Crear es almacenado en TOurCollection del FOwner variable que se pasa como el resultado de GetOwner. Un punto a destacar aquí es que en SetOurCollection no trabajamos FOurCollection := valor como son la sustitución de los objetos (los objetos son simplemente punteros), le asignamos nuestra propiedad en el valor.
más Tarde las versiones de Delphi hacer esto más simple todavía. En lugar de tener que reemplazar GetOwner en nuestra clase de Colección, ahora podemos derivar nuestra Colección de TOwnedCollection lugar. TOwnedCollection es un contenedor para TCollection con este trabajo hecho por nosotros.
Sub-propiedades
Antes en este artículo vimos cómo era posible crear una propiedad expansible. La limitación de la anterior técnica fue que cada uno de los sub-elemento apareció como una propiedad Booleana. En la siguiente sección se muestra cómo crear ampliable propiedades que puede contener cualquier tipo de propiedad.
Si un componente requiere una propiedad que es un tipo de registro, esto puede ser fácilmente implementado por la exposición de cada una de las propiedades por separado. Sin embargo, si nuestro componente debe presentar dos o más de las propiedades del mismo tipo de complejo de nuestro Inspector de Objetos de la vista de repente se vuelve muy complicado.
La respuesta es crear una estructura compleja (por igual a un registro o de un objeto) y la publicación de esta estructura como una propiedad siempre que sea necesario. El problema obvio es que Delphi no sabe cómo mostrar esta propiedad a menos que se lo indique. La creación de un completo soplado editor de propiedades (con los cuadros de diálogo, etc) sería una exageración, así que, por suerte Delphi ha proporcionado una solución. Como se mencionó anteriormente, Delphi interna de streaming se basa en el TPersistent clase. El primer paso es derivar nuestra compleja estructura de esta clase.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TExpandingRecord = clase(TPersistent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FIntegerProp : Integer
& nbsp & nbsp & nbsp & nbsp FStringProp : Cadena
& nbsp & nbsp & nbsp & nbsp FCollectionProp : TOurCollection
& nbsp & nbsp & nbsp & nbsp procedimiento SetCollectionProp(const Valor:
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp TOurCollection)
& nbsp & nbsp público
& nbsp & nbsp & nbsp & nbsp constructor Create(AOwner : TComponent)
& nbsp & nbsp & nbsp & nbsp destructor Destruir reemplazar
& nbsp & nbsp & nbsp & nbsp procedimiento Assign(Fuente : TPersistent) reemplazar
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad IntegerProp : Integer
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer FIntegerProp
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir FIntegerProp
& nbsp & nbsp & nbsp & nbsp propiedad StringProp : Cadena
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer FStringProp
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir FStringProp
& nbsp & nbsp __
Componente de la escritura, parte 2 Componente de la escritura, parte 2 : Multi-millones de consejos para hacer su vida mas facil. en Este articulo se explica como escribir propiedades avanzadas, como escribir personalizado de streaming de esas propiedades, y sub-propiedades.
Este articulo aparecio originalmente en Desarrolladores de Delphi
derechos de Autor Pinnacle Publishing, Inc. Todos los derechos reservados.
|
Este articulo es la parte dos de tres articulo sobre los componentes. Parte uno cubierto el basico de la creacion de componentes, parte dos cubrira la forma de escribir de propiedades avanzadas, como escribir personalizado de streaming de esas propiedades, y sub-propiedades. La parte final se cubre los bienes / editores de componentes, como escribir dedicado a los editores para su componente de propiedad, y como escribir 'ocultos' de los componentes.
Muy a menudo es necesario escribir los componentes que realizan las funciones mas avanzadas. Estos componentes a menudo necesario hacer referencia a otros componentes, tener costumbre de datos de propiedad de formatos, o tienen una propiedad que posee una lista de valores en lugar de un unico valor. En esta parte, vamos a explorar los diversos ejemplos que cubren estos temas, comenzando con el mas sencillo.
referencias de Componentes
Algunos de los componentes de la necesidad de hacer referencia a otros componentes. TLabel por ejemplo, tiene un 'FocusControl' de la propiedad. Cuando se incluye un signo de y comercial en la propiedad 'Caption' subraya la letra siguiente ( & Hola convierte en Hola), presionando la tecla de metodo abreviado ALT-H en el teclado activara un evento en su etiqueta. Si el 'FocusControl' propiedad ha sido establecer el foco se pasa al control especificado.
Para tener una propiedad en su propio componente es bastante simple. Todo lo que hacemos es declarar una propiedad nueva, y establecer el tipo de propiedad a los mas bajos de la clase base que se puede aceptar (TWinControl permitira a cualquier descendiente de TWinControl para ser utilizado), pero, hay implicaciones.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TSimpleExample = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FFocusControl: TWinControl
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp procedimiento SetFocusControl(const Valor: TWinControl) virtual
& nbsp & nbsp publico
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad FocusControl: TWinControl leer FFocusControl escribir SetFocusControl
& nbsp & nbsp fin
procedimiento TSimpleExample.SetFocusControl(const Valor: TWinControl)
begin
& nbsp & nbsp FFocusControl := Valor
fin
& nbsp & nbsp & nbsp & nbsp |
Tomar el ejemplo de arriba. Este es un ejemplo sencillo (de ahi el nombre del componente) de como escribir un componente que hace referencia a otro componente. Si usted tiene una propiedad en su componente en el Inspector de Objetos mostrara una lista desplegable con una lista de componentes que coinciden con los criterios (todos los componentes descendientes de TWinControl). Nuestro componente puede hacer algo como
& nbsp & nbsp & nbsp & nbsp procedimiento TSimpleExample.Haceralgo
begin
& nbsp & nbsp si (Asignado(FocusControl)) y
& nbsp & nbsp & nbsp & nbsp & nbsp (FocusControl.Habilitado) entonces
& nbsp & nbsp & nbsp & nbsp FocusControl.Setfocus
fin
& nbsp & nbsp & nbsp & nbsp |
en Primer lugar se comprueba si la propiedad ha sido asignada, si es asi se establezca el foco, pero hay situaciones en las que la propiedad no es Nil sin embargo, el componente puntos ya no es valida. Esto sucede a menudo cuando una propiedad hace referencia a un componente que ha sido destruido. por Suerte Delphi nos ofrece una solucion. Cada vez que un componente es destruido notifica a su propietario (el formulario) que esta siendo destruido. En este punto todos los componentes de titularidad de la misma forma que se notifique de este evento. Para capturar este evento debemos sobreescribir un metodo estandar de TComponent llama 'Notificacion'.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TSimpleExample = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FFocusControl: TWinControl
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp procedimiento de Notificacion(AComponent: TComponent
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Operacion: TOperation) reemplazar
& nbsp & nbsp & nbsp & nbsp procedimiento SetFocusControl(const Valor: TWinControl) virtual
& nbsp & nbsp publico
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad FocusControl: TWinControl leer FFocusControl escribir SetFocusControl
& nbsp & nbsp fin
procedimiento TSimpleExample.SetFocusControl(const Valor: TWinControl)
begin
& nbsp & nbsp FFocusControl := Valor
fin
procedimiento TSimpleExample.Notificacion(AComponent :TComponent
& nbsp & nbsp Operacion : TOperation)
begin
& nbsp & nbsp heredado //Nunca te olvides de llamar a esta
& nbsp & nbsp si (Operacion = opRemove) y
& nbsp & nbsp & nbsp & nbsp & nbsp (AComponent = FocusControl) entonces
& nbsp & nbsp & nbsp & nbsp FFocusControl := nil
fin
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp |
Ahora, cuando nuestro componente que se hace referencia es destruido se nos notifica, punto en el cual podemos poner nuestros referencia a Nil. Nota, sin embargo, que me dijo: 'cada componente de titularidad de la misma forma que se notifica a este evento tambien'Esto nos introduce con otro problema. Solo se nos notifica que el componente va a ser destruido si es propiedad de la misma forma. Es posible tener nuestra propiedad punto a los componentes de otras formas (o incluso sin un dueño en todo), y cuando estos componentes son destruidos no somos notificados. Sin embargo, de nuevo hay una solucion. TComponent presenta un metodo llamado 'FreeNotification'. El proposito de FreeNotification es decir el componente (FocusControl) que nos mantenga en mente cuando es destruido. Una aplicacion tendria este aspecto
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TSimpleExample = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FFocusControl: TWinControl
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp procedimiento de Notificacion(AComponent: TComponent
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp Operacion: TOperation) reemplazar
& nbsp & nbsp & nbsp & nbsp procedimiento SetFocusControl(const Valor: TWinControl) virtual
& nbsp & nbsp publico
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad FocusControl: TWinControl leer FFocusControl escribir SetFocusControl
& nbsp & nbsp fin
procedimiento TSimpleExample.SetFocusControl(const Valor: TWinControl)
begin
& nbsp & nbsp si Valor <> FFocusControl entonces
& nbsp & nbsp begin
& nbsp & nbsp & nbsp & nbsp si Asignado(FFocusControl)
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FFocusControl.RemoveFreeNotification(Auto)
& nbsp & nbsp & nbsp & nbsp FFocusControl := Valor
& nbsp & nbsp & nbsp & nbsp si Asignado(FFocusControl) entonces
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp FFocusControl.FreeNotification(Auto)
& nbsp & nbsp final
fin
procedimiento TSimpleExample.Notificacion(AComponent: TComponent
& nbsp & nbsp Operacion : TOperation)
begin
& nbsp & nbsp si (Operacion = opRemove) y
& nbsp & nbsp & nbsp & nbsp & nbsp (AComponent = FocusControl)
& nbsp & nbsp & nbsp & nbsp FFocusControl := nil
fin
& nbsp & nbsp & nbsp & nbsp |
Cuando la configuracion de nuestro FocusControl de la propiedad en primer lugar comprobar si ya esta configurado para un componente. Si ya esta configurado, necesitamos decirle a la del componente original que ya no necesitamos saber cuando es destruido. Una vez que nuestra propiedad se ha fijado el nuevo valor informamos el nuevo componente que se requiere una notificacion cuando se libera. El resto de nuestro codigo sigue siendo el mismo que el componente que se hace referencia todavia llama a nuestro metodo de Notificacion. Marca Esta seccion es muy sencillo y no tomara mucho tiempo para cubrir. No me cabe duda de que usted ya esta familiarizado con la creacion de sus propios tipos ordinales.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TComponentOption = (coDrawLines,
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp coDrawSolid,
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp coDrawBackground)
& nbsp & nbsp & nbsp & nbsp |
Propiedades de este tipo se mostrara una lista desplegable con una lista de todos los valores posibles, pero a veces se necesitan para establecer una combinacion de muchos (o todos) de estos valores. Esto es, se establece entran en juego
& nbsp & nbsp & nbsp & nbsp Tipo
& nbsp & nbsp TComponentOption = (coDrawLines,
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp coDrawSolid,
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp & nbsp coDrawBackground)
& nbsp & nbsp TComponentOptions = set TComponentOption
& nbsp & nbsp & nbsp & nbsp |
la Publicacion de una propiedad de tipo TComponentOptions resultaria en un [ ] aparece al lado de nuestro nombre de la propiedad. Cuando usted haga clic para expandir la propiedad, usted vera una lista de opciones. Para cada elemento en TComponentOption vera una propiedad Booleana, puede incluir / excluir elementos de su conjunto estableciendo su valor a True / False. es sencillo comprobar y modificar elementos en un conjunto de dentro de nuestro componente como tal.
& nbsp & nbsp & nbsp & nbsp si coDrawLines en OurComponentOptions
& nbsp & nbsp entonces DrawTheLines
& nbsp & nbsp & nbsp & nbsp |
o
& nbsp & nbsp & nbsp & nbsp procedimiento Tuncomponente.SetOurComponentOptions(const Valor: TComponentOptions)
begin
& nbsp & nbsp si (coDrawSolid en Valor) y
& nbsp & nbsp (coDrawBackground en valor)
& nbsp & nbsp & nbsp & nbsp {elevar una excepcion}
& nbsp & nbsp FOurComponentOptions := Valor
& nbsp & nbsp Invalidar
fin
& nbsp & nbsp & nbsp & nbsp |
Binario propiedades A veces es necesario escribir su propia transmision de rutinas para leer y escribir los tipos de propiedad (Esto es como el Delphi de lecturas / escrituras de las propiedades Top y Left para no visible en los componentes de la publicacion de las propiedades en el inspector de objetos). Por ejemplo, una vez me escribio un componente para dar forma a un formulario basado en una imagen de mapa de bits. Mi codigo en el momento de convertir un mapa de bits a una ventana de la region era muy lento y no ser, posiblemente, de cualquier uso en tiempo de ejecucion. Mi solucion fue convertir los datos en tiempo de diseño, y la secuencia de datos binarios que el resultado de la conversion. Para crear las propiedades binarias es un proceso de tres pasos. 1. Escribir un metodo para escribir los datos. 2. Escribir un metodo para leer los datos. 3. Decirle a Delphi que tenemos un binario de la propiedad, y de paso nuestra lectura / escritura de metodos.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TBinaryComponent = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FBinaryData : Puntero
& nbsp & nbsp & nbsp & nbsp FBinaryDataSize : DWord
& nbsp & nbsp & nbsp & nbsp procedimiento WriteData(S : TStream)
& nbsp & nbsp & nbsp & nbsp procedimiento ReadData(S : TStream)
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp procedimiento DefineProperties(Filer : TFiler) reemplazar
& nbsp & nbsp publico
& nbsp & nbsp & nbsp & nbsp constructor Create(AOwner : TComponent) reemplazar
& nbsp & nbsp fin
& nbsp & nbsp & nbsp & nbsp |
DefineProperties es llamado por Delphi cuando se necesita para transmitir nuestro componente. Todo lo que tenemos que hacer es reemplazar este metodo, y agregar una propiedad utilizando TFiler.DefineProperty o TFiler.DefineBinaryProperty.
& nbsp & nbsp & nbsp & nbsp procedimiento TFiler.DefineBinaryProperty(const Nombre: cadena
& nbsp & nbsp ReadData, WriteData: TStreamProc HasData: Boolean)
constructor TBinaryComponent.Create(AOwner: TComponent)
begin
& nbsp & nbsp heredado
& nbsp & nbsp FBinaryDataSize := 0
fin
procedimiento TBinaryComponent.DefineProperties(Filer: TFiler)
var
& nbsp & nbsp HasData : Boolean
begin
& nbsp & nbsp heredado
& nbsp & nbsp HasData := FBinaryDataSize <> 0
& nbsp & nbsp Archivador.DefineBinaryProperty('BinaryData',ReadData,
& nbsp & nbsp & nbsp & nbsp WriteData, HasData )
fin
procedimiento TBinaryComponent.ReadData(S: TStream)
begin
& nbsp & nbsp S. Leer(FBinaryDataSize, SizeOf(DWord))
& nbsp & nbsp si FBinaryDataSize > 0 entonces begin
& nbsp & nbsp & nbsp & nbsp GetMem(FBinaryData, FBinaryDataSize)
& nbsp & nbsp & nbsp & nbsp S. Leer(FBinaryData^, FBinaryDataSize)
& nbsp & nbsp fin
fin
procedimiento TBinaryComponent.WriteData(S: TStream)
begin
& nbsp & nbsp //Esto no se llama a si FBinaryDataSize = 0
& nbsp & nbsp S. Escritura(FBinaryDataSize, Sizeof(DWord))
& nbsp & nbsp S. Escritura(FBinaryData^, FBinaryDataSize)
fin
& nbsp & nbsp & nbsp & nbsp |
en primer lugar, se anulan DefineProperties. Una vez que hemos hecho esto podemos definir una propiedad binario con los valores - & nbsp & nbsp -BinaryData : El invisible nombre de la propiedad para ser usada. & nbsp & nbsp -ReadData : El procedimiento que se encarga de leer los datos. & nbsp & nbsp -WriteData : El procedimiento de los responsables de escribir los datos. & nbsp & nbsp -HasData : Si esto es falso, el WriteData procedimiento no es llamado. la Persistencia Una breve explicacion de la persistencia es en el orden que nos vamos a referir en las siguientes secciones. La persistencia es lo que hace posible que Delphi para leer y escribir las propiedades de todos sus componentes. TComponent se deriva de una clase que se llama TPersistent. TPersistent es simplemente un Delphi clase capaz de tener sus propiedades leido y escrito en Delphi, lo que significa que cualquier descendientes de TPersistent tambien tienen esta misma capacidad. Colecciones a Medida que el progreso a traves de este articulo vamos a cubrir propiedades de componente de mayor complejidad. Las colecciones son una de las mas complejas 'estandar' de Delphi tipos de propiedad. Si se le cae un TDBGrid en un formulario y un vistazo a sus propiedades en el Inspector de Objetos, usted vera una propiedad denominada 'Columnas'. Columnas es una propiedad de coleccion, cuando usted haga clic en el [..] boton, aparecera una pequeña ventana pop-up. Esta ventana es el estandar editor de propiedades para TCollection propiedades (y a los descendientes de TCollection). cada vez que usted haga clic en el boton 'Nuevo' se encuentra con un nuevo elemento añadido (una TColumn elemento), haga clic en el elemento que se seleccione en el Inspector de Objetos, de modo que puede alterar sus propiedades y eventos. Como se hace esto ? Las Columnas de la propiedad desciende de TCollection. TCollection es similar a una matriz, que contiene una lista de TCollectionItem. Porque TCollection es descendiente de TPersistent es capaz de transmitir a esta lista de elementos, del mismo modo, TCollectionItem es tambien descendiente de TPersistent y tambien pueden transmitir sus propiedades. Asi que lo que tenemos es una matriz-como elemento capaces de transmitir todos sus elementos y sus propiedades. La primera cosa a hacer a la hora de crear nuestra propia estructura basada en TCollection / TCollectionItem es definir nuestra CollectionItem. (Vease OurCollection.pas)
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TOurCollectionItem = clase(TCollectionItem)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FSomeValue : Cadena
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp funcion GetDisplayName : Cadena reemplazar
& nbsp & nbsp publico
& nbsp & nbsp & nbsp & nbsp procedimiento Assign(Fuente: TPersistent) reemplazar
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad SomeValue : Cadena
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer FSomeValue
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir FSomeValue
& nbsp & nbsp fin
& nbsp & nbsp & nbsp & nbsp |
Lo que hemos hecho aqui es crear un descendiente de TCollectionItem. Hemos añadido un token de propiedad llamada 'SomeValue', reemplaza el GetDisplayName (funcion para modificar el texto que se muestra en el editor por defecto), y finalmente reemplazado el metodo de Asignar a fin de permitir TOurCollectionItem a ser asignado a otro TOurCollectionItem. Si omitimos el paso final, a continuacion, el metodo de Asignar de nuestra Coleccion de clase no va a funcionar !
& nbsp & nbsp & nbsp & nbsp procedimiento TOurCollectionItem.Asignar(Fuente: TPersistent)
begin
& nbsp & nbsp si Fuente se TOurCollectionItem entonces
& nbsp & nbsp & nbsp & nbsp SomeValue := TOurCollectionItem(Fuente).SomeValue
& nbsp & nbsp persona
& nbsp & nbsp & nbsp & nbsp heredado //genera una excepcion
fin
funcion TOurCollectionItem.GetDisplayName: Cadena
begin
& nbsp & nbsp Resultado := Format('Elemento %d',[Index])
fin
& nbsp & nbsp & nbsp & nbsp |
La aplicacion de TOurCollection es mucho mas complejo, y requiere un poco de trabajo.
& nbsp & nbsp & nbsp & nbsp TOurCollection = clase(TCollection)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FOwner : TComponent
& nbsp & nbsp protegido
& nbsp & nbsp & nbsp & nbsp funcion GetOwner : TPersistent reemplazar
& nbsp & nbsp & nbsp & nbsp funcion GetItem(Index: Integer): TOurCollectionItem
& nbsp & nbsp & nbsp & nbsp procedimiento SetItem(Indice: Valor Entero:
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp TOurCollectionItem)
& nbsp & nbsp & nbsp & nbsp procedimiento Update(Elemento: TOurCollectionItem)
& nbsp & nbsp publico
& nbsp & nbsp & nbsp & nbsp constructor Create(AOwner : TComponent)
& nbsp & nbsp & nbsp & nbsp funcion Agregar : TOurCollectionItem
& nbsp & nbsp & nbsp & nbsp funcion Insertar(Index: Integer): TOurCollectionItem
& nbsp & nbsp & nbsp & nbsp propiedad Articulos[Index: Integer]: TOurCollectionItem
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer GetItem
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir SetItem
& nbsp & nbsp fin
& nbsp & nbsp & nbsp & nbsp |
Hay una serie de elementos para cubrir con base en lo anterior la declaracion de la clase, asi que vamos a empezar desde la parte superior y cubrir cada una a su vez. GetOwner es un metodo virtual introducido en TPersistent. Este debe ser reemplazado como el codigo predeterminado para este metodo devuelve Nil. En nuestra aplicacion podemos modificar el constructor para recibir un solo parametro (AOwner : TComponent). Guardamos este parametro en FOwner, que luego pasa como el resultado de GetOwner (TComponent desciende de TPersistent, por lo tanto, es un resultado valido de tipo).
& nbsp & nbsp & nbsp & nbsp constructor TOurCollection.Create(AOwner: TComponent)
begin
& nbsp & nbsp heredado Crear(TOurCollectionItem)
& nbsp & nbsp FOwner := AOwner
fin
funcion TOurCollection.GetOwner: TPersistent
begin
& nbsp & nbsp Resultado := FOwner
fin
& nbsp & nbsp & nbsp & nbsp |
No solo no se Cree el dueño de la tienda (que es necesaria para el Inspector de Objetos para que funcione correctamente), tambien le dice Delphi ¿que clase de nuestro CollectionItem esta llamando 'heredado Crear(TOurCollectionItem)'. GetItem / SetItem se declaran de la misma manera como lo son en TCollection, pero en lugar de trabajar en TCollectionItem que trabajar en nuestra nueva clase TOurCollectionItem. Estos son utilizados en nuestros 'Elementos' de la propiedad mas adelante. Actualizacion como es arriba es una recta hacia adelante sustitucion de la original, trabajando en nuestro nuevo CollectionItem clase en su lugar. Añadir / Insertar son responsables de añadir elementos a la lista, estos han sido reemplazados para devolver objetos de la clase correspondiente. por ultimo, un 'Elementos' de la propiedad se introdujo para sustituir los Elementos originales de la propiedad, de nuevo, de modo que nos devuelve un resultado de TOurCollectionItem en lugar de TCollectionItem que nos ahorra el problema innecesario de este el resultado de cada tiempo. por ultimo un ejemplo de la implantacion de este tipo de propiedad en un componente de la nuestra.
& nbsp & nbsp & nbsp & nbsp TCollectionComponent = clase(TComponent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FOurCollection : TOurCollection
& nbsp & nbsp & nbsp & nbsp procedimiento SetOurCollection(const Valor:
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp TOurCollection)
& nbsp & nbsp publico
& nbsp & nbsp & nbsp & nbsp constructor Create(AOwner : TComponent) reemplazar
& nbsp & nbsp & nbsp & nbsp destructor Destruir reemplazar
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad OurCollection : TOurCollection
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer FOurCollection
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir SetOurCollection
& nbsp & nbsp fin
& nbsp & nbsp & nbsp & nbsp |
es tan simple como eso. Una vez que nuestro TCollection clase esta escrito todo el trabajo duro esta hecho. Nuestro constructor crea la clase de coleccion, el destructor de la destruye, y SetOurCollection hace esto.
& nbsp & nbsp & nbsp & nbsp constructor TCollectionComponent.Create(AOwner: TComponent)
begin
& nbsp & nbsp heredado
& nbsp & nbsp FOurCollection := TOurCollection.Create(Self)
fin
destructor TCollectionComponent.Destruir
begin
& nbsp & nbsp FOurCollection.Libre
& nbsp & nbsp heredado
fin
procedimiento TCollectionComponent.SetOurCollection(
& nbsp & nbsp const Valor: TOurCollection)
begin
& nbsp & nbsp FOurCollection.Asignar(Valor)
fin
& nbsp & nbsp & nbsp & nbsp |
Como se menciono antes, la (Auto) paso a la TOurCollectionItem.Crear es almacenado en TOurCollection del FOwner variable que se pasa como el resultado de GetOwner. Un punto a destacar aqui es que en SetOurCollection no trabajamos FOurCollection := valor como son la sustitucion de los objetos (los objetos son simplemente punteros), le asignamos nuestra propiedad en el valor. mas Tarde las versiones de Delphi hacer esto mas simple todavia. En lugar de tener que reemplazar GetOwner en nuestra clase de Coleccion, ahora podemos derivar nuestra Coleccion de TOwnedCollection lugar. TOwnedCollection es un contenedor para TCollection con este trabajo hecho por nosotros. Sub-propiedades Antes en este articulo vimos como era posible crear una propiedad expansible. La limitacion de la anterior tecnica fue que cada uno de los sub-elemento aparecio como una propiedad Booleana. En la siguiente seccion se muestra como crear ampliable propiedades que puede contener cualquier tipo de propiedad. Si un componente requiere una propiedad que es un tipo de registro, esto puede ser facilmente implementado por la exposicion de cada una de las propiedades por separado. Sin embargo, si nuestro componente debe presentar dos o mas de las propiedades del mismo tipo de complejo de nuestro Inspector de Objetos de la vista de repente se vuelve muy complicado. La respuesta es crear una estructura compleja (por igual a un registro o de un objeto) y la publicacion de esta estructura como una propiedad siempre que sea necesario. El problema obvio es que Delphi no sabe como mostrar esta propiedad a menos que se lo indique. La creacion de un completo soplado editor de propiedades (con los cuadros de dialogo, etc) seria una exageracion, asi que, por suerte Delphi ha proporcionado una solucion. Como se menciono anteriormente, Delphi interna de streaming se basa en el TPersistent clase. El primer paso es derivar nuestra compleja estructura de esta clase.
& nbsp & nbsp & nbsp & nbsp tipo
& nbsp & nbsp TExpandingRecord = clase(TPersistent)
& nbsp & nbsp privada
& nbsp & nbsp & nbsp & nbsp FIntegerProp : Integer
& nbsp & nbsp & nbsp & nbsp FStringProp : Cadena
& nbsp & nbsp & nbsp & nbsp FCollectionProp : TOurCollection
& nbsp & nbsp & nbsp & nbsp procedimiento SetCollectionProp(const Valor:
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp TOurCollection)
& nbsp & nbsp publico
& nbsp & nbsp & nbsp & nbsp constructor Create(AOwner : TComponent)
& nbsp & nbsp & nbsp & nbsp destructor Destruir reemplazar
& nbsp & nbsp & nbsp & nbsp procedimiento Assign(Fuente : TPersistent) reemplazar
& nbsp & nbsp publicado
& nbsp & nbsp & nbsp & nbsp propiedad IntegerProp : Integer
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer FIntegerProp
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir FIntegerProp
& nbsp & nbsp & nbsp & nbsp propiedad StringProp : Cadena
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp leer FStringProp
& nbsp & nbsp & nbsp & nbsp & nbsp & nbsp escribir FStringProp
& nbsp & nbsp __
Componente de la escritura, parte 2
By Consejos Y Trucos Componente de la escritura, parte 2 : Multi-millones de consejos para hacer su vida más fácil. Consejos Y Trucos www.consejosytrucos.net Ciempozuelos, Madrid Extramuros 82 ES-M 28350 Spain 674 192 969 |
|