Monografias.com > Sin categoría
Descargar Imprimir Comentar Ver trabajos relacionados

Programación con Visual C++ (página 2)




Enviado por coriadavid



Partes: 1, 2

  1. EL ENTORNO DE DESARROLLO
    VISOR DE PROYECTOS

El Visor de Proyectos es una ventana a través
de la que podemos visualizar el contenido de los proyectos,
accedemos a la misma desde el menú "Ver" y la
opción "Proyecto".
Está formada por 3 carpetas que nos permiten visualizarlos
desde distintos puntos de vista:

  • ClassView, o Visor de clases, representa el
    proyecto con
    las clases que lo componen. Desde aquí podremos
    añadir miembros datos o
    funciones
    fácilmente.
  • ResourceView, o Visor de recursos, que
    permite añadir/modificar/eliminar recursos de la
    aplicación.
  • FileView, o Visor de ficheros, que representa
    el proyecto mediante la lista de ficheros fuente que lo
    componen.

Por último aparece también la carpeta
InfoView que permite un rápido acceso a la ayuda en
línea.

Cada una de estas funcionalidades se utilizarán en
función de la tarea a realizar. La gestión
y tratamiento de los recursos
sólo se puede hacer mediante ResourceView, mientras
que ClassView y FileView son casi similares en
cuanto a su objetivo
último: el mantenimiento
del código del programa.

  1. LA LIBRERÍA DE CLASES MFC –
    INTRODUCCIÓN.

A continuación, y siguiendo en todo momento el
código de la aplicación básica que acabamos
de generar, procederemos a presentar las clases mas utilizadas de
la MFC. Esta librería está compuesta por cientos de
clases distintas, que desde el punto de vista funcional, las
podemos dividir en 4 grupos:

  1. Clases orientadas al interfaz de usuario, representan
    ventanas, menús, diálogos, etc.
  2. Clases de propósito general, representando
    ficheros, strings, datos de fecha
    y hora, etc.
  3. Clases orientadas a bases de datos,
    representando tanto bases de datos
    como conjuntos de
    registros
    seleccionados después de una consulta sobre una tabla,
    etc.
  4. Clases para manejo de excepciones, para control
    avanzado de errores de ejecución.
  1. Filosofía de trabajo con la
    MFC.

El hecho de utilizar una librería de clases como la MFC
añade complejidad al desarrollo e
impone una serie de normas de
programación a las que regirse. La
complejidad añadida deriva de la necesidad de que el
programador ahora no sólo debe controlar C/C++, sino que
además debe conocer las clases de la MFC para poder utilizar
su potencia.

Entran aquí en juego algunos
conceptos que ya conocemos:

  • Herencia, Un buen número de las clases de la
    MFC son "no instanciables", es decir, no podemos crear
    objetos de esa clase con lo que no podremos utilizarla
    directamente. Esto significa que el programador deberá
    en muchos casos derivar sus propias clases de alguna de
    la MFC (estas clases "prohibidas" suelen ser
    abstracciones que dan pie a polimorfismos).
    Además debemos saber que clase es la mas óptima
    para que nos sirva de clase base; por ejemplo: se debe saber
    que la clase MFC CWinApp es la que da soporte a las
    aplicaciones Windows, y
    que toda aplicación debe derivar su propia
    versión de la clase para poder
    funcionar (en realidad, un programa MFC
    comienza con la creación de un objeto de ese tipo y
    finaliza con la destrucción del mismo). También
    deberemos saber que si lo que queremos es obtener una ventana
    de diálogo, deberemos derivar nuestra propia clase desde
    CDialog (que es una clase especializada para ello), en
    vez de desde CWnd (que representa a una clase mas
    genérica y presentaría muchos problemas),
    por ejemplo, CDialog soporta que su plantilla haya sido
    dibujada en los recursos de la aplicación (al estilo de
    un formulario de Visual Basic,
    …) mientras que CWnd no, lo que nos obligaría a
    pintar los botones con código duro (programar su
    tamaño, posición en pixeles dentro de la ventana
    padre …), aunque no sería imposible. En
    definitiva, a la hora de derivar clases de la MFC debemos tener
    en cuenta el concepto de
    especialización para obtener una programación más sencilla.
  • Polimorfismo. Pero la mayor potencia de
    la MFC reside en las funciones
    polimórficas (virtuales). El mecanismo de herencia no
    sería útil si no se pudiese redefinir el comportamiento por defecto de las clases de la
    MFC. Por ejemplo, supongamos que hemos creado un diálogo
    (derivando una clase desde CDialog) con nuestro propio diseño, supongamos que tiene unos campos
    que deseamos inicializar con los datos de un empleado para que
    aparezcan en pantalla, en este caso debemos ser capaces de
    definir nuestro propio método
    de inicialización. Esto es posible gracias a que este
    método
    (en concreto
    denominado OnInitDialog) es definido como virtual
    dentro de la clase base CDialog, lo que da lugar a una
    función polimórfica. Así, si en nuestra
    clase derivada de CDialog redefinimos ese método
    OnInitDialog, nos aseguraremos que el procedimiento
    de inicialización que se ejecutará será el
    nuestro. En definitiva, las dos clases (CDialog como clase base
    y la nuestra como derivada) responden al mismo mensaje
    (OnInitDialog) pero de distinta manera (por que no
    comparten el método).

Esta es la filosofía de trabajo que debemos seguir:
derivar nuestras clases de la clase MFC mas especializada en
función de lo que queramos, y utilizar las funciones
virtuales que tenga para conseguir el comportamiento
deseado.

  1. Para conseguir una mejor visión del
    funcionamiento de la MFC, nos basaremos en el código
    generado en el punto 5.

    1. La clase CWinApp
  2. Las clases básicas para
    interfaz de usuario.

Representa una aplicación Windows. Cada
programa debe tener un objeto global o estático (es decir,
que exista durante todo el programa) de una clase propia derivada
de CWinApp. De hecho, otra característica de la programación
basada en MFC es que el código carece de programa
principal (punto inicial de ejecución como la
función "main" de C/C++ para DOS, UNIX, etc.), la
ejecución comienza con la creación del objeto
CWinApp.

