19 Controles de lista reorganizables
Dentro de la gran variedad de controles de lista que nos ofrece wxWidgets, en este capítulo veremos otros dos orientados a listas con casillas de chequeo con un orden determinado de los ítems.
Además veremos otro control que ademas de ordenar los ítems, permite editarlos, borrarlos o añadir nuevos.
Control wxRearrangeList

El primer control, wxRearrangeList, es el más simple, y únicamente muestra un control de lista con casillas de chequeo.
Constructor
La ventaja es que podemos indicar en el constructor tanto los ítems que contendrá el control como su orden y el estado de sus marcas de chequeo.
Esto se hace mediante dos arrays. Los ítems se especifican en un array de cadenas, wxArrayString, y sus posiciones y marcas mediante un array de enteros, wxArrayInt.
Podemos usar un objeto de una clase que contenga estos dos arrays para pasarle los datos al diálogo que contiene el control. Por ejemplo:
class datosItems { public: wxArrayInt orden; wxArrayString items; };
El array de orden contiene para cada ítem dos datos en el mismo entero. El índice dentro del array corresponde con el índice en el control. El valor de cada entero indica la posición, y para indicar si el ítem está marcado o no se invierte binariamente el valor primario. Si el valor está sin invertir, el ítem estará marcado. Un valor invertido indica que el ítem no está marcado.
Por ejemplo:
datos.orden.push_back(~1); datos.orden.push_back(5); datos.orden.push_back(2); datos.orden.push_back(~6); datos.orden.push_back(~3); datos.orden.push_back(0); datos.orden.push_back(~4); datos.items.push_back(_T("Primero")); datos.items.push_back(_T("Segundo")); datos.items.push_back(_T("Tercero")); datos.items.push_back(_T("Cuarto")); datos.items.push_back(_T("Quinto")); datos.items.push_back(_T("Sexto")); datos.items.push_back(_T("Séptimo"));
El primer valor del array es ~1, que indica que el primer elemento del control será el segundo del array de cadenas (los índices empiezan en 0), y que no estará marcado. El segundo valor es 5, que indica que el segundo elemento del control será el sexto del array de cadenas y estará marcado, etc.
Con esto en cuenta, crear un control de este tipo es sencillo:
lista = new wxRearrangeList(this, idList, wxDefaultPosition, wxDefaultSize, datos.orden, datos.items);
Basta con especificar en los parámetros quinto y sexto los arrays de orden y cadenas respectivamente. El resto de parámetros son los habituales.
Estilos
En el séptimo parámetro podemos añadir algunos estilos, aunque estos controles no disponen de estilos propios, se pueden usar los de sus clases base, aunque algunos, como wxLB_SORT no tienen efecto.
Otros estilos, como el de selección múltiple, impedirán reordenar la lista.
Mover ítems
Esta clase dispone de un par de métodos para mover el ítem actualmente seleccionado arriba, MoveCurrentUp o abajo, MoveCurrentDown. Además de otros dos métodos para averiguar si el elemento actualmente seleccionado puede moverse hacia arriba, CanMoveCurrentUp o hacia abajo, CanMoveCurrentDown.
Podemos añadir un par de botones para ordenar los ítems del control, y procesar sus pulsaciones:
void RearrangeList::OnButtonUp(wxCommandEvent& event) { if(lista->CanMoveCurrentUp()) lista->MoveCurrentUp(); } void RearrangeList::OnButtonDown(wxCommandEvent& event) { if(lista->CanMoveCurrentDown()) lista->MoveCurrentDown(); }
Recuperar el orden
Finalmente, el método GetCurrentOrder obtiene el orden actual de los ítems del control, así como el estado de sus marcas de chequeo.
void RearrangeList::OnOk(wxCommandEvent& event) { datos.orden = lista->GetCurrentOrder(); EndModal(wxID_OK); }
No hay ningún método para recuperar los ítems, puesto que no hay forma de modificar sus valores ni su cantidad.
Control wxRearrangeCtrl

