5 Control de edición
El siguiente control básico que veremos nos permite introducir valores en forma de texto o números desde el teclado. Me refiero a los controles de edición, que se encapsulan en la clase wxTextCtrl.
Todos los controles que permiten introducir texto, existen otros además de wxTextCtrl, derivan de la clase wxControl, pero también lo hacen de la clase wxTextEntry, por lo que tendrán acceso a métodos de ambas clases.
En muchos casos nos interesará restringir los datos que introduzca un usuario. Puede que solo queramos leer una cadena, pero a menudo nos interesa leer números enteros, o texto en mayúsculas, etc. Es decir, querremos validar los datos introducidos en un control de edición incluso antes de que el usuario los envíe a la aplicación pulsando Retorno o el botón de aceptar.
Aunque no es imprescindible, la mejor forma de hace esto es usar validadores. Los validadores nos ayudarán a recuperar los valores introducidos por el usuario y opcionalmente, también validarlos. Además, la clase wxTextCtrl también dispone de métodos para establecer valores iniciales y para recuperar valores desde el control, sin necesidad de usar validadores.
Etiquetas
Aunque tampoco sea obligatorio, es habitual que a cada control de edición de texto se le asocie un control estático de texto que sirve para indicar al usuario qué tipo de dato se debe introducir. Estos textos se denominan etiquetas, y generalmente se sitúan a la izquierda o encima del control de edición de texto, aunque de nuevo, esto no es obligatorio.
Aunque se trate de controles estáticos, y evidentemente no pueden obtener el foco del teclado, es buena idea usar un acelerador en esas etiquetas, ya que el foco se asigna al siguiente control en el orden Z.
El orden Z es el orden en que se insertan los controles en una ventana o diálogo. Es también el orden en que se asigna el foco al usar la tecla TAB.
Por eso, si queremos que los aceleradores en las etiquetas establezcan el foco de teclado en el control que etiquetan es importante que la etiqueta y el control correspondiente tengan posiciones correlativas en el orden Z, y en ese orden.
Usar validadores
Usar validadores tiene varias ventajas interesantes.
Por una parte, no tenemos que preocuparnos por establecer el contenido inicial del control, el validador lo hace por nosotros automáticamente.
Tampoco tenemos que actualizar la variable a partir del contenido del control, de nuevo, el validador lo hace automáticamente al pulsar el botón de aceptar.
Ciertos estilos de validadores, en general los filtros, impiden directamente que se introduzcan valores no permitidos. Por ejemplo, el filtro wxFILTER_ALPHA no permitirá que el usuario introduzca caracteres no alfabéticos, como números, espacios o signos de puntuación.
Otros validadores actúan solo cuando se valida el diálogo al pulsar el botón de aceptar, de modo que si el control tiene un contenido no válido se muestra un mensaje de error y el diálogo no se cierra, permitiendo al usuario corregir las entradas no válidas.
Esto simplifica mucho el código a la hora de obtener ciertos datos:
wxTextValidator val = wxTextValidator(wxFILTER_ALPHA | wxFILTER_SPACE, cad); wxTextCtrl* editCtrl = new wxTextCtrl(this, idtexto, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, val); boxHorizontal->Add(new wxStaticText(this, wxID_ANY, _T("&Texto alfanumérico:")), wxSizerFlags().Border()); boxHorizontal->Add(editCtrl, wxSizerFlags().Border());
Diálogo básico de captura de datos
Aunque existen muchas formas de capturar datos introducidos por usuarios vamos a ver una manera sencilla de hacerlo: el cuadro de diálogo básico.
Estructura de datos
Salvo cuando la estructura de los datos a obtener sea muy simple: un booleano, una cadena o un número, es buena idea crear una clase o estructura para encapsular los datos que deben leerse desde un diálogo. De este modo solo necesitaremos una referencia a un objeto, en lugar de una por cada uno de los datos individuales a capturar.
Veamos esto con un ejemplo. Supongamos que tenemos que obtener los datos de un usuario: nombre, dirección de correo y número de teléfono. Para ello crearemos una clase que contenga esos datos:
class datosUsuario { public: datosUsuario(const wxString &n, const wxString &e, const wxString &t) : nombre(n), email(e), telefono(t) {} wxString nombre; wxString email; wxString telefono; };
Esto es una versión muy simple, los datos miembro están declarados como públicos, lo que nos ahorra la tarea de añadir una interfaz, pero en otros casos podemos complicar esta clase tanto como sea preciso.
De este modo es mucho más simple pasar una referencia a un único objeto al diálogo, en lugar de usar varias referencias en distintos parámetros, lo que complicaría el proceso innecesariamente:
class editarUsuario: public wxDialog { public: editarUsuario(wxWindow *wnd, datosUsuario &datos); protected: enum { idNombre = 1000, idEmail, idTelefono }; private: wxTextCtrl* ctrlNombre; wxTextCtrl* ctrlEmail; wxTextCtrl* ctrlTelefono; void OnClose(wxCloseEvent& event); DECLARE_EVENT_TABLE() };
El constructor de este diálogo solo insertará los controles necesarios, y el método OnClose simplemente destruye el diálogo. No es necesario procesar eventos procedentes de ningún control ni de ningún botón, siempre que creemos los botones de aceptar y cancelar con los identificadores correctos, es decir, wxOK y wxCANCEL.
#include "editartexto.h" BEGIN_EVENT_TABLE(editarUsuario, wxDialog) EVT_CLOSE(editarUsuario::OnClose) END_EVENT_TABLE() editarUsuario::editarUsuario(wxWindow *wnd, datosUsuario &datos) : wxDialog(wnd, -1, _T("Ejemplo edición de usuario")) { wxBoxSizer *boxVertical; wxBoxSizer *boxHorizontal; wxTextValidator valNombre = wxTextValidator(wxFILTER_ALPHA | wxFILTER_SPACE, &datos.nombre); wxTextValidator valEmail = wxTextValidator(wxFILTER_ALPHANUMERIC | wxFILTER_INCLUDE_CHAR_LIST, &datos.email); wxTextValidator valTelefono = wxTextValidator(wxFILTER_NUMERIC, &datos.telefono); valEmail.AddCharIncludes("@."); boxVertical = new wxBoxSizer(wxVERTICAL); boxHorizontal = new wxBoxSizer(wxHORIZONTAL); boxHorizontal->Add(new wxStaticText(this, wxID_ANY, _T("&Nombre:")), wxSizerFlags().Border()); boxHorizontal->Add(new wxTextCtrl(this, idNombre, wxEmptyString, wxDefaultPosition, wxSize(200, wxDefaultCoord), 0, valNombre), wxSizerFlags().Border()); boxVertical->Add(boxHorizontal, wxSizerFlags().Border(wxTOP).Right()); boxHorizontal = new wxBoxSizer(wxHORIZONTAL); boxHorizontal->Add(new wxStaticText(this, wxID_ANY, _T("&Email:")), wxSizerFlags().Border()); boxHorizontal->Add(new wxTextCtrl(this, idEmail, wxEmptyString, wxDefaultPosition, wxSize(200, wxDefaultCoord), 0, valEmail), wxSizerFlags().Border()); boxVertical->Add(boxHorizontal, wxSizerFlags().Border(wxTOP).Right()); boxHorizontal = new wxBoxSizer(wxHORIZONTAL); boxHorizontal->Add(new wxStaticText(this, wxID_ANY, _T("&Telefono:")), wxSizerFlags().Border()); boxHorizontal->Add(new wxTextCtrl(this, idTelefono, wxEmptyString, wxDefaultPosition, wxSize(200, wxDefaultCoord), 0, valTelefono), wxSizerFlags().Border()); boxVertical->Add(boxHorizontal, wxSizerFlags().Border(wxTOP).Right()); boxVertical->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Border()); SetSizerAndFit(boxVertical); } void editarUsuario::OnClose(wxCloseEvent &event) { Destroy(); }
Estilos generales
Los controles de edición soportan varios estilos diferentes. Veamos algunos de ellos.
El estilo wxTE_PASSWORD no mostrará el contenido real del control, sustituyendo los caracteres por asteriscos. Este estilo está pensado para ocultar información introducida por el usuario a otras personas que puedan estar viendo la pantalla, por ejemplo, cuando se introducen contraseñas.
El estilo wxTE_READONLY impide que el usuario pueda modificar el contenido del control. En la práctica se comporta como un control de texto estático, pero sigue siendo un control de edición.
Este estilo se puede cambiar durante la ejecución usando el método SetEditable, indicando como parámetro el valor true para que se pueda editar, o false para activar el estilo de solo lectura.
El estilo wxTE_PROCESS_ENTER hace que el control genere eventos wxEVT_TEXT_ENTER cuando el usuario pulsa la tecla ENTER. Se puede usar para evitar el comportamiento por defecto cuando se pulsa esa tecla.
Los estilos de justificación de texto wxTE_LEFT (por defecto), wxTE_CENTRE y wxTE_RIGHT sirven para justificar el texto del control a la izquierda, centrado o a la derecha, respectivamente.
Pistas de contenido
Existe la posibilidad de prescindir de las etiquetas, o al menos de algunas de ellas, usando en su lugar "pistas" o "hints". Estas pistas consisten en un texto que se mostrará en el control de edición cuando no tenga contenido. Es decir, el control nunca aparecerá vacío, cuando no contenga un texto se mostrará la pista, que generalmente sustituye o complementa a la etiqueta. Se puede usar también como una plantilla del formato que se espera. Por ejemplo, para leer un nombre podría ser: "apellido, nombre", para un número de teléfono "(+34) 123123231", etc.
Para establecer el texto de una pista se usa el método SetHint y para recuperar el valor actual de una pista GetHint.
edit = new wxTextCtrl(this, idNombre, wxEmptyString, wxDefaultPosition, wxSize(200, wxDefaultCoord), 0, valNombre); boxHorizontal->Add(edit, wxSizerFlags().Border()); edit->SetHint(_T("nombre apellido"));
Obtener y asignar datos a un control de edición
A veces necesitaremos modificar o recuperar el contenido de un control de edición antes de cerrar el diálogo.
Para recuperar el valor actual de la cadena desde un control wxTextCtrl usaremos el método GetValue, heredado de la clase wxTextEntry:
wxString contenido; contenido = ctrlTexto->GetValue();
También podemos obtener parte del contenido del control mediante el método GetRange.
wxString val = ctrlTexto->GetRange(5, 16);
Para asignar valores a un control wxTextCtrl tenemos varias alternativas. Podemos usar, por ejemplo, el método SetValue, también heredado de la clase wxTextEntry:
ctrlRepetir->SetValue(contenido);
El método ChangeValue funciona igual que SetValue, salvo que no genera eventos EVT_TEXT.
El método WriteText añade el texto pasado como parámetro en el punto de inserción actual.
A veces será más cómodo usar el operador <<, ya que está sobrecargado para varios tipos de datos: cadenas, caracteres, enteros y valores en coma flotante.
Un pequeño inconveniente de usar este operador es que el valor indicado se añade al final del contenido actual del control. Si queremos partir de un contenido limpio podemos usar el método Clear.
Por otra parte, el método AppendText se comporta igual que el operador, aunque solo admite como parámetro una cadena.
Si nos interesa saber si un control contiene texto, sin necesidad de leer su contenido, sobre todo en controles multilínea que pueden contener mucho texto, podemos usar el método IsEmpty, que devolverá true si el control está vacío.
Control de edición multilínea
Si se especifica el estilo wxTE_MULTILINE al crear el control se podrán editar textos de varias líneas. Por defecto este estilo no está activado, lo que significa que el control no podrá contener caracteres de salto de línea.
El método GetValue recuperará el contenido completo del control, pero también podemos obtener el valor de líneas individuales mediante el método GetLineText, indicando como parámetro el valor de la línea, comenzando en cero. Para obtener el número de líneas podríamos usar el método GetNumberOfLines. Este método devuelve el número de retornos de línea más uno, no el número de líneas físicas mostradas en el control, salvo en Windows, que sí devuelve el número de líneas físicas, por eso no es recomendable usar esta función.
También podemos obtener la longitud de una línea mediante el método GetLineLength, indicando como parámetro el número de línea. Se excluyen de la cuenta los caracteres de retorno de línea. Si el valor de línea especificado no es válido, el valor de retorno es -1.
Otros dos métodos interesantes son IsMultiLine y IsSingleLine, que nos indican si un control es multilínea o no, respectivamente.
Existen algunos estilos propios de los controles multilínea:
El estilo wx_PROCESS_TAB evita que las pulsaciones de la tecla TAB pasen el foco al siguiente control. En su lugar se insertará un carcácter TAB en el control.
Los estilos wxTE_RICH y wxTE_RICH2 crean un control de texto enriquecido, aunque el primero está desaconsejado. Estos estilos permiten introducir texto de más de 64KiB.
El estilo wxTE_AUTO_URL detecta y destaca URLs, y además genera eventos wxTextUrlEvent cuando se producen eventos de ratón sobre ellas. (En la wiki se menciona que esto solo funciona en Windows, aunque no he podido verificar si funciona en otros sistemas, de modo que evitaremos usarlo en favor de la portabilidad).
BEGIN_EVENT_TABLE(multilinea, wxDialog) ... EVT_TEXT_URL(idTexto, multilinea::OnURL) ... END_EVENT_TABLE() ... void multilinea::OnURL(wxTextUrlEvent &event) { long inicio = event.GetURLStart(); long fin = event.GetURLEnd(); wxString url = ctrlTexto->GetRange(inicio, fin); wxMessageBox(url, _T("Se ha pulsado una URL")); }
El estilo wxTE_NO_VSCROLL evita que se cree una barra de desplazamiento vertical, limitando la cantidad de texto que se puede introducir.
Los estilos wxHSCROLL y wxTE_DONTWRAP impiden que el texto se divida en líneas diferentes, añadiendo una barra de desplazamiento horizontal.
El estilo wxTE_WORDWRAP divide la líneas de texto demasiado largas para la anchura del control, en los límites entre palabras.
El estilo por defecto, wxTE_BESTWRAP, hace lo mismo, pero en el caso de que no sea posible dividir entre palabras, porque una palabra no quepa en el ancho del control, dividirá el texto en cualquier punto.
El estilo wxTE_CHARWRAP no está disponible en Windows, dividirá el texto siempre por cualquier punto.
Cargar y guardar en ficheros
Es posible cargar el contenido de un control de edición directamente desde un fichero, usando el método LoadFile. También podemos guardar el contenido de un control de edición en un fichero mediante el método SaveFile.
void multilinea::OnClose(wxCloseEvent &event) { datos.nLineas = ctrlTexto->GetNumberOfLines(); ctrlTexto->SaveFile("texto.txt"); Destroy(); } void multilinea::OnCargar(wxCommandEvent &event) { ctrlTexto->LoadFile("texto.txt"); }
Marca de modificación
A veces el usuario cierra el cuadro de diálogo sin modificar alguno de los controles. En ciertos casos nos puede interesar detectar estos casos para evitar realizar ciertas tareas. Para ello disponemos del método IsModified, que nos devuelve true si el valor de control ha sido modificado o asignado mediante SetValue. Si queremos marcar un control como modificado, aunque el usuario no lo haya hecho, podemos usar el método MarkDirty o SetModified.
También existe la posibilidad de detectar si el texto del control ha sido modificado. Para ello bastará con procesar el evento EVT_TEXT.
... EVT_TEXT(idTexto, miClase::OnTextoModificado) ... void miClase::OnTextoModificado(wxCommandEvent& event) { wxMessageBox(_T("El texto ha sido modificado"), _T("Texto")); }Menú contextual
Aunque el sistema operativo crea un menú contextual por defecto para los controles de edición con las opciones de deshacer, cortar, pegar y eliminar, es posible que en nuestra aplicación necesitemos crear uno propio, ya sea para personalizar estas funciones o para añadir otras.
La clase wxTextEntry, dispone de métodos para borrar Clear, copiar Copy, cortar Cut, pegar Paste, deshacer Undo y rehacer Redo.
Podemos crear un menú para usarlo como contextual:
menuContextual = new wxMenu(); menuContextual->Append(idBorrar, _("&Borrar\tSupr")); menuContextual->Append(idCopiar, _("&Copiar\tCtl-C")); menuContextual->Append(idCortar, _("Co&rtar\tCtl-X")); menuContextual->Append(idPegar, _("&Pegar\tCtl-V")); menuContextual->Append(idRedo, _("&Redo\tCtl-Y")); menuContextual->Append(idUndo, _("&Undo\tCtl-Z"));
Para desplegar el menú contextual añadimos el evento a nuestra tabla de eventos:
EVT_CONTEXT_MENU(leerModificar::OnContextMenu)
Y el método para desplegarlo es simple:
void leerModificar::OnContextMenu(wxContextMenuEvent& event) { PopupMenu(menuContextual); }
Si no queremos personalizar estos comandos, tan solo tenemos que invocar el método correspondiente:
void leerModificar::OnBorrar(wxCommandEvent &event) { ctrlTexto->Clear(); }
Además, la clase wxTextEntry dispone de varios métodos para averiguar si las acciones de copiar, cortar, pegar, redo y undo son posibles. Por ejemplo, si no hay texto seleccionado, no se podrá cortar ni copiar, si no hay texto en el portapapeles no se podrá pegar, etc.
Estos métodos son: CanCopy, CanCut, CanPaste, CanRedo, CanUndo
Cuando activemos un menú contextual deberemos desactivar las opciones que no se pueden realizar. Para ello usaremos un puntero auxiliar a un control wxTextCtrl, que asignaremos al recibir una notificación EVT_CONTEXT_MENU.
wxTextCtrl* activo;
Nuestro método para responder a una notificación para desplegar un menú contextual recuperará el identificador del control que tenía el foco en el momento de pulsar el botón derecho del ratón. Si el control no es de tipo wxTextCtrl, retornaremos sin hacer nada, ya que no tiene sentido desplegar un menú de este tipo para controles que no deriven de wxTextCtrl.
En caso de tratarse de un control de edición de texto podremos acceder a sus métodos y activar o desactivar las opciones de menú.
Por otra parte, el método IsEditable devuelve false si el control no puede ser editado por el usuario, es decir, si es de solo lectura. Estos controles pueden ser editados desde el programa, pero en general tendremos que impedir que el usuario lo haga.
void leerModificar::OnContextMenu(wxContextMenuEvent& event) { int id = event.GetId(); activo = (wxTextCtrl*)this->FindWindow(id); if(!activo->IsKindOf(wxCLASSINFO(wxTextCtrl))) return; menuContextual->Enable(idBorrar, activo->IsEditable() ); menuContextual->Enable(idCopiar, activo->CanCopy()); menuContextual->Enable(idCortar, activo->CanCut()); menuContextual->Enable(idPegar, activo->CanPaste()); menuContextual->Enable(idRedo, activo->IsEditable() && activo->CanRedo()); menuContextual->Enable(idUndo, activo->IsEditable() && activo->CanUndo()); PopupMenu(menuContextual); }
Selección de texto
La clase wxTextEntry dispone de varios métodos para manejar selecciones de texto.
El método SelectAll selecciona todo el contenido del control, y el método SelectNone elimina cualquier selección activa.
Para obtener las posiciones inicial y final de la selección actual podemos usar el método GetSelection, pasando como parámetros dos punteros a long que recuperarán esas posiciones.
De forma simétrica, para establecer una selección de texto se usa el método SetSelection, al que pasaremos dos enteros long con las posiciones inicial y final de la selección.
El método GetStringSelection recupera la cadena actualmente seleccionada...
Eliminar texto
Podemos eliminar parte del texto de un control de edición mediante el método Remove, indicando como parámetros la primera y última posición. Hay que tener en cuenta que el carácter en la última posición no se elimina. Por ejemplo, si el texto contiene cien caracteres, con posiciones entre 0 y 99, para eliminar los últimos diez caracteres usaremos los valores 90 y 100.
Reemplazar texto
El método Replace funciona de forma parecida a Remove. Los dos primeros parámetros son iguales, el tercer parámetro es una cadena wxString que sustituirá al texto eliminado.
Punto de inserción
El punto de inserción es el índice en la cadena del control donde se insertará el siguiente carácter introducido por el usuario, y se marca con un cursor. Para obtener el punto de inserción se usa el método GetInsertionPoint y para establecer un nuevo punto de inserción se usa SetInsertionPoint. Para colocar el punto de inserción al final del texto podemos usar SetInsertionPointEnd.
Otro método útil es GetLastPosition, que nos devuelve la última posición en el control, o lo que es lo mismo, el número de caracteres que contiene.
SetInsertionPointEnd() equivale a SetInsertionPointSetInsertionPoint(GetLastPosition()).
Opciones de autocompletado
Siempre es una buena práctica ahorrar trabajo al usuario a la hora de introducir datos. Una buena ayuda consiste en intentar predecir qué quiere escribir el usuario, y ofrecer alternativas para terminar el texto, evitando la necesidad de escribir el resto del texto.
Los editores de código que solemos usar los programadores hacen buen uso de esta técnica, completando el nombre de objetos y clases de forma automática después de haber introducido tres o cuatro caracteres.
wxWidgets nos proporciona algunos métodos para realizar estas tareas, y será nuestro trabajo detectar en qué casos tiene sentido usarlas y cómo implemetarlas.
Para que un control de edición pueda hacer uso del autocompletado deberemos usar el método AutoComplete, al que pasaremos un array de cadenas wxArrayString en su forma más simple, o bien el puntero a un objeto de una clase derivada de wxTextCompleterSimple o wxTextCompleter. Esas dos clases generarán un array de cadenas mediante algún algoritmo suministrado por el usuario.
Las dos clases son clases virtuales puras, de modo que siempre tendremos que derivarlas y crear sus métodos virtuales.
La más sencilla es, como su propio nombre indica, wxTextCompleterSimple, que solo tiene un método virtual GetCompletions.
Este método tiene dos parámetros. El primero es una cadena con el prefijo, que es la cadena que contiene el control y el segundo es una referencia a un array de cadenas, de la clase wxArrayString en la que se devolverán las cadenas que se ajusten al prefijo.
Cada vez que cambie el contenido del control se hará una llamada a este método para actualizar las cadenas con las opciones de autocompletado.
Las cadenas que se añadan al array que no se ajusten al prefijo serán ignoradas.
class colorCompleter : public wxTextCompleterSimple { public: virtual void GetCompletions(const wxString& prefix, wxArrayString& res) { const wxString firstWord = prefix.BeforeFirst(' '); if ( firstWord == "verde" ) { res.push_back("verde claro"); res.push_back("verde oscuro"); } else if ( firstWord == "azul" ) { res.push_back("azul claro"); res.push_back("azul oscuro"); } else { res.push_back("amarillo"); res.push_back("azul"); res.push_back("blanco"); res.push_back("naranja"); res.push_back("rojo"); res.push_back("rosa"); res.push_back("negro"); res.push_back("verde"); res.push_back("violeta"); } } }; ... ctrlTexto->AutoComplete(new colorCompleter); ...
La forma simple es suficiente cuando el número de opciones no es demasiado grande, pero en caso contrario es mejor usar una clase derivada de AutoComplete.
En estos casos se pueden extraer las cadenas de opciones desde una base de datos, o cualquier otra estructura de almacenamiento.
Por ejemplo, usando un diccionario en una base de datos SQLite podemos hacer una clase de autocompletado como esta:
class palabrasCompleter : public wxTextCompleter { public: virtual bool Start(const wxString& prefix) { int rc; if(prefix.size() <= 3) return false; // No completar palabras de tres letras o menos rc = sqlite3_open("palabras.db", &db); consulta = _("SELECT palabra FROM palabras WHERE palabra LIKE '") + prefix + "%';"; rc = sqlite3_prepare_v2(db, static_cast<const char*>(consulta), -1, &ppStmt, NULL); if( rc!=SQLITE_OK ) return false; return true; } virtual wxString GetNext() { if(SQLITE_ROW == sqlite3_step(ppStmt)) { const char *p = reinterpret_cast<const char*>(sqlite3_column_text(ppStmt, 0)); return wxString::FromUTF8(p); } else { sqlite3_finalize(ppStmt); sqlite3_close(db); return wxString(_T("")); } } private: sqlite3 *db; sqlite3_stmt *ppStmt; wxString consulta; };
Otra posibilidad es almacenar nuevas entradas en algún tipo de base de datos, de modo que si el usuario necesita volver a introducirlas, puedan ser sugeridas por el programa automáticamente.
Autocompletar nombres de fichero y directorios
Aunque la documentación menciona que estos métodos solo en están implementados en Windows no he conseguido que funcionen. Sin embargo, los comentaremos aquí de todos modos.
La clase wxTextEntry dispone de dos métodos: AutoCompleteDirectories y AutoCompleteFileNames que deberían autocompletar nombres de directorios y de fichero respectivamente.
Limitar la longitud del texto
Para limitar la longitud del texto que el usuario pueda introducir en un control wxTextCtrl se usa el método SetMaxLength.
Una vez se llega al límite de caracteres se generará un evento EVT_TEXT_MAXLEN.
BEGIN_EVENT_TABLE(textoLimitado, wxDialog) EVT_CLOSE(textoLimitado::OnClose) EVT_TEXT_MAXLEN(idTexto, textoLimitado::OnMaxTexto) END_EVENT_TABLE() ... ctrlTexto->SetMaxLength(10); ... void textoLimitado::OnMaxTexto(wxCommandEvent& event) { wxMessageBox(_T("La longitud máxima del texto es de 10 caracteres"), _T("Texto limitado")); }
Mayúsculas y minúsculas
Podemos forzar que el texto introducido por el usuario se convierta a mayúsculas, independientemente del tipo de caracteres introducidos, usando el método ForceUpper.
Margenes
Aunque creo que tiene una utilidad limitada, es posible establecer un margen a la izquierda y en la parte superior del control mediante el método SetMargins. Para recuperar el valor de los márgenes de un control de edición podemos usar el método GetMargins.
Nota
El método OnDropFiles gestiona eventos wxDropFilesEvent, pero solo está soportado en Windows.
Ejemplo 5
Nombre | Fichero | Fecha | Tamaño | Contador | Descarga |
---|---|---|---|---|---|
Ejemplo 5 | wx005.zip | 2024-12-02 | 995448 bytes | 14 |