En realidad, es la MFC la que provee una función
principal estándar WinMain (este es el nombre que toma
para las aplicaciones Windows) que utilizarán todos los
programas. Los
pasos básicos que sigue son tres: inicialización
del programa, entrada en el bucle de mensajes y
finalización del programa. Veámoslo más en
detalle.

  • Inicialización del programa. Se obtiene en
    dos fases distintas: inicialización de la
    aplicación e inicialización de la
    instancia de la aplicación. Para entender esto
    tenemos que tener en cuenta que los programas
    Windows pueden ser "multi-instanciables", podemos tener varios
    ejemplares del mismo programa ejecutándose a la misma
    vez. Los ejemplos mas claros son aplicaciones como el bloc de
    notas (notepad) o cualquier utilidad de
    conexión remota (telnet). En
    definitiva, si queremos obtener programas multi-instanciables
    tenemos que distinguir operaciones de
    inicialización que servirían a todos los
    ejemplares y que por tanto se deberían realizar una sola
    vez, de aquellas que son específicas a cada ejemplar
    (como crear cada ejemplar su ventana principal).
  • Bucle de mensajes. Es la parte central de la
    ejecución, no finaliza hasta que no se cierra la ventana
    principal.
  • Finalización de la instancia.
    Permitirá liberar recursos, cerrar ficheros de trabajo,
    confirmar operaciones,
    etc.

Los detalles mas importantes de la clase CWinApp son los
siguientes:

  1. Miembros datos públicos -> Destacar:
  • m_pszAppName, contiene el nombre de la
    aplicación.
  • m_pMainWnd, contiene un puntero (referencia) a la
    ventana principal de la aplicación.
  • m_hInstance, identificador de la instancia del
    programa que se está ejecutando.
  • m_hPrevInstance, identificador de la instancia
    previa del programa (0 si no hay instancia previa). Sirve
    para saber si se deben realizar tareas de
    "inicialización de aplicación" (ver
    arriba).
  • m_lpCmdLine, línea de comando con la que se
    llamó al programa (argumentos).
  1. Constructor CWinApp -> Recibe un sólo
    parámetro con el nombre de la aplicación (por
    defecto llevará NULL, nulo).
  2. Miembros funciones públicos ->
    La funcionalidad de esta clase, como siempre, reside en
    funciones virtuales que se pueden redefinir; destacan las
    siguientes:
  • InitApplication -> Invocada por el sistema
    automáticamente cuando se ejecuta la primera instancia
    de un programa (cuando no existe instancia previa).
  • InitInstance -> Invocada por el sistema
    para cualquier instancia del programa. Se suelen realizar
    operaciones como la de creación de la ventana
    principal, etc.
  • Run -> Que realiza el bucle de mensajes por
    defecto. En la mayoría de los casos este bucle es
    suficiente, con lo que no tendremos por que redefinirlo.
  • ExitInstance -> Invocada por el sistema
    después de cerrarse su ventana principal.

Comparando el código generado para nuestra primera
aplicación con lo expuesto en este punto podemos comenzar
a entender como funcionan las cosas en el mundo MFC.

  1. 2 El interfaz Documento/Vista

El estándar Documento/Vista es una manera de enfocar el
desarrollo de aplicaciones para Windows. Se basa en los
siguientes conceptos:

  1. Documento, cualquier tipo de información que se presenta sobre una
    ventana, podría ser tanto una hoja de
    cálculo, como una base de datos o
    algún tipo de gráfico.
  2. Vista (view), ventana que presenta el documento.
    Cada vista presenta un único documento.
  3. Ventana marco (frame window), que contiene a la
    ventana vista en su área cliente.

Figura 1.- Interfaz documento/vista

De esta manera, cualquier tipo de información se puede interpretar como un
documento, que se presenta al usuario mediante una vista, que se
inscribe dentro de una ventana marco. Mientras la vista se ocupa
solamente de representar el documento, la ventana marco se puede
ocupar del tratamiento del menú.

AppWizard genera todo su código basándose
en este estándar. Una aplicación SDI sólo
podrá tener abierto un documento (la ventana principal es
también la ventana marco), mientras que una MDI
podrá tener varios abiertos simultáneamente
(aquí la ventana principal puede contener varias marcos
con vistas). Sin embargo este enfoque no es el mas idóneo
para un buen número de aplicaciones Windows SDI donde la
ventana principal no sirve sino como contenedor del menú,
y la representación o el manejo de los datos de la
aplicación se suele realizar a través de
diálogos. Si es sin embargo mas útil en el caso de
las aplicaciones MDI donde si que las ventanas marcos se utilizan
como formularios
usuales, es decir, como ventanas para presentación de
datos.

Figura 2.- Detalle de aplicación MDI

Observando la figura basada en el entorno de desarrollo
de Visual C++,
vemos que la ventana principal contiene dos ventanas marcos, la
primera representa en su vista el contenido del workspace que
tenemos abierto, mientras la segunda está representando un
fichero de código fuente CPP.

Las clases MFC en las que se apoya el interfaz
Documento/Vista son las siguientes:

  1. Clase CDocument-> funcionalidad
    básica para documentos de
    usuario. Un documento es un objeto que almacena cualquier tipo
    de datos. Es una clase abstracta de la que tendremos que
    derivar nuestros propios documentos.
  2. Clase CView -> Ventana vista que
    presenta un documento. Es una ventana "especial" que no
    contiene ni bordes ni título ni barra de menú,
    orientada a circunscribirse dentro de otra ventana marco.
    Existen otras clases derivadas de
    ésta que presentan mayor
    especialización:
  • CScrollView, es una vista con soporte a las
    barras de scroll.
  • CFormView, vista formulario, con controles
    al estilo de los diálogos.
  • CEditView, vista orientada a la
    edición de textos.
  • CRecordView, vista orientada a la
    visualización de bases de datos.
  1. Clase CDocTemplate -> Clase abstracta que
    aporta la funcionalidad básica para plantillas SDI o
    MDI. Al ser una clase abstracta no la podremos utilizar
    directamente, tendremos que utilizar sus clases derivadas:
    CSingleDocTemplate y CMultiDocTemplate.
  2. Clase CSingleDocTemplate ->
    derivada de CDocTemplate representa la plantilla de
    interfaz SDI. Define la relación existente entre un
    documento (CDocument), una vista (CView, …) y una
    ventana marco que será la ventana principal.
  3. Clase CMultiDocTemplate->
    derivada de CDocTemplate representa la plantilla para
    interfaz MDI. Define la relación entre un documento, su
    vista y la ventana marco que ventana MDI hija.

Toda aplicación que se base en el Documento/Vista
debe registrar en el sistema las plantillas de documento que
soporta antes de poder utilizarlas, lo que se realiza a
través de la función
CWinApp::AddDocTemplate. Así, una aplicación
SDI, que debe soportar una única plantilla de documento,
debe crear un objeto CSingleDocTemplate (donde se define
la relación entre documento, vista y ventana marco) y
registrarlo mediante el método anterior. Una vez realizado
esto bastará con invocar la función
CDocTemplate::OpenDocumentFile() del objeto recién
creado para conseguir que se visualice la ventana principal de la
aplicación, con su vista presentando el documento
especificado (el enfoque en aplicaciones MDI es algo distinto y
se revisará posteriormente). Estas operaciones se
introducirán dentro del InitInstance de la
aplicación.