Por otra parte, los controles wxRearrangeCtrl, que no se derivan de wxRearrangeList, sino que se tratan de un panel que incluye uno de esos controles e incorporan los botones para reordenar los ítems.
Un panel, que veremos en otro capítulo, es una forma de agrupar controles.
Esto nos facilita la tarea si necesitamos reordenar los ítems, y usar los controles wxRearrangeList cuando el orden no importe, o cuando queramos personalizar los botones para reordenar los ítems.
El constructor es idéntico al de la clase wxRearrangeList.
Recuperar el orden
Este control no dispone de métodos para recuperar el orden de los ítems. En su lugar tendremos que usar el método GetList para recuperar la parte del control de lista del panel y así poder acceder a su método GetCurrentOrder cuando queramos recuperar el orden y estado de los ítems.
void RearrangeCtrl::OnOk(wxCommandEvent& event) { datos.orden = lista->GetList()->GetCurrentOrder(); EndModal(wxID_OK); }
Control wxEditableListBox

El tercer control de lista que veremos en este capítulo que también permite ordenar los ítems es wxEditableListBox. A diferencia de los anteriores, el orden no se indica mediante un array de enteros, sino que se deduce del propio orden del array de cadenas. Tampoco se añaden casillas de chequeo a los ítems.
Además, estos controles permiten editar, añadir y eliminar ítems mediante algunos botones adicionales.
Como en el caso de los controles wxRearrangeCtrl, se trata de una clase derivada de la clase wxPanel, que incluye la lista y los botones asociados.
Constructor
Los parámetros del constructor de este control varían de la norma general. Los dos primeros son lo habituales, ventana padre e identificador, pero el tercero es un texto que se usa como etiqueta en el encabezado del control. El resto son la posición, tamaño, estilos y nombre del control, opcionales.
lista = new wxEditableListBox(this, idList, "&Editar", wxDefaultPosition, wxDefaultSize, wxEL_DEFAULT_STYLE);
Estilos
Estos controles disponen de varios estilos propios que permiten desactivar algunas de las opciones de editar, añadir, borrar u ordenar ítems.
Por defecto toda las opciones están activas, pero podemos desactivar cada acción, combinando los estilos adecuados:
- wxEL_ALLOW_NEW: si no se especifica no será posible añadir ítems.
- wxEL_ALLOW_EDIT: si no se especifica no será posible editar ítems.
- wxEL_ALLOW_DELETE: si no se especifica no será posible borrar ítems.
- wxEL_NO_REORDER: si se especifica no se podrá modificar el orden de los ítems.
Hay que tener en cuenta que se se activa el estilo wxEL_ALLOW_NEW, también se activará wxEL_ALLOW_EDIT, aunque no se indique explícitamente. Esto es lógico, puesto que en caso contrario no sería posible establecer el valor de los nuevos ítems.
Ítems
Para establecer los ítems del contenido de la lista se usa el método SetStrings, indicando como parámetro una lista de cadenas en un objeto wxArrayString.
lista->SetStrings(datos.items);
Para recuperar el contenido de la lista se usa el método GetStrings, usando como parámetro una referencia a una lista de cadenas, en un objeto wxArrayString.
void EditableListBox::OnOk(wxCommandEvent& event) { lista->GetStrings(datos.items); EndModal(wxID_OK); }
Control wxAddRemoveCtrl

