Curso de C++ Builder


Acceso a bases de datos

TField



Acceso a las columnas de un conjunto de datos

La clase TField representa un campo (una columna) en un conjunto de datos. Por medio de esta clase pueden establecer los atributos de un campo (tipo, tamaño, índice, si es un campo calculado o de búsqueda, si es obligatorio...), y también se puede acceder a su valor a través de propiedades como AsString o AsInteger.

TField es una clase base de la que se derivan otras muchas. Sus descendientes incluyen a TStringField, TIntegerField, TFloatField y TDateField, entre otros muchos.

TField
Nuevos en C++Builder 4:
TField

Acceso a los valores de los campos

Para recuperar o establecer el valor de un campo podemos usar:

Ejemplo
TablaApellidos->Value = "Pérez Martín";

Tabla->Fields->Fields[0]->Value = "Pérez Martín";

Tabla->FieldByName("Apellidos")->Value = "Pérez Martín";

El Editor de Campos [Fields Editor]

Desde el menú contextual de cualquier descendiente de TDataSet (vg: TTable o TQuery) se permite el acceso al "Fields Editor" en tiempo de diseño. De esta forma se pueden especificar aquellos campos que se quieren incluir en el conjunto de datos y sus propiedades.

Ejemplo
  • Seleccionar del menú contextual (botón derecho del ratón) de cualquier TDataSet la opción Fields Editor.
  • Seleccionar Add Fields en el menú del Fields Editor.
  • Añadir los campos que deseemos utilizar.
  • Ver las propiedades de los campos en el Inspector de Objetos (p.ej. seleccionándolos en el Fields Editor).
  • Propiedades interesantes de TField

    Propiedad Descripción
    FieldName Nombre de la columna en la BD.
    DisplayLabel Texto descriptivo empleado por TDBGrid.
    Value Valor en la fila activa.
    IsNull Indica si el valor es nulo.
    DisplayFormat Personalización de la visualización.
    EditMask Control de la edición del campo.
    CustomConstraint Restricción en el valor del campo.
    ConstraintErrorMessage Mensaje de error asociado.
    ReadOnly Campo de sólo lectura

    Los eventos de TField

    Evento Descripción
    OnChange Cuando cambia el valor del campo.
    OnValidate Validación a nivel de campos.
    OnGetText Al visualizar valores.
    OnSetText Al editar valores.

    Uso de TField

    Visualizacion personalizada

    Definiendo la respuesta al evento GetText

    Seleccionar un campo de tipo entero y hacer que se visualice con números romanos.
    void __fastcall ...::tbFieldGetText
                         (TField *Sender, AnsiString &Text, bool DisplayText)
    {
     static AnsiString Unidades[10] = {"", "I", "II", "III", "IV",
                                       "V", "VI", "VII", "VIII", "IX"};
     static AnsiString Decenas[10] = {"", "X", "XX", "XXX", "XL",
                                      "L", "LX", "LXX", "LXXX", "XC"};
     static AnsiString Centenas[10] = {"", "C", "CC", "CCC", "CD",
                                       "D", "DC", "DCC", "DCCC", "CM"};
     static AnsiString Miles[4] = {"", "M", "MM", "MMM"};
     
     if (Sender->AsInteger > 3999) {
        Text = "Infinitum";  // Hay que ser consecuentes con el lenguaje
     } else {
        int i = Sender->AsInteger;
        Text = Miles[i / 1000] 
             + Centenas[i / 100 % 10]
    	 + Decenas[i / 10 % 10]
    	 + Unidades[i % 10];
     }
    }
    

    Restricciones a nivel de campos

    1. Definiendo la respuesta al evento SetText:

    Forzar que las iniciales de los nombres sean siempre letras mayúsculas
    void __fastcall ...::tbFieldSetText(TField *Sender, const AnsiString Text)
    {
     int        i;
     AnsiString S = Text;
    
     for ( i=1; i<=S.Length(); i++)
         if ( i==1 || S[i-1]==' ')
            CharUpperBuff(&S[i], 1);
    
     Sender->AsString = S;
    }
    

    2. Utilizando el evento OnValidate:

    Un nombre propio no puede incluir dígitos ni otros simbolos
    void __fastcall ...::tbFieldValidate(TField *Sender)
    {
      AnsiString S = Sender->AsString;
    
      for (int i = S.Length(); i > 0; i--)
          if (S[i] != ' ' && !IsCharAlpha(S[i]))
             DatabaseError("Carácter no permitido en nombre propio", 0);
    }
    

    3. Controlando el valor que puede tomar un campo mediante sus propiedades EditMask y CustomConstraint. Cuando se utiliza esta última, lo normal es definir también ConstraintErrorMessage para que el usuario sepa por qué no puede darle determinados valores a un campo.

    Valores no nulos
    CustomConstraint = value is not null
    
    Código postal
    EditMask = !99999;1;_
    
    Teléfono o fax
    EditMask = !999 99 99 99;0;_
    
    Dirección de correo electrónico
    CustomConstraint = value is null or value='' or value like '%_@%_.%_'
    

    Campos calculados

    Se crean con New field (Calculated) desde el menú contextual del editor de campos y se manejan a través del evento OnCalcFields, que se produce cada vez que se cambia o se modifica la fila activa del conjunto de datos (si está a true la propiedad AutoCalcFields del conjunto de datos).

    Campos de búsqueda [lookup fields]

    Se pueden crear con la opción New field (Lookup) del menú contextual del editor de campos. Se definen mediante las propiedades KeyFields, LookupDataset, LookupKeyFields y LookupResultField.

    Mediante LookupCache se pueden cargar los valores permitidos en la propiedad LookupList, la cual se puede actualizar llamando a RefreshLookupList.

    BLOBs: TBlobField

    Los campos de tipo BLOB [Binary Large OBject] en una base de datos se pueden utilizar para almacenar ficheros completos, imágenes, sonidos o cualquier otro tipo de información digitalizada. El contenido de este tipo de campos se puede modificar invocando al método LoadFromFile, mientras que su complementario (SaveToFile) nos permite recuperar la información almacenada en la base de datos.

    Imágenes en formato JPG (jpeg.hpp)
    void __fastcall ...::DataSourceImagenDataChange(TObject *Sender, TField *Field)
    {
      if (tbImagenesFoto->IsNull)
         Image->Picture->Graphic = NULL;
      else {
         std::auto_ptr BS(new TBlobStream(tbImagenesFoto, bmRead));
         auto_ptr Graphic(new TJPEGImage);
         Graphic->LoadFromStream(BS.get());
         Image->Picture->Graphic = Graphic.get();
      }
    }
    


    Índice de la sección