De todas maneras, en contra de lo que hemos dicho antes,
no es difícil adaptar cualquier aplicación al
protocolo
requerido por el interfaz documento vista, sin mucho impacto en
la misma, gracias a que la mayoría de las funcionalidades
están predefinidas por defecto.

  1. 2. 3. La ventana básica
    CWnd

Es una de las clases mas importantes de la MFC ya que
contiene las funcionalidades básicas de todas las clases
de ventanas Windows. Como siempre, al ser una
abstracción, no está muy orientada a la
utilización directa, mas bien siempre tenderemos a
utilizar alguna de sus clases derivadas, mas especializadas,
como CFrameWindow (ventana principal de
aplicación) o CDialog (para ventanas de
diálogo).

Pero su principal interés
reside en que es la clase responsable del funcionamiento del
mecanismo de paso de mensajes de Windows. Éste queda
oculto por lo que se llama en la MFC mapa de mensajes.
El mapa de mensajes de una clase de ventana recoge la
asociación entre el mensaje recibido del sistema y la
función que se ejecutará como respuesta. Todas
estas funciones de respuesta (métodos
de clase) son funciones virtuales que por tanto se pueden
redefinir en todas las clases derivadas.

Supongamos que estamos construyendo una aplicación la
cual queremos que antes de finalizar descargue cierto contenido
de memoria en un
fichero. Para ello deberíamos ser capaces de contestar
adecuadamente al mensaje WM_CLOSE que el sistema manda a la
ventana principal cuando se tiene que cerrar. El mapa de
mensajes de la clase CWnd especifica que la función de
respuesta será CWnd::OnClose(). Bastará
entonces con que en nuestra clase ventana principal redefinamos
una nueva versión de esa función heredada. No
hace falta que conozcamos de memoria todo el
mapa de mensajes por defecto de CWnd (nombres de las funciones
de respuesta, etc.), la utilización de AppWizard
automatiza todo este complejo tratamiento.

Los miembros datos y miembros funciones de esta clase son
muy numerosos y variados, los iremos comentando según
los vayamos utilizando.

7. 2. 4. Una ventana
principal – CFrameWnd

Derivando de CWnd, proporciona las funcionalidades
básicas de cualquier ventana principal de
aplicación. Incluye soporte de menús, barras de
estado y barra
de herramientas.
Las aplicaciones SDI derivarán de esta clase sus ventanas
principales. Entre sus características incluye título,
menú de sistema y borde redimensionable.

De sus miembros funciones destacan:

  • Create -> Función que permite crear una
    ventana física y asociarla con el objeto
    recién creado.
  • LoadFrame -> Función análoga a la
    anterior, per de mas alto nivel (exige menos parámetros)
    que adopta muchos comportamientos por defecto.

Derivando de CFrameWnd aparecen otras clases de ventanas mas
especializadas, son las siguientes:

  • CMDIFrameWnd-> Ventana principal para
    aplicaciones MDI.
  • CMDIChildWnd -> Ventanas MDI hijas (tienen la
    mayoría de las propiedades de cualquier ventana
    principal).
  1. 2.
    5.
    Las
    clases Vista