Los controles wxAddRemoveCtrl no permiten reordenar los ítems, pero ofrecen la posibilidad de añadirlos o eliminarlos.
Como en el caso de los controles wxEditableListBox, se trata de un panel en el que podemos insertar un control de lista, que no tiene que ser necesariamente un wxListBox, puede ser también un wxListCtrl, wxTreeCtrl o un wxDataViewCtrl, al que se le añaden dos botones que permiten añadir o eliminar ítems.
Crear uno de estos controles no es tan simple como los anteriores, y hay que seguir ciertos pasos:
- Crear el propio control wxAddRemoveCtrl.
- Crear el control de lista, indicando en el primer parámetro como ventana padre el control wxAddRemoveCtrl.
- Crear un objeto de una clase derivada de wxAddRemoveAdaptor. Esta clase se encargará de inhibir los botones de añadir o eliminar ítems y de añadirlos o borrarlos.
- Establecer el objeto adaptor como el adaptador del control. Para ello se usa l método SetAdaptor.
- Añadir el control a la ventana, ya sea un marco o un diálogo.
control = new wxAddRemoveCtrl(this, idAddRemove, wxDefaultPosition, wxSize(100,100)); lbox = new wxListBox(control, idlistbox, wxDefaultPosition, wxDefaultSize, datos.items); adaptor = new MiAdaptor(lbox); control->SetAdaptor(adaptor); boxVertical->Add(control, wxSizerFlags().Expand().Border());
La clase wxAddRemoveAdaptor es una clase virtual pura, de la que tendremos que derivar nuestra clase adaptadora, que se encargará de sobrecargar sus métodos en función de nuestras necesidades.
Los métodos que hay que sobrescribir de esta clase son:
- CanAdd: que debe devolver true si es posible añadir un elemento a la lista. En ese caso se habilita el botón de añadir. El que sea posible o no añadir elementos dependerá de cada aplicación.
- CanRemove: que debe devolver true si el elemento seleccionado puede ser eliminado. Esto habilitará el botón de borrado. De nuevo, esto dependerá de nuestra aplicación. Ese botón no estará habilitado tampoco si no hay ningún elemento seleccionado.
- GetItemsCtrl: debe devolver la ventana asociada al control de lista asociado al control.
- OnAdd: es el procedimiento que será invocado cuando el usuario pulse el botón de añadir elemento.
- OnRemove: es el procedimiento que será invocado cuando el usuario pulse el botón de eliminar elemento.
La personalización de estos métodos nos permitirá, por ejemplo, limitar el número de elementos en la lista, evitar que ciertos elementos sean eliminados, editar el valor de un elemento antes de añadirlo, o asignarle un valor automáticamente, etc.
Por ejemplo, veamos un adaptador usando un wxListCtrl que permita añadir, modificar y eliminar ítems.
Usaremos un control wxListCtrl, en vista de reporte, con una única columna y si cabeceras porque proporciona una forma sencilla de editar ítems.
Añadiremos algunas limitaciones para ilustrar el funcionamiento de estos controles. No dejaremos eliminar los primeros siete elementos del control, ni tampoco dejaremos añadir más de quince elementos:
class MiAdaptor: public wxAddRemoveAdaptor { public: explicit MiAdaptor(wxListCtrl* lbox) : m_lbox(lbox) {} wxWindow* GetItemsCtrl() const wxOVERRIDE { return m_lbox; } // Sólo se puede añadir un elemento si contiene menos de 15 bool CanAdd() const wxOVERRIDE { return (m_lbox->GetItemCount()<15); } // Sólo se puede eliminar un elemento si está seleccionado y no es uno de los 7 primeros bool CanRemove() const wxOVERRIDE { long item = m_lbox->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); return (item != -1 && item > 6); } // Añadimos un nuevo elemento al final y lo editamos void OnAdd() wxOVERRIDE { long item = m_lbox->GetItemCount(); m_lbox->InsertItem(item, "nuevo"); m_lbox->EditLabel(item); } // Eliminamos el elemento actualmente seleccionado void OnRemove() wxOVERRIDE { long item = m_lbox->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); m_lbox->DeleteItem(item); } private: wxListCtrl* m_lbox; };
Para crear el control usaremos el código siguiente:
control = new wxAddRemoveCtrl(this, idAddRemove, wxDefaultPosition, wxSize(100,150)); lbox = new wxListCtrl(control, idlistbox, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_EDIT_LABELS | wxLC_NO_HEADER); lbox->InsertColumn(0, _T("")); lbox->SetColumnWidth(0, 100); for(size_t i=0; i<datos.items.size(); i++) { lbox->InsertItem(i, datos.items[i]); } adaptor = new MiAdaptor(lbox); control->SetAdaptor(adaptor);
Ejemplo 19
Windows:
Nombre | Fichero | Fecha | Tamaño | Contador | Descarga |
---|---|---|---|---|---|
Ejemplo 19 | wx019.zip | 2025-04-25 | 11311 bytes | 11 |
Linux:
Nombre | Fichero | Fecha | Tamaño | Contador | Descarga |
---|---|---|---|---|---|
Ejemplo 19 | wx019.tar.gz | 2025-04-25 | 6273 bytes | 11 |