Tutorial WinAPI C++ 3.5 (Creación del ObjetoComboBox)
Categorías : Windows, Programación, C y C++.

En windows un combobox es un control que consiste en un EDITBOX que tiene un BUTTON al lado, y que al presionar ese button despliega un LISTBOX con varias opciones.
En este tutorial veremos el funcionamiento básico del COMBOBOX, y lo encapsularemos dentro de la clase ObjetoComboBox. Esta clase heredara de ObjetoControlEstandar (La clase ObjetoControlEstandar se describe en el tutorial 3.3 Creación del ObjetoEditBox)
Tenemos que tener bien claro para que vamos a querer usar este control, ya que podemos usarlo como una forma de seleccionar opciones fijas, o tambien podria servirnos para otros fines que no requieran opciones fijas, como por ejemplo insertar un texto a buscar que nos muestre otras posibilidades, etc...
Veamos su declaración :
// Clase que hereda ObjetoControlEstandar y se centra en las funciones del comboboxclass ObjetoComboBox : public ObjetoControlEstandar {public : //////// Miembros publicos// -ConstructorObjetoComboBox(void);// -Destructor~ObjetoComboBox(void);// -Función para crear el ComboBoxvoid CrearComboBox(HWND hWndParent, const UINT nEstilos, const TCHAR *nTexto,const int cX, const int cY,const int cAncho, const int cAlto, const UINT nID );// -Función para agregar un texto a la posición especificada// Si omitimos nPos se agregara al finalvoid InstertarString(const TCHAR *nTxt, const UINT nPos = UINT_MAX);// -Función para seleccionar un string de la listavoid Seleccion(const UINT nPos);// -Función obtener la selección de la listaUINT Seleccion(void);// -Función para borrar el texto de la posición especificadavoid BorrarString(const UINT nPos);// -Función que borra todos los strings del ComboBoxvoid BorrarTodo(void);// -Función que retorna el total de strings que tiene el ComboBoxconst UINT TotalStrings(void);// -Función para asignar el texto del comboboxBOOL AsignarTexto(const TCHAR *nTxt);// -Función para obtener el texto del comboboxUINT ObtenerTexto(TCHAR *nTxt, const UINT TamTxt);// -Función para obtener el texto de una posicion especificada dentro// del LISTBOX de la COMBOBOX.// Para estar seguros de que la función se ha realizado correctamente// el resultado devuelto tiene que ser mas grande que cero.UINT ObtenerTextoLista(const UINT Pos, TCHAR *nTxt, const UINT TamTxt);protected :HFONT _Fuente;};
Lo primero que vemos es una función para crear la ComboBox, después tenemos varias funciones para manipular los strings de la lista interna del ComboBox : InsertarString, BorrarString, BorrarTodo, y ObtenerTextoLista. También tenemos un par de funciones que nos retornan el texto del editbox interno : AsignarTexto y ObtenerTexto. Y por ultimo tenemos dos funciones para asignar y obtener la selección dentro de la lista interna de la ComboBox.
Veamos la función CrearComboBox :
// Función para crear el ComboBoxvoid ObjetoComboBox::CrearComboBox( HWND hWndParent, const UINT nEstilos, const TCHAR *nTexto,const int cX, const int cY, const int cAncho, const int cAlto, const UINT nID ) {// Iniciamos los CommonControlsObjetoIniciarCommonControls::Iniciar();// Creamos el control_hWnd = CreateWindowEx( NULL, TEXT("COMBOBOX"), 0, nEstilos, cX, cY, cAncho, cAlto, hWndParent,reinterpret_cast<HMENU>(IntToPtr(nID)), GetModuleHandle(NULL), NULL );// Asignamos el texto al EDITBOX que tiene dentro la COMBOBOXSetDlgItemText(hWndParent, nID, nTexto);_ConectarControl();// Creamos la fuente que usara el control_Fuente = CreateFont( 13, 0, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FF_ROMAN, TEXT("Tahoma") );// Asignamos la fuenteSendMessage(_hWnd, WM_SETFONT, (WPARAM)_Fuente , 0);}
Lo primero que se hace es llamar a la función ObjetoIniciarCommonControls::Iniciar. Esta función llama a la API InitCommonControlsEx para iniciar los controles estándar de windows para nuestra aplicación. Antiguamente en VC6 esto era necesario si queríamos trabajar con controles estándar, pero ahora mismo a decir verdad ya no se si es necesario, porque en mi maquina me funcionan igual los ejemplos tanto si llamo a InitCommonControlsEx como si no… y en la MSDN no dice nada.. Por lo que prefiero mantener este código por si las moscas.
Lo segundo que se hace es llamar a la API CreateWindowEx con el segundo parámetro “COMBOBOX” (que es el nombre de la clase). Esto hace que el control creado se convierta en un COMBOBOX. Para ver más nombres de control mira este enlace de la MSDN : CreateWindow (Casi al final hay una tabla que muestra los nombres de classe mas comunes)
Lo siguiente es asignar el texto especificado al EditBox interno, y llamar a la función _ConectarControl, que re-emplazara el WindowProcedure del ComboBox por el nuestro.
Y por último creamos una fuente con la API CreateFont para el button, y le mandamos el mensaje WM_SETFONT al editbox con la API SendMessage, cosa que le dirá al ComboBox que debe usar esa fuente.
Ahora veamos las funciones para interactuar con el ListBox interno de la ComboBox :
// -Funcion para agregar un texto a la posición especificada// Si omitimos nPos se agregara al finalvoid ObjetoComboBox::InstertarString(const TCHAR *nTxt, const UINT nPos) {SendMessage(_hWnd, CB_INSERTSTRING, nPos, (LPARAM)nTxt);}// -Funcion para borrar el texto de la posición especificadavoid ObjetoComboBox::BorrarString(const UINT nPos) {SendMessage(_hWnd, CB_DELETESTRING, nPos, 0);}// -Función que borra todos los strings del comboboxvoid ObjetoComboBox::BorrarTodo(void) {SendMessage(_hWnd, CB_RESETCONTENT, 0, 0);};// -Función que retorna el total de strings que tiene el comboboxconst UINT ObjetoComboBox::TotalStrings(void) {return static_cast<UINT>(SendMessage(_hWnd, CB_GETCOUNT, 0, 0));}// Función para obtener texto del LISTBOX interior del COMBOBOX// Si la funcion retorna 0 es que ha sucedido un errorUINT ObjetoComboBox::ObtenerTextoLista(const UINT nPos, TCHAR *nTxt, const UINT TamTxt) {// Comprobamos que nTxt tenga el suficiente tamaño para obtener el texto especificadoUINT TamTextoLista = SendMessage(_hWnd, CB_GETLBTEXTLEN, nPos, NULL);if (TamTextoLista > TamTxt) {// Error, el buffer introducido no tiene tamaño suficiente para el texto que se quiere obtenerreturn 0;}// Obtenemos el texto de la posición especificadareturn SendMessage(_hWnd, CB_GETLBTEXT, nPos, reinterpret_cast<LPARAM>(nTxt));}
Podemos ver 5 funciones diseñadas para trabajar con el contenido del ListBox interno de la ComboBox :
- La función InsertarString manda el mensaje CB_INSERTSTRING con la API SendMessage para insertar un texto dentro de la lista del ComboBox.
- La función BorrarString manda el mensaje CB_DELETESTRING con la API SendMessage para eliminar el texto especificado por nPos dentro de la lista del ComboBox.
- La función BorrarTodo manda el mensaje CB_RESETCONTENT con la API SendMessage para eliminar el contenido de la lista del ComboBox.
- La función TotalStrings manda el mensaje CB_GETCOUNT con la API SendMessage para obtener el número total de items dentro de la lista interna del ComboBox.
- La función ObtenerTextoLista lo primero que hace es mandar el mensaje CB_GETTEXTLEN apuntando al item especificado en nPos para obtener el tamaño en caracteres de ese string. Una vez sabemos el tamaño del string mandamos el mensaje CB_GETLBTEXT con la API SendMessage, lo que nos retorna el texto del item especificado en nPos.
Ahora veamos las funciones de Selección :
// -Función para seleccionar un string de la listavoid ObjetoComboBox::Seleccion(const UINT nPos) {SendMessage(_hWnd, CB_SETCURSEL, nPos, 0);}// -Función para seleccionar un string de la listaUINT ObjetoComboBox::Seleccion(void) {return SendMessage(_hWnd, CB_GETCURSEL, 0, 0);}
La primera función se usa para asignar la selección, y en ella mandamos el mensaje CB_SETCURSEL con la API SendMessage. La segunda función se usa para obtener la selección, y en ella mandamos el mensaje CB_GETCURSEL con la API SendMessage para hacer el trabajo.
Ya solo nos queda ver las funciones ObtenerTexto y AsignarTexto :
// Función para obtener el texto del comboboxUINT ObjetoComboBox::ObtenerTexto(TCHAR *nTxt, const UINT TamTxt) {return GetDlgItemText(GetParent(_hWnd), GetWindowLongPtr(_hWnd, GWL_ID), nTxt, TamTxt);}// Función para asignar el texto del comboboxBOOL ObjetoComboBox::AsignarTexto(const TCHAR *nTxt) {return SetDlgItemText(GetParent(_hWnd), GetWindowLongPtr(_hWnd, GWL_ID), nTxt);}
Para obtener el texto del ComboBox utilizamos la API GetDlgItemText, y para asignarlo utilizamos la API SetDlgItemText. Además utilizamos la API GetWindowLongPtr para obtener la ID del button que necesitamos a la hora de asignar / obtener su texto.
Ahora solo nos falta saber como responder a los eventos de la ComboBox. Para ello normalmente se tiene que mirar el mensaje WM_COMMAND, o en este caso como lo tenemos encapsulado lo recibiremos por Evento_Comando de su ventana padre. Observad el siguiente ejemplo :
ERROR!! no se ha encontrado el archivo : './Tutoriales_WinAPI/3.05 Tutorial crear ObjetoComboBox/3.5 Tutorial crear ObjetoComboBox.cpp'
Como podeis ver, comparamos la ID con ID_COMBO y la Notificación con CBN_SELCHANGE, para determinar si ha cambiado la selección dentro del listbox interno de la ComboBox. Si la comparación es positiva mostramos un mensaje con el texto de la selección.
Para mas información referente al control ComboBox consulta el siguiente enlace de la MSDN : ComboBox Control.
Siguiente tutorial : 3.6 Creación del ObjetoProgressBar.