Curso de C++ Builder


Acceso a bases de datos

Formulario maestro/detalle



  1. Crear la aplicación Inversiones (menú File | New | Application) y guardar sus ficheros en un directorio nuevo
    • Formulario principal: fichero FormInversiones.cpp
    • Proyecto: fichero Inversiones.bpr
  2. Configurar el formulario principal de la aplicación:
    • Name = frmInversiones
    • Caption = Gestión de inversiones
  3. Crear un módulo de datos dmInversiones (menú File | New | Data Module):
    • Fichero DataInversiones.cpp.
    • Name = dmInversiones.
    Modulo de datos

    Insertar dos componentes de tipo TTable (pestaña BDE) y dos de tipo TDataSource (pestaña Data Access):
    • Tabla maestro:
      • Name = TableClients
      • DatabaseName = BCDEMOS
      • TableName = clients.dbf
    • DataSource maestro:
      • Name = dsClients
      • DataSet = TableClients
    • Tabla detalle:
      • Name = TableHoldings
      • DatabaseName = BCDEMOS
      • TableName = holdings.dbf
    • DataSource detalle:
      • Name = dsHoldings
      • DataSet = TableHoldings
  4. Añadir controles al formulario principal:
    • Botón para terminar (BitBtn): Kind=bkClose.
    • TDBNavigator personalizado (pestaña Data Controls): Hints & VisibleButtons.

      Personalización del TDBNavigator

    • 2 componentes de tipo TDBGrid (pestaña Data Controls), a los que llamaremos gridClients y gridHoldings.
  5. Para poder usar el módulo de datos desde el formulario, hemos de incluir fichero de cabecera correspondiente al módulo de datos, a mano (#include "DataInversiones.h") o utilizando la opción correspondiente del menú (menú File | Include Unit Hdr, Alt+F11).

    Include unit header...

  6. Enlazar los controles "data-aware" a los correspondientes componentes de tipo TDataSource (que están en el módulo de datos):
    • DBNavigator: DataSource = dmInversiones->dsClients.
    • Rejilla "gridClients": DataSource = dmInversiones->dsClients.
    • Rejilla "gridHoldings": DataSource = dmInversiones->dsHoldings.
  7. Como la foto del cliente no podemos verla en la rejilla, añadimos un componente de tipo TDBImage (pestaña Data Controls y lo enlazamos al DataSource correspondiente, de forma que nuestro formulario queda de la siguiente forma:


  8. Hasta ahora hemos estado trabajando son dos tablas independientes. Para establecer la relación maestro/detalle entre las dos tablas tenemos que hacer lo siguiente:
    • Establecer la propiedad MasterSource de la tabla detalle: TableHoldings->MasterSource = dsClients
    • Fijar la condición de la reunión a través de la propiedad MasterFields de la tabla detalle:


  9. Ya sólo nos falta hacer que se visualicen los datos cuando se ejecute la aplicación:
    • En tiempo de diseño: Table...->Active = true.
    • En tiempo de ejecución: Table...->Open() & Table...->Close() al producirse los eventos adecuados...
  10. Finalmente, podemos compilar nuestro proyecto para obtener la siguiente aplicación:


Posibles mejoras




De esta forma conseguimos que el usuario no tenga que saberse de memoria los códigos de las empresas que cotizan en bolsa para poder utilizar nuestra aplicación (un fallo más común en la realidad de lo que gustaría pensar).


Manipulación de conjuntos de datos

Calcular y mostrar, bajo demanda, el número de acciones y el importe total de las inversiones del cliente actual:


Pasos a seguir:

  1. Insertar un botón (Name = buttonResumen, Caption = Resumen)
  2. Insertar 6 etiquetas con los valores siguientes para las propiedades (Name,Caption): (Label1, Cliente:), (Label2, Acciones:), (Label3, Importe:), (LabelNombre,-vacío-), (LabelAccsiones,-vacío-), (LabelImporte,-vacío-).
  3. Insertar un control de tipo Bevel que enmarque a todas las etiquetas anteriores.
  4. Implementar el gestor del evento que se desencadena al pulsar sobre el botón "buttonResumen":

Evento correspondiente a la pulsación del botón
void __fastcall TfrmInversiones::buttonResumenClick(TObject *Sender)
{
  int   acciones;
  float importe;

  dmInversiones->CalcularResumen (acciones, importe);

  Label1->Visible = true;
  Label2->Visible = true;
  Label3->Visible = true;

  LabelNombre->Caption = dmInversiones->TableClients->FieldByName("FIRST_NAME")->AsString
                 + " " + dmInversiones->TableClients->FieldByName("LAST_NAME")->AsString;

  LabelAcciones->Caption = IntToStr(acciones);

  LabelImporte->Caption = FloatToStr(importe);
}

donde CalcularTotal() lo definimos como un método de la clase que define el módulo de datos:

Recorrido secuencial de un conjunto de datos
void TdmInversiones::CalcularResumen (int &acciones, float &importe)
{
  acciones = 0;
  importe = 0;

  TableHoldings->First();

  while (!TableHoldings->Eof) {

     acciones += TableHoldings->FieldByName("SHARES")->AsInteger;

     importe += TableHoldings->FieldByName("SHARES")->AsInteger
              * TableHoldings->FieldByName("PUR_PRICE")->AsFloat;

     TableHoldings->Next();
  }
}

Posibles mejoras

Evento OnCalcFields
void __fastcall TdmInversiones::TableClientsCalcFields(TDataSet *DataSet)
{
  QueryResumen->ParamByName("ACCT_NBR")->Value = TableClientsACCT_NBR->Value;
  QueryResumen->Open();

  TableClientsACCIONES->AsInteger = QueryResumen->Fields->FieldByNumber(1)->AsInteger;
  TableClientsIMPORTE->AsFloat = QueryResumen->Fields->FieldByNumber(2)->AsFloat;

  QueryResumen->Close();

  TableClientsNOMBRE->AsString = TableClientsFIRST_NAME->AsString.Trim()
                         + " " + TableClientsLAST_NAME->AsString.Trim();
}

donde QueryResumen es una consulta SQL auxiliar que utilizamos para calcular los totales en función del número de cuenta del cliente:

Consulta SQL auxiliar
select sum(shares), sum(shares*pur_price)
  from holdings.dbf
  where acct_nbr=:acct_nbr

De esta forma el usuario no tiene que hacer nada para que la aplicación muestre toda la información:

- Código fuente -


Índice de la sección