Como ya hemos comentado, la clase CView
proporciona la funcionalidad básica para ventanas que se
asocian a plantillas de documentos y que realizan tareas de
intermediarias entre el documento y el usuario. Es la responsable
de presentar la imagen del
documento y de interpretar las acciones del
usuario sobre el mismo (modificaciones, etc.). Entre estas
funcionalidades cabe destacar:

  • CView::OnInitialUpdate, función
    miembro que permite la inicialización de la vista con
    los datos del documento.
  • CView::OnUpdate, invocada ante cualquier
    modificación del documento, permite actualizar la vista
    antes de que se repinte.
  • CView::OnDraw, función de pintado de
    la vista (utilizada casi siempre para "documentos
    gráficos").
  • CView::GetDocument, que permite obtener una
    referencia al documento que se esta
    representando.

Las vistas mas especializadas se encuentran entre las
siguientes clases derivadas:

  • CEditView, donde la vista es una ventana de
    edición de texto.
  • CListView, donde la vista es una
    lista.
  • CFormView, donde la vista utiliza una
    plantilla de diálogo de los recursos de la
    aplicación (al estilo de los formularios
    tradicionales).
  • CRecordView, derivando de CFormView
    implementa además soporte para bases de datos,
    permitiendo asociar estáticamente campos de tablas con
    controles de la plantilla de diálogo que
    utiliza.
  1. 3 Clases básicas de propósito
    general.

Presentaremos a continuación algunas
de las clases de propósito general mas importantes y
utilizadas de la MFC.

  1. 3. 1
    La clase
    CString

La clase CString representa un string de
caracteres. Cualquier programador de C/C++ sabe lo tedioso que
puede ser el manejo de este tipo de dato ya que no está
reconocido como tal en el núcleo de C. Mientras que en
otros lenguajes de alto nivel el string de caracteres es un tipo
de dato autónomo que dispone de sus propios operadores
(asignación, concatenación, comparación,
etc.), en C/C++ el string se representa como una colección
(array) de caracteres (que el tipo de dato básico), esto
supone que cualquier operación sobre ellos se debe
realizar mediante funciones de la librería estándar
de C (strcpy, strcat, strcmp, etc.).

La principal virtud de CString es precisamente
esa, facilita el manejo de strings de caracteres automatizando
todo el tratamiento óptimo de la memoria.
Destacan las siguientes funcionalidades:

  • Función CString::GetLength, que
    permite conocer el número de caracteres que
    contiene.
  • Funciones CString::GetAt/CString::SetAt, que
    permiten acceder y modificar respectivamente el carácter
    del string que aparece en una posición
    dada.
  • Funciones
    CString::MakeUpper/CString::MakeLower, que permiten
    convertir a mayúsculas/minúsculas
    respectivamente.
  • Función CString::Find, que
    permite conocer si un determinado string o carácter
    aparece dentro de otro string.

Pero además, la clase CString tiene
sobrecargados algunos de los operadores de C/C++ lo que permite
un manejo intuitivo de esta clase, son los siguientes:
asignación (mediante =),
concatenación (mediante + y +=) y
comparación (operadores ==, <, <=,
etc.).

  1. 3. 2.
    La clase
    CFile

Esta clase presenta las funcionalidades básicas
para el tratamiento de ficheros, aportando funciones de alto
nivel.

  • Funciones CFile::Open/CFile::Close para abrir
    y cerrar ficheros.
  • Funciones CFile::Read/CFile::Write, para
    lectura y
    escritura
  • Funciones
    CFile::Seek/CFile::SeekToBegin/CFile::SeekToEnd que
    permiten posicionamiento
    directo dentro del fichero.
  • Funciones CFile::GetLenght/CFile::SetLenght
    que permiten obtener y cambiar el tamaño del
    fichero.
  • Función CFile::Rename/CFile::Remove que
    permiten renombrar (mover) y eliminar ficheros
    respectivamente.
  1. 3. 3.
    La clase CTime

CTime presenta las funcionalidades básicas de
tratamiento de fechas y horas. Al estilo de como se hace en C/C++
mediante el tipo de dato "time_t", representa un determinado
instante de tiempo (con
fecha, horas, minutos y segundos). Destacan:

  • Función CTime::GetCurrentTime, que
    obtiene el instante actual.
  • Funciones de extracción que permiten
    acceder a cualquiera de los datos significativos que componen
    un CTime: el día del mes ó el día de la
    semana, el mes, el año, la hora, etc.
  • Función CTime::Format, que permite
    construir un string formateado a partir de un
    CTime.
  • Operadores de asignación, suma, resta y
    comparación. Como complementaria a esta clase aparece
    CTimeSpan que representa un intervalo de tiempo. Las
    operaciones de suma se realizan con esta clase, y una resta de
    dos fechas dadas siempre da como resultado un
    CTimeSpan.
  1. 3.
    4.
    La clase
    CRect

CRect automatiza el tratamiento de
rectángulos. En Windows este concepto se
utiliza continuamente ya que las posiciones o el tamaño de
las ventanas se representan mediante los rectángulos que
ocupan en la pantalla.

Un rectángulo viene representado
físicamente por las coordenadas de su esquina superior
izquierda y la de su esquina inferior derecha. Estos datos se
almacenan en sus variables
miembro públicas: top, left, bottom y
right.

Dispone de funciones
como:

  • CRect::Width/CRect::Height, que
    permiten saber el ancho/alto de un
    rectángulo.
  • CRect::PtInRect¸que permite
    saber si un determinado punto está contenido dentro de
    un rectángulo.
  1. TRATAMIENTO DEL
    MENU.

Una de las principales vías de
interacción con el usuario, además de los
diálogos, son los menús. De manera general, cada
ventana principal de aplicación contiene un menú.
El método que suele asociar la ventana con el menú
es la función CFrameWnd::LoadFrame, esta recibe
como primer parámetro el identificador de los recursos de
la ventana principal. Serían el menú, el icono y el
título de la ventana. En suma, si creamos un menú,
un icono y un string todos con el mismo identificador, y
utilizamos éste en la llamada a LoadFrame, la ventana
principal aparecerá con las características
deseadas (este es el método que se suele seguir en la
MFC).

De todas maneras, la MFC proporciona otro
método alternativo que permite asociar o cambiar el
menú de una ventana. Mediante la función
CWnd::SetMenu podemos realizar también esta
operación.

Aunque en la mayoría de los casos el
menú de una ventana es constante durante toda la
duración de la misma, puede que en algún momento
necesitemos modificarlo dinámicamente, para ello se
proporciona la clase CMenu que aporta las funcionalidades
básicas para tratamiento de menús y la
función de ventana CWnd::GetMenu que devuelve una
referencia al objeto CMenu asociado con el menú de la
ventana. Destacan:

  • CMenu::LoadMenu, que permite asociar
    un objeto CMenu con un menú diseñado previamente
    en los recursos de la aplicación.
  • CMenu::DeleteMenu, que permite
    eliminar elementos (items o submenús desplegables –
    popup -) de un determinado menú.
  • CMenu::AppendMenu, que permite
    añadir items o submenús a un
    menú.
  • CMenu::EnableMenuItem, que permite
    habilitar e inhabilitar items de un
    menú.
  • CMenu::CheckMenuItem, que permite
    "marcar" como seleccionados elementos de un
    menú.
  • CMenu::GetMenuState, que permite
    saber si un determinado ítem está habilitado o
    seleccionado.

Pero aunque hemos repasado hasta aquí
los detalles de como asociar un menú a una ventana
(CFrameWnd::LoadFrame o CWnd::SetMenu) no hemos hecho
ningún comentario de lo mas importante. ¿ Como
podemos capturar las selecciones del usuario dentro del
menú y asociarles operaciones concretas ?. Este aspecto lo
veremos a continuación.

  1. Las selecciones que el usuario realice dentro
    de un menú se notifican a la ventana propietaria
    mediante mensajes de comando (WM_COMMAND). Cada uno de estos
    mensajes, cuando son recibidos por una ventana, va
    acompañado del identificador del ítem de
    menú seleccionado de manera que la aplicación
    pueda reconocer las operaciones a ejecutar. La forma en que
    se puede asociar una función de respuesta a un
    ítem de menú es bastante gráfica y
    sencilla gracias al uso de
    ClassWizard.

    Para ello, bastará con abrir la ventana
    de ClassWizard (CTRL+W o en el menú "Ver" con
    la opción "ClassWizard"), seleccionar la clase que
    queremos que controle el mensaje en cuestión,
    seleccionar el ítem de menú deseado y
    especificar el nombre de la función miembro que
    funcionará como respuesta a ese mensaje (tras
    presionar el botón de "Añadir función").
    Desde ese momento, ClassWizard añadirá los
    ficheros de cabecera e implementación de la clase
    seleccionada los datos específicos de la nueva
    función definida; el programador será el
    responsable de completar la implementación de la
    función con el tratamiento adecuado.

    Una característica propia de todas las
    aplicaciones generadas con AppWizard es que los items de
    menú que no estén asociados con ninguna
    función de respuesta aparecerán
    inhabilitados.

    8. 2. Objetos capaces de gestionar mensajes de
    comando de menú.

    En la MFC tanto el objeto aplicación CWinApp
    como cualquier ventana (objetos CWnd y derivados) es capaz de
    recibir mensajes de comando procedentes del menú de la
    aplicación. Aunque de alguna forma lo mas "real" es
    que la ventana sea la encargada de gestionarlos (ya que es la
    propietaria del menú y además en la
    programación SDK de Windows, la aplicación no
    tiene entidad como tal y son solamente las ventanas los
    elementos capaces de recibir mensajes del sistema, mediante
    su ya conocido procedimiento de ventana) si que es
    verdad que la elección siempre depende del
    programador. Todo esto quiere decir que mediante ClassWizard
    podemos asociar un comando del menú con una
    función miembro de un objeto
    aplicación.

    De cualquier manera lo que siempre es una
    práctica aconsejable es centralizar todas las
    funciones de respuesta (también conocidas como
    manejadores de mensajes) dentro de una misma
    clase.

  2. 1.
    Gestión de mensajes
    de comandos del
    menú.
  3. GESTIÓN DE
    DIÁLOGOS

Las ventanas de diálogos son uno de los elementos
mas utilizados para la interacción con el usuario. De
manera general un diálogo es una ventana especial que
contiene en su interior ventanas hijas que son controles
(botones, listas, cajas de edición, listas desplegables,
…) identificados por un número único,
además, cuando un diálogo se despliega, se
convierte en una ventana exclusiva en el sentido de que deja
inhabilitada cualquier operación con el resto de la
aplicación (este efecto se conoce realmente con el nombre
de diálogos modales, aunque existe la posibilidad de crear
también diálogos no modales). Las plantillas de
estos diálogos pueden diseñarse mediante herramientas
integradas en el entorno de desarrollo como es el ya conocido
ResourceView (también conocido como taller de
recursos).

Es la clase CDialog, derivada de CWnd, la
responsable de proporcionar las funcionalidades básicas de
esta ventana especializada.

  • El constructor de la clase CDialog::CDialog,
    requiere dos parámetros: el nombre de la plantilla de
    diálogo que utilizará (la que hayamos
    diseñado en los recursos) y una referencia a la ventana
    padre del diálogo (casi siempre es la ventana que pide
    que se visualice). También existe un constructor por
    defecto (sin parámetros) orientado a la creación
    de diálogos no modales.
  • La función CDialog::DoModal, aplicada sobre un
    objeto construido previamente permite visualizarlo en modo
    modal. Esta función es síncrona en el sentido de
    que no devuelve el control a la
    función llamante hasta que no se cierre el
    diálogo. Devuelve un valor que
    podemos utilizar para indicar distintas opciones de cierre del
    diálogo (por ejemplo podemos devolver TRUE para indicar
    que se presionó
    OK o FALSE para Cancelar).
  • La función CDialog::EndDialog permite
    finalizar un diálogo modal, recibe un parámetro
    que se corresponderá con el valor que
    devuelva DoModal.
  • La función CDialog::Create, aplicada
    sobre un objeto construido previamente, permite crear
    diálogos no modales. Los diálogos no modales no
    se finalizan con EndDialog sino que utilizaremos la
    función estándar heredada de CWnd
    DestroyWindow.
  • Función CDialog::OnInitDialog, para
    inicializar el diálogo.
  • Funciones CDialog::OnOk/CDialog::OnCancel que
    permiten realizar las operaciones de confirmación o
    cancelación del objetivo del
    diálogo.

Pero CDialog es una clase abstracta, por lo que
no la podremos utilizar directamente (no se pueden crear objetos
CDialog). El programador deberá derivar sus propias clases
desde CDialog para crear sus propios diálogos.

  1. Creación de
    diálogos

Los pasos para crear una ventana de diálogo son
los siguientes:

  1. Crear la plantilla de diálogo que se va a
    utilizar en el fichero de recursos. Para ello utilizaremos
    ResourceView y las herramientas de diseño de diálogos. El
    diálogo se podrá completar con los controles
    necesarios (cajas de edición, listas, botones, etc.).
    Cada uno de los controles deberá llevar un identificador
    único.
  2. Asignar un identificador a la plantilla de
    diálogo que se haya diseñado.
  3. Invocar ClassWizard
  4. Seleccionar botón "Añadir
    clase nueva"
  5. Definir la nueva clase. Para ello le
    daremos un nombre y seleccionaremos la clase base mas adecuada.
    En este caso seleccionaremos la clase CDialog. El
    sistema automáticamente asignará un nombre a los
    ficheros de cabecera e implementación donde se
    codificará la clase (estos nombres los podemos cambiar).
    Aparece una lista desplegable donde seleccionaremos el
    identificador de la plantilla de diálogo asociado
    (especificado en el paso 2).

El sistema genera entonces el esqueleto de la nueva
clase, en los ficheros especificados, añadiéndolos
al proyecto. Bastará con completar el código
generado e introducir una llamada al diálogo en
algún punto del programa (mediante la función
CDialog::DoModal por ejemplo).

  1. Tratamiento de los controles de
    diálogos.

La librería MFC aporta también clases
representativas de los controles típicos de Windows. Esto
nos permite crearlos de manera dinámica (mediante código) o
manejarlos adecuadamente. De entre estas clases,
destacan:

  • CButton, representa cualquier tipo de botones
    (pushbuttons, radio buttons o
    check boxes).
  • CComboBox, representa listas
    desplegables.
  • CListBox, representa listas.
  • CEdit, representando cajas de
    edición.
  • CStatic, representando texto
    estáticos.

Cada una de estas clases deriva de CWnd (no en vano son
todas ventanas especializadas) e incorpora funciones
específicas que facilitan su tratamiento (así por
ejemplo las listas aportan funciones que permiten saber el
elemento que tiene seleccionado en cada momento).

Aunque un control puede aparecer dentro de cualquier
ventana (se dice que el control es una ventana hija) es en los
diálogos donde mas se utilizan. De manera general, la
ventana padre debe ser capaz de manejar los controles que la
forman (rellenando una lista con las opciones disponibles,
presentando el DNI del empleado seleccionado en la caja de
edición al efecto, etc.). Para conseguir esto disponemos
de dos métodos:

  1. Asociación estática
    de controles
    . Este método consiste en la
    creación de objetos miembros de la clase de la ventana
    padre (el diálogo) y su asociación con cada uno
    de los controles. Es decir, existe una variable miembro dentro
    del diálogo que representa cada uno de los controles. De
    manera general no se "mapearán" todos los controles a
    variables
    sino sólo aquellos que necesitemos (aquellos que vayamos
    a manejar en el programa). Este trabajo se realiza mediante
    ClassWizard dentro de su "subcarpeta" marcada como "Variables".
    Así un botón se mapea a un objeto CButton, una
    lista a un objeto CListBox, etc.
  2. Asociación dinámica de controles. Mediante este
    método se consiguen referencias a los controles durante
    la ejecución del programa. No existen variables miembro
    que se asocien a controles de manera estática
    (constante) sino que conseguimos el mismo efecto cuando lo
    necesitamos. Para ello disponemos de la función de
    ventana CWnd::GetDlgItem que recibe como
    parámetro el identificador del control del que queremos
    obtener una referencia. Hay que destacar que esta
    función es de la ventana básica CWnd, lo que
    significa que cualquier ventana puede acceder a sus ventanas
    hijas (controles generalmente) de la misma manera
    (abstracción). Además, mediante esa
    función obtenemos referencias a objetos de distintas
    clases en función del tipo de control que queramos, es
    decir, utilizamos la misma función para acceder a
    botones, listas o cajas de edición. En realidad la
    función GetDlgItem devuelve referencias a
    ventanas genéricas (devuelve punteros a CWnd *) o lo que
    es lo mismo, devuelve referencias a cualquier tipo de ventana
    (no tiene por que ser controles).
  1. De manera análoga a lo que comentamos con
    los items de menú, los controles informan a las
    ventanas padres de las acciones
    que el usuario realiza sobre ellos. Así los botones
    informan de que se hizo "click" sobre ellos o las cajas de
    edición lo hacen de que se modificó su
    contenido. El mecanismo utilizado es también el
    mensaje de comando WM_COMMAND aunque aquí tiene un
    enfoque adicional.

    Mientras los elementos de menú sólo
    informan de que han sido seleccionados los controles pueden
    informar de distintos eventos
    (dependiendo del tipo de control), así siempre es
    distinto realizar un click sobre una lista que un doble
    click. En definitiva, los mensajes de comando de los
    controles de diálogos incorporan una nueva
    información que se conoce como
    notificación. Las notificaciones recogidas
    por cada tipo de control son distintas, dependiendo de su
    naturaleza.

    La forma de añadir funciones manejadoras de
    mensajes de controles a los diálogos es
    análoga a la que se describió para los
    comandos
    de menú. Lo realizaremos mediante ClassWizard, pero
    además de seleccionar el identificador del control
    tendremos que seleccionar también la
    notificación a la que queremos añadir el
    nuevo manejador.

  2. Mensajes de comando de controles de
    diálogos.

    Una vez que hemos visto como obtener un
    vínculo con los controles que forman un
    diálogo hemos de conocer como inicializarlo para que
    presente al usuario el aspecto seleccionado. El momento de
    inicialización del diálogo viene marcado por
    la llegada del mensaje WM_INITDIALOG, cuyo manejador
    virtual es CDialog::OnInitDialog. En nuestra clase
    de ventana de diálogo redefiniremos esta
    función virtual para definir nuestra propia
    inicialización.

  3. Inicialización de
    diálogos.
  4. Un diálogo especial –
    CPropertySheet

La clase CPropertySheet presenta las funcionalidades
básicas de los diálogos basados en pestañas
o subcarpetas. En la imagen se
presenta un detalle del diálogo ClassWizard que es de este
estilo.

Figura 3.- Detalle de diálogo con
subcarpetas.

Estos diálogos están compuestos por una
serie de páginas (subcarpetas), que vienen representadas
en la MFC mediante la clase CPropertySheet. Cada una de estas
páginas es básicamente un diálogo de estilos
especiales, pero cuentan con su plantilla correspondiente en el
fichero de recursos del proyecto.

Para construir diálogos de este tipo seguiremos
los siguientes pasos:

  1. Generar las páginas necesarias. Para ello
    necesitamos diseñar las plantillas de cada una de ellas
    en los recursos, y añadir una clase derivada de
    CPropertyPage que las represente (de manera análoga a
    como se vio en el punto 9.1)
  2. Añadir una clase derivada de
    CPropertySheet al proyecto mediante ClassWizard.
  3. Asociar a esta clase las páginas
    correspondientes. Se realiza mediante la función miembro
    CPropertySheet::AddPage, que recibe como
    parámetro una referencia a la clase CPropertyPage a
    añadir. Estas operaciones se suelen realizar dentro del
    constructor del propio objeto.
  4. Crear un objeto de esa clase e invocar la
    función CPropertySheet::DoModal
  1. EL INTERFAZ MDI

El interfaz de documento múltiple es
sensiblemente distinto al ya conocido de documento simple (SDI)
en el que nos hemos basada en las exposiciones previas. Las
aplicaciones MDI pueden tener abiertas simultáneamente
varias ventanas marco, conteniendo vistas que visualizan
documentos. Las diferencias principales son las
siguientes:

  • La ventana principal de la aplicación
    derivará de CMDIFrameWnd, y su objetivo principal
    no es contener una vista como ventana cliente
    (según el modelo SDI)
    sino controlar y gestionar las ventanas marcos
    existentes.
  • Como ventana cliente de la ventana principal aparece
    la clase de ventana MDICLIENT. Esta es la verdadera ventana
    padre de las sucesivas ventanas marco que se vayan abriendo. La
    MFC no contempla ninguna clase que represente este tipo de
    ventanas ya que su comportamiento por defecto es totalmente
    suficiente y estándar. De hecho, a primera vista puede
    quedar oculta la existencia de esta ventana cliente ya que en
    ningún momento necesitamos crearla (la crean las
    funciones por defecto).
  • Las ventanas marcos derivarán de
    CMDIChildWnd y son "hijas" de la ventana MDICLIENT de la
    ventana principal de la aplicación (recordar que en el
    modelo SDI
    la ventana principal era a su vez ventana marco de
    documento).

De esta manera, para crear la ventana principal de la
aplicación la función InitInstance
invocará a la función CFrameWnd::LoadFrame(),
mientras para crear cualquier ventana marco con su vista y
documento tendremos que utilizar las funciones aportadas por los
objetos CMultiDocTemplate (como
CDocTemplate::OpenDocumentFile) que hayamos definido como
plantillas soportadas por la aplicación mediante la
función CWinApp::AddDocTemplate (es decir, el mismo
tratamiento descrito arriba para aplicaciones SDI).

Obviamente, las ventanas principales de este tipo de
aplicaciones, derivadas de CMDIFrameWnd contienen funcionalidades
especializadas en la gestión
de las ventanas MDI hijas, destacan las siguientes:

  • CMDIFrameWnd::MDIGetActive, que permite
    obtener una referencia a la ventana MDI hija (ventana marco con
    vista y documento) que está activa.
  • Funciones como CMDIFrameWnd::MDITile que
    organiza en mosaico las ventanas MDI hijas existentes,
    CMDIFrameWnd::MDICascade que lo hace en cascada o
    CMDIFrameWnd::MDIIconArrange que alinea en el
    área cliente de la ventana principal los iconos de las
    ventanas MDI hijas que estén minimizadas.

La utilización del modelo SDI o MDI
dependerá siempre de los requisitos de nuestra
aplicación, de todas maneras el funcionamiento de ambos
modelos es muy
similar en su concepción y tratamiento gracias a las
abstracciones prestadas por la MFC.

  1. CLASES ORIENTADAS A ACCESO A BASES DE
    DATOS

La MFC proporciona clases que proveen un interfaz de
alto nivel para el tratamiento de bases de datos. Para ello se
basa en dos mecanismos distintos pero de funcionamiento y
tratamiento muy similar:

  1. El término ODBC (Open Data Base
    Conectivity) indica que su objetivo es conseguir un
    tratamiento estándar para distintos sistemas
    gestores de bases de datos (SGBD). Su funcionamiento se
    basa en el uso de drivers. Estos drivers proveen un
    interfaz estándar de programación, ocultando
    los detalles internos de funcionamiento de cada SGBD. El
    estándar ODBC está muy extendido, proveen una
    librería de funciones C (el API o SDK de ODBC) que
    se basa en un SQL
    estándar como lenguaje
    de consulta utilizado, de manera que podemos acceder con el
    mismo método a tablas dBase, Oracle o
    Informix (…) sin mas que disponer del driver ODBC
    apropiado para cada SGBD.

    Para utilizar una base de
    datos mediante ODBC entra en juego lo
    que se denomina Origen de datos (DSN – Data source
    name). Un origen de datos es una entidad identificada por
    su nombre que especifica una base de datos concreta,
    mediante ese DSN podremos acceder a cualquier tabla de
    dicha base de datos. La definición de los DSN se
    consigue gracias al Administrador ODBC que se suele
    encontrar dentro del Panel de
    Control de Windows (puede que encontremos instalaciones
    en las que no aparezca referencias al ODBC ya que es una
    extensión de Windows no estándar, aunque en
    la actualidad es instalado por la mayoría de los
    SGBD mas comerciales).

  2. Tratamiento mediante ODBC

    El modelo DAO (Data Access
    Object) es una extensión del ODBC que está
    especializada y optimizada para el acceso a bases de datos
    de Microsoft
    Access. DAO ha sido incorporado a la MFC en la
    última versión comercializada, ya que antes
    el tratamiento de bases de datos Access
    estaba integrado dentro del propio ODBC.

    Dado que el funcionamiento es totalmente
    análogo (aunque las clases DAO tienen tratamientos y
    capacidades específicas) pero siendo ODBC un
    método mucho mas general, nos centraremos en el uso
    de este último para el desarrollo de este
    capítulo, realizando el paralelismo oportuno con el
    modelo DAO cuando sea necesario.

  3. Tratamiento mediante DAO

    Dos son los conceptos que se utilizan en el
    tratamiento de bases de datos mediante MFC: la base de
    datos (conjunto de tablas) y el recordset (conjunto de
    registros
    de una tabla). Son representados mediante las clases
    CDatabase y CRecordset.

    1. La clase
      CDatabase
  4. Las clases
    básicas

Presta las funcionalidades básicas para el
tratamiento de bases de datos. Encapsula la conexión con
un DSN definido dentro del administrador
ODBC que nos permitirá operar sobre la base de datos
asociada.

  • Función CDatabase::Connect que permite
    conectar un objeto CDatabase con un DSN ODBC. Las
    función CDatabase::Close permite liberar esa
    conexión.
  • Funciones de soporte a transacciones (encapsulamiento
    de varias operaciones como una operación atómica)
    como CDatabase::BeginTrans (marca comienzo
    de una transacción), CDatabase::CommitTrans (que
    cierra y confirma las operaciones realizadas) o
    CDatabase::Rollback (que cierra y anula las
    operaciones). Obviamente, para que este enfoque funcione el
    SGBD asociado al DSN debe ser transaccional, lo que podemos
    averiguar mediante la función
    CDatabase::CanTransact.
  • La función CDatabase::ExecuteSQL que
    ejecuta la sentencia SQL que
    recibe como parámetro. Con esta función
    sólo se pueden realizar tareas de mantenimiento de la base de datos como
    añadir tablas (CREATE TABLE …), modificarlas
    (ALTER TABLE …), eliminarlas (DROP TABLE …), etc.
    Es decir, al nivel de CDatabase el SQL se puede utilizar como
    lenguaje de
    mantenimiento de datos, pero no como lenguaje de consulta
    (sentencias SELECT …) que se reserva para el objeto
    CRecordset.

En la mayoría de los casos el trabajo se
realizará sin la necesidad de trabajar al nivel de
CDatabase, ya que la mayoría de las aplicaciones se
limitan a consultar y modificar registros de tablas, operaciones
que se realizan al nivel de CRecordset. Sólo en el caso de
que nuestra aplicación tenga requisitos de mantenimiento
de la base de datos (añadir/modificar/borrar tablas,
gestión de permisos, usuarios …) necesitaremos
trabajar al nivel de CDatabase, en cuyo caso bastará con
crear un objeto de esa clase, abrirlo, operar sobre él y
cerrarlo; en ningún caso necesitaremos derivar de
CDatabase nuestras propias clases para bases de datos.

El análogo de CDatabase en el mundo DAO es
CDaoDatabase.

  1. La clase
    CRecordset

Representa un conjunto de registros de una determinada
tabla resultado de realizar una consulta sobre ella (un SELECT
del SQL), algo análogo al concepto de cursor, es decir,
siempre se asocia a una tabla de una base de datos. Presenta
restricciones como la imposibilidad de realizar consultas
compuestas (registros de mas de una tabla) o las clásicas
uniones de las bases de datos relacionales.

La clase CRecordset es abstracta de manera que
tendremos que derivar nuestros propios recordsets de ella. Entre
sus miembros destacan:

  1. Su constructor recibe como parámetro una
    referencia al objeto CDatabase al cual pertenece la tabla
    asociada. Por defecto lleva un valor nulo lo que significa que
    el proceso por
    defecto construye su propio CDatabase cuando es
    necesario.
  2. La función
    CRecordset::GetDefaultConnect, que especifica la tabla
    asociada al cursor y el DSN de la base de datos a la que
    pertenece.
  3. Miembro dato
    CRecordset::m_strFilter, que almacena la sentencia
    SELECT con la que se accede a la tabla asociada al
    recordset.
  4. Miembro dato CRecordset::m_strSort,
    que almacena el(los) nombre(s) de los campos por los que se
    quiere ordenar los registros seleccionados.
  5. Funciones como CRecordset::Open y
    CRecordset::Close que permiten abrir y cerrar
    recordsets.
  6. Funciones de navegación en el
    recordset como CRecordset::MoveFirst,
    CRecordset::MoveLast, CRecordset::MoveNext o
    CRecordset::MovePrev.
  7. Funciones como CRecordset::AddNew
    que permite añadir nuevos registros,
    CRecordset::Edit que permite modificar el registro activo
    o CRecordset::Delete para eliminar el registro
    activo. En complemento a las dos primeras funciones aparece
    CRecordset::Update, función necesaria para
    reflejar en la tabla una inserción (AddNew) ó
    modificación (Edit).

La clase análoga a CRecordset en el modelo DAO se
denomina CDaoRecordset

La creación de los recordsets necesarios se
realizará mediante ClassWizard. Para ello procederemos a
añadir una nueva clase al proyecto, en el momento de
especificar la clase base seleccionaremos CRecordset. Tras
confirmar la operación el sistema nos pedirá que
seleccionemos el DSN del origen de datos ODBC (para lo que debe
haber sido definido previamente en el administrador de
ODBC). Una vez realizado esto aparecerá una lista con el
nombre de todas las tablas que forman la base de datos asociada
al DSN seleccionado. Escogeremos una de ellas que se
asociará al nuevo objeto recordset. El sistema como
siempre crea un esqueleto de la nueva clase que incluye, entre
otras cosas, un constructor por defecto y la definición de
la conexión a la tabla (en la función
CRecordset::GetDefaultConnect). Además, esta clase
incorpora un miembro dato por cada uno de los campos de la tabla
asociada, datos que serviremos para almacenar los valores
del registro actual en cada momento. Estas variables se mapean a
cada campo, relación que se define en el cuerpo de la
función CRecordset::DoFieldExchange. Esta
función es implementada por ClassWizard y solo en algunos
casos tendremos que modificarla (los veremos a
continuación). Podemos destacar dos tipos de recordsets
distintos:

  • Tipo Snapshot, donde el recordset es una vista
    estática del contenido de la tabla en el momento de su
    apertura. Cualquier modificación sobre la misma no se
    reflejaría en el recordset hasta que no volviese a
    abrirse.
  • Tipo Dynaset, donde se representa una
    visión dinámica de las tablas. Es mas utilizado
    aplicaciones que trabajan sobre bases de datos multiusuario o
    compartidas, donde otras aplicaciones pueden realizar
    modificaciones.

Para utilizar un determinado recordset bastará
con crear un objeto de esa clase, rellenar la información
de la consulta en m_strFilter (si no va relleno se
recuperarían todos los registros de la tabla), la
información de ordenación en m_strSort
(opcional) y llamar a la función Open que realiza
la consulta apropiada. Cuando el recordset haya dejado de
utilizarse invocaremos la función Close que libera
los recursos de la conexión ODBC.

11.3.3 Los recordsets
parametrizados

Uno de los mayores problemas que
se le han achacado al ODBC ha sido el excesivo tiempo de
respuesta (factor por el que vio la luz el modelo
DAO). Aunque esto siempre ha dependido de la calidad del
driver y del propio SGBD lo cierto es que operaciones de apertura
y cerrado sobre algunas tablas son realmente lentas; esto, como
no, se agrava en el caso de acceso a bases de datos remotas
(soportadas por múltiples SGBD’s como SQL Server,
Informix net, etc.) ó cuando se recuperan muchos
registros.

Para solucionar, en alguna medida, este problema
aparecen los recordsets parametrizados. Éstos nos permiten
modificar los criterios de selección de registros de
manera dinámica sin necesidad de cerrar y volver a abrir
el recordset. En su lugar se utiliza simplemente la
función CRecordset::Requery que no libera la
conexión con el DSN asociado por lo que es sensiblemente
mas rápida.

Para parametrizar un determinado recordset seguiremos
como sigue:

  1. Incluir miembros datos dentro de la clase que nos
    servirán como parámetros en las consultas. La
    inicialización de estos nuevos miembros la realizaremos
    en el constructor de la clase, así como también
    inicializaremos el miembro CRecordset::m_nParams con el
    número de parámetros que hayamos
    definido.
  2. Mapear los parámetros
    añadidos con los campos asociados. Para ello tendremos
    que modificar la función DoFieldExchange de la
    clase.

Una vez parametrizado, podremos modificar los criterios
de búsqueda del recordset de manera dinámica sin
mas que modificar el valor de los parámetros y refrescar
el contenido del cursor mediante Requery.

La utilización de un recordset parametrizado es
totalmente análoga a la de uno estándar.
Simplemente basta con rellenar el valor de los parámetros
antes de realizar la apertura de la tabla.

  1. Manejo de excepciones mediante
    CDBException

Cuando trabajamos con bases de datos se pueden producir
situaciones anómalas que provocan errores de
ejecución de las aplicaciones. Por ejemplo, el intento de
abrir una determinada tabla que ha sido abierta previamente por
otro usuario de modo exclusivo, o invocar la función de
pasar al siguiente registro cuando ya se ha alcanzado el
último del recordset, son casos que provocarán una
finalización anómala del programa.

El concepto de excepción permite capturar estas
situaciones especiales antes de que se produzca el error fatal,
avisar al usuario y continuar con la ejecución del
programa dentro de lo posible.

De manera general, una excepción se puede
producir dentro del ámbito de cualquier función sin
necesidad de que se estén manejando en ella recordsets o
bases de datos. La clase abstracta CException, representa
este concepto. De entre sus clases derivadas destacan:

  • CMemoryException, para gestión de
    excepciones producidas por operaciones directas sobre memoria
    (new, delete, …).
  • CFileException, para operaciones sobre
    ficheros (fichero no existente o de sólo lectura,
    etc.)
  • CDBException y CDaoException para
    operaciones sobre bases de datos ODBC y DAO
    respectivamente.

Cada una de estas clases incorpora funcionalidades
propias, pero su utilización es muy similar, por lo que
nos centraremos sobre CDBException que nos ocupa
ahora.

La forma de utilizar las excepciones es como sigue:
tenemos que encapsular la operación que pueda producir la
excepción dentro de un bloque TRY/CATCH, que de manera
general tiene el siguiente formato.

TRY

{

Operación que puede producir
excepción …

}

CATCH(Clase de excepción a capturar, objeto
asociado)

{

Operaciones de recuperación de la
excepción …

}

La rama donde se encuentran las operaciones de
recuperación de la excepción sólo se
ejecutarán en el caso de que se produzca una
excepción de la clase especificada en la sentencia CATCH,
entonces el objeto que le acompaña tomará los
valores que
identifican dicha excepción. Mas en concreto, para
el caso de CDBException, el ejemplo sería algo
así:

CEmpleadosSet e;

e.m_strFilter = "DEPARTAMENTO = ‘VENTAS’";

TRY

{

e.Open();

}

CATCH(CDBException, e)

{

}

END_CATCH

 

 

Autor:

Fco. Javier Rivilla Lizano
Level data, S.A. – Septiembre 1.997

Trabajo enviado por:
Coria David Marcelo

Partes: 1, 2
 Página anterior Volver al principio del trabajoPágina siguiente 

Nota al lector: es posible que esta página no contenga todos los componentes del trabajo original (pies de página, avanzadas formulas matemáticas, esquemas o tablas complejas, etc.). Recuerde que para ver el trabajo en su versión original completa, puede descargarlo desde el menú superior.

Todos los documentos disponibles en este sitio expresan los puntos de vista de sus respectivos autores y no de Monografias.com. El objetivo de Monografias.com es poner el conocimiento a disposición de toda su comunidad. Queda bajo la responsabilidad de cada lector el eventual uso que se le de a esta información. Asimismo, es obligatoria la cita del autor del contenido y de Monografias.com como fuentes de información.

Categorias
Newsletter