Ejemplo CTRLTEST: implementa controles personalizados

Actualización: noviembre 2007

En el ejemplo CTRLTEST se ilustran varias técnicas para implementar y utilizar controles personalizados:

  • Implementación de CParsedEdit, un control de edición especializado que deriva funcionalidad de su clase de control de biblioteca, y de tres métodos de utilizar controles personalizados.

  • Uso del control de número. El control de número tiene botones flecha arriba y flecha abajo pequeños para aumentar o reducir un valor.

  • Implementación en botón de mapa de bits de comandos del menú Custom mediante CBitmapButton.

  • Dibujo del propietario (ventana primaria) de menús y cuadros de lista. Las clases de control correspondientes derivadas de las clases CMenu y CListBox proporcionan esta característica de forma orientada a objetos.

  • Uso de archivos de recursos que no se pueden mantener mediante los editores de recursos de Microsoft Visual C++. Esto ilustra las ventajas y los inconvenientes de utilizar un archivo .rc2 en un cuadro de diálogo que tiene un control personalizado con estilos definidos mediante constantes en un archivo de encabezado.

Todas las ilustraciones de CTRLTEST se inician mediante comandos de menú.

Nota de seguridad:

Este código de ejemplo se proporciona para ilustrar un concepto y no debe utilizarse en aplicaciones o sitios Web, ya que quizás no ilustre las prácticas de codificación más seguras. Microsoft no asume ninguna responsabilidad por daños incidentales o consecuentes en caso de que el código de ejemplo se utilice para propósitos distintos de aquellos para los que se concibió.

Para obtener ejemplos e instrucciones para su instalación:

  • En el menú Ayuda de Visual Studio, haga clic en Ejemplos.

    Para obtener más información, vea Localizar archivos de ejemplo.

  • La lista de ejemplos completa con la versión más reciente está disponible en línea en la página Visual Studio 2008 Samples.

  • También encontrará ejemplos en el disco duro de su equipo. De manera predeterminada, los ejemplos y el archivo Léame se copian en una carpeta bajo \Archivos de programa\Visual Studio 9.0\Samples\. Para las versiones Express de Visual Studio, todos los ejemplos están en línea.

Generar y ejecutar el ejemplo

Para generar y ejecutar el ejemplo CTRLTEST

  1. Abra la solución Ctrltest.sln.

  2. En el menú Generar, haga clic en Generar.

  3. En el menú Depurar, haga clic en Iniciar sin depurar.

Ejemplo: implementar y utilizar controles personalizados

Puede implementar un control personalizado derivándolo de CWnd, pero es mucho más fácil utilizar la funcionalidad de los controles estándar de Windows derivando de las clases de control de la biblioteca. CTRLTEST lo hace para implementar un control de edición especializado, CParsedEdit. Este control de edición sólo acepta los juegos de caracteres especificados como datos proporcionados por el usuario: caracteres numéricos, alfabéticos o no pertenecientes a un control. CParsedEdit se deriva de CEdit. Tiene un controlador de mensajes OnChar para filtrar los caracteres.

La implementación de los comandos del menú Simple ilustra tres métodos de utilizar un control personalizado. Los métodos se distinguen en función de cómo se asocian en la aplicación instancias del control del cuadro de diálogo con la clase CParsedEdit. Cada comando del menú Simple muestra un cuadro de diálogo con cuatro instancias del control CParsedEdit. Los datos escritos en el cuadro de diálogo se envían al puerto de depuración como salida de TRACE. Los tres comandos del menú Simple son:

Test C++ Derived Class

Los controles CParsedEdit son miembros de datos de la clase del cuadro de diálogo. Los controles se crean explícitamente en la función OnInitDialog del cuadro de diálogo llamando a CParsedEdit::CreateSet. Vea Dertest.cpp.

Test WNDCLASS Registered

Los controles CParsedEdit se dibujan en un recurso de plantilla de cuadro de diálogo (IDD_WNDCLASS_EDIT) como controles personalizados con una clase WNDCLASS identificada como "paredit". Es instructivo examinar las propiedades de estos controles personalizados mediante el editor de cuadros de diálogo de Visual C++.

  • Caption blank. Éste es el valor inicial mostrado en el control CParsedEdit.

  • Class:paredit. Éste es el nombre de la clase registrado por CParsedEdit::RegisterControlClass en PAREDIT2.CPP antes de que se llame al cuadro de diálogo.

  • Visible:checked. El control está visible.

  • Tabstop:checked. El usuario puede llegar a este control mediante tabulaciones.

  • Style:0x5081002, 0x5081001, 0x5081003, 0x5081ffff para los cuatro controles de edición analizados. El estilo 0x500000 es para WS_CHILD y WS_VISIBLE, y el estilo 0x1000 es para WS_TABSTOP. Todos los controles personalizados tienen el estilo WS_CHILD. El editor de cuadros de diálogo establece automáticamente los estilos WS_VISIBLE y WS_TABSTOP si activa los estilos Visible y Tabstop. 0x80000 es para WS_BORDER. Dado que la página de propiedades del editor de cuadros de diálogo de un control personalizado proporciona todos los estilos de ventanas, como WS_BORDER, debe buscar la constante en \Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include\WINUSER.H. Los estilos 0x0001, 0x0002, 0x0004 y 0x0ffff están definidos en PAREDIT.H como PES_NUMBERS, PES_LETTERS, PER_OTHERCHARS y PES_ALL respectivamente.

  • Los estilos hexadecimales de la página de propiedades del control personalizado no tienen documentación propia. Si es importante utilizar los estilos simbólicos, como PES_NUMBERS y PES_LETTERS, como alternativa puede editar un archivo de recursos independiente, como RES\Ctrltest.rc2, que incluye el compilador de recursos en tiempo de compilación, aunque no lo lee Visual C++ en tiempo de edición. Si desea ver una descripción de las ventajas y los inconvenientes de editar manualmente un cuadro de diálogo de control personalizado en un archivo .rc2, vea Utilizar archivos de recursos que no pueden mantener los editores de recursos de Visual C++.

Test Dynamic Subclassed

Los controles se colocan en un recurso de plantilla de cuadro de diálogo (IDD_SUB_EDIT en Ctrltest.rc) como controles de edición estándar. Se declaran como miembros de datos de CParsedEdit en la clase del cuadro de diálogo. La función OnInitDialog del cuadro de diálogo llama a CParsedEdit::SubClassEdit, que a su vez llama a CWnd::SubclassDlgItem para asociar cada instancia específica del control de edición a la clase CParsedEdit. Vea Paredit.cpp.

Ejemplo: control Spin

El ejemplo CTRLTEST incluye una implementación de un control de botones de número (Spin). El control de botones de número tiene botones flecha arriba y flecha abajo pequeños para aumentar o reducir un valor.

El comando Spin Control llama a un cuadro de diálogo que tiene cuatro controles CParsedEdit, cada uno de ellos asociado a un control de botones de número. Los datos escritos en los controles CParsedEdit de este cuadro de diálogo se filtran para aceptar sólo números enteros no negativos. El usuario puede escribir datos numéricos en el control CParsedEdit o utilizar el control de botones de número asociado para escribir los datos.

Ejemplo: botón Bitmap

La implementación de los siguientes comandos del menú Custom ilustran varias formas de utilizar CBitmapButton:

  • Bitmap Button 1: el constructor del cuadro de diálogo carga explícitamente los recursos del mapa de bits para cada uno de los tres estados (up, down, focus) del botón llamando a CBitmapButton::LoadBitmaps.

  • Bitmap Button 2: La función OnInitDialog del cuadro de diálogo llama a CBitmapButton::Autoload para cargar los recursos de mapas de bits con la siguiente convención de asignación de nombres. El texto de la ventana del control sirve como base para el nombre del recurso, y se anexan las letras U, D y F para crear los nombres de los recursos para cada una de las tres imágenes de mapa de bits correspondientes a los modos up, down y focus, respectivamente. Por ejemplo, los tres recursos de mapa de bits del botón Aceptar son OKU, OKD y OKF.

  • Bitmap Button 3: el cuadro de diálogo es una extensión del segundo cuadro de diálogo anterior, con un posible cuarto estado de botón deshabilitado. Para utilizar este cuadro de diálogo, haga clic en el botón de mapa de bits de flecha izquierda o flecha derecha hasta que el número mostrado sea 1, el número más bajo, o 10, el número más alto. Cuando se alcance el límite, se deshabilita el botón y se muestra una cuarta imagen de mapa bits. La convención de asignación de nombres para el recurso de mapa de bits para el estado deshabilitado es un sufijo X, como se refleja en los nombres de recursos PREVX y NEXTX.

Ejemplo: dibujo del propietario (menú y cuadro de lista)

Varios controles y menús de Windows tienen una característica de dibujo que permite a la ventana primaria (o propietaria) dibujar lo que desee en el área de cliente en sustitución del comportamiento estándar del control. Las clases de control correspondientes y la clase CMenu proporcionan esta característica de forma más conveniente orientada a objetos: la clase del control o el menú controlan el dibujo. Esto se denomina "dibujo automático".

CTRLTEST ilustra las técnicas generales de dibujo del propietario al implementar los siguientes comandos en el menú Custom:

  • Custom Menu: este elemento de menú llama a un menú emergente CColorMenu, derivado de CMenu. Cada elemento de submenú muestra uno de los ocho colores de la característica de dibujo automático. Un cuadro de mensaje le confirmará el color seleccionado en el submenú.

  • Custom List Box: este elemento de menú llama a un cuadro de diálogo que muestra un elemento CColorListBox, derivado de CListBox. El cuadro de lista tiene ocho entradas, cada una dibujada con uno de los ocho colores mediante la característica de dibujo automático. La salida de TRACE confirma la selección en el cuadro de lista.

Ejemplo: utilizar archivos de recursos que no pueden mantener los editores de recursos de Visual C++

El archivo de recursos CTRLTEST\RES\Ctrltest.rc2 es un ejemplo de archivo de recursos que los editores de recursos de Visual C++ no pueden mantener de forma legible. Si desea abrir el archivo Ctrltest.rc2 en Visual C++ y después guardarlo, perdería información legible útil, aunque el compilador de recursos podría compilar el archivo .rc2 y generar un archivo .res binario equivalente. Por tanto, se ha agregado RES\Ctrltest.rc2 mediante #include a Ctrltest.rc con una directiva de tiempo de compilación especificada mediante el comando Resource File Set Includes.

A continuación, se muestran tres categorías de información legible que no pueden mantener los editores de recursos de Visual C++. En Ctrltest.rc2 se muestran dos de estos tipos:

  • Símbolos de estilos de control personalizado: por ejemplo, "msctls_updown32" es un estilo definido para el control de número. Aunque Visual C++ puede interpretar este símbolo como lo lee en el archivo .rc2, lo escribirá en el archivo .rc2 como valor hexadecimal.

  • WS_ estándar de Windows o símbolos de estilo de control utilizados en un control de una clase derivada de un control estándar de Windows: por ejemplo, ES_AUTOHSCROLL está definido para el control de número en el cuadro de diálogo IDD_SPIN_EDIT. Aunque Visual C++ puede interpretar estos símbolos como los lee en el archivo .rc2, los escribirá en los archivos .rc2 como valores hexadecimales.

  • Aritmética en el archivo .rc: Visual C++ escribirá en el archivo .rc2 las expresiones como "IDC_EDIT1+2" para identificar controles en el cuadro de diálogo IDD_SPIN_EDIT como un solo valor hexadecimal.

En el ejemplo CTRLTEST se ilustran las ventajas y los inconvenientes de utilizar un archivo .rc2 en un cuadro de diálogo que tiene un control personalizado con estilos definidos mediante constantes en un archivo de encabezado. Los cuadros de diálogo IDD_WNDCLASS_EDIT e IDD_SPIN_EDIT tienen controles personalizados con estilos definidos simbólicamente; pero IDD_WNDCLASS está especificado en un archivo .rc modificable en el editor de cuadros de diálogo de Visual C++, mientras que IDD_SPIN_EDIT está especificado en un archivo .rc2 que sólo se puede editar manualmente.

Las diferencias entre el uso del archivo .rc y el archivo .rc2 se pueden resumir de la manera siguiente.

Las secuencias de comandos de recursos del cuadro de diálogo IDD_WNDCLASS_EDIT están definidas en Ctrltest.rc. Las secuencias de comandos de recursos del cuadro de diálogo IDD_SPIN_EDIT están definidas en RES\Ctrltest.rc2. En el cuadro de diálogo IDD_WNDCLASS_EDIT, el control personalizado WNDCLASS es "paredit", las constantes de estilo se definen en PAREDIT.H y un ejemplo de constante de estilo es PES_NUMBER. IDD_WNDCLASS_EDIT se puede editar en Visual C++ pero no puede utilizar los estilos #define. IDD_SPIN_EDIT no se puede modificar en Visual C++ pero puede utilizar los estilos #define.

Si utiliza el archivo .rc2, puede utilizar los estilos simbólicos legibles definidos en el archivo de encabezado para el control personalizado, pero no puede editar el archivo .rc2 con el editor de cuadros de diálogo de Visual C++. Es más fácil diseñar el cuadro de diálogo en Visual C++ que escribir manualmente una secuencia de comandos de recursos; además, es más fácil cometer errores con esta segunda opción. Por otra parte, los estilos no proporcionan documentación cuando se muestran en hexadecimal en la página de control personalizada en el editor de cuadros de diálogo de Visual C++.

Palabras clave

En este ejemplo, se muestra el uso de las siguientes palabras clave:

AfxGetInstanceHandle; AfxMessageBox; AfxThrowResourceException; CBitmapButton::AutoLoad; CDC::FillRect; CDC::FrameRect; CDialog::DoModal; CDialog::EndDialog; CDialog::OnInitDialog; CDialog::OnOK; CDialog::OnSetFont; CEdit::Create; CEdit::SetSel; CFrameWnd::Create; CListBox::AddString; CListBox::CompareItem; CListBox::DrawItem; CListBox::GetItemData; CListBox::MeasureItem; CMenu::AppendMenu; CMenu::CreateMenu; CMenu::Detach; CMenu::DrawItem; CMenu::EnableMenuItem; CMenu::FromHandle; CMenu::GetMenuString; CMenu::MeasureItem; CRect::Width; CStatic::Create; CString::Format; CString::LoadString; CWinApp::InitInstance; CWnd::Attach; CWnd::EnableWindow; CWnd::FromHandle; CWnd::GetDlgCtrlID; CWnd::GetDlgItem; CWnd::GetDlgItemInt; CWnd::GetMenu; CWnd::GetParent; CWnd::GetWindowRect; CWnd::GetWindowText; CWnd::IsWindowEnabled; CWnd::MessageBox; CWnd::OnChar; CWnd::OnCommand; CWnd::OnVScroll; CWnd::PostNcDestroy; CWnd::SendMessage; CWnd::SetDlgItemInt; CWnd::SetFocus; CWnd::SetFont; CWnd::SetWindowPos; CWnd::ShowWindow; CWnd::SubclassDlgItem; CallWindowProc; GetBValue; GetClassInfo; GetGValue; GetRValue; GetSystemMetrics; HIWORD; IsCharAlpha; IsCharAlphaNumeric; LOWORD; MAKEINTRESOURCE; MAKELONG; MessageBeep; ModifyMenu; RGB; RegisterClass; SetWindowLong

Nota:

Algunos ejemplos, como éste, no se han modificado para reflejar los cambios en los asistentes, las bibliotecas y el compilador de Visual C++, pero, aun así, muestran cómo realizar la tarea deseada.

Vea también

Otros recursos

Ejemplos de MFC