15 Barra de estado

Ejemplo de barra de estado

Ya hemos usado las barras de estado en los ejemplos anteriores, pero hablaremos con un poco más de detalle en éste capítulo.

Podemos considerar estos controles como controles estáticos, desde el punto de vista de que no permiten al usuario introducir datos, y se usan exclusivamente para dar información al usuario.

Se trata de una barra horizontal que se muestra en la parte inferior de la ventana de la aplicación y que puede y suele estar dividida en varias partes. En los ejemplos que hemos visto hasta ahora se usan para mostrar una pequeña ayuda sobre las opciones de menú y la versión de las librerías de wxWidgets que se está usando, pero puede servir para mostrar mucha más información.

Las barras de estado se encapsulan en objetos de la clase wxStatusBar, aunque generalmente accederemos a ellas a través de los métodos disponibles en la clase wxFrame.

Así, para crear una barra de estado asociada a un Frame (o marco), usaremos el método CreateStatusBar, indicando el número de campos, el estilo, un identificador y un nombre para el control. Todos los parámetros son opcionales. Para asignar un texto a cualquiera de sus campos usaremos el método SetStatusText, indicando el texto y el número del campo que queramos asignar.

Por ejemplo, hemos usado este código para crear una barra de estado con dos campos y los estilos por defecto, y asignado una cadena a cada campo:

    CreateStatusBar(2);
    SetStatusText(_("Hola"),0);
    SetStatusText(wxbuildinfo(short_f), 1);

Siempre podemos obtener un puntero a esta barra de estado mediante el método GetStatusBar, lo que nos permite usar los métodos propios de esa clase, y también podemos asignar otra barra de estado mediante el método SetStatusBar.

Estilos

Además de los estilos heredados de la clase base wxWindow, estos controles admiten algunos estilos propios:

wxSTB_SIZEGRIP muestra una "pinza" en la parte derecha que permite modificar el tamaño de la ventana.

Los estilos wxSTB_ELLIPSIZE_START, wxSTB_ELLIPSIZE_MIDDLE y wxSTB_ELLIPSIZE_END establecen el lugar en el que se insertarán los puntos suspensivos si una cadena no cabe en el campo que tiene asignado.

El estilo wxSTB_DEFAULT_STYLE, que es el valor por defecto, equivale a wxSTB_SIZEGRIP|wxSTB_SHOW_TIPS|wxSTB_ELLIPSIZE_END|wxFULL_REPAINT_ON_RESIZE.

Número de campos

El constructor de la clase wxStatusBar no dispone de ningún parámetro para indicar el número de campos. Ese valor se establece posteriormente mediante el método SetFieldsCount:

    sb = new wxStatusBar(this);
    sb->SetFieldsCount(4);

Estilos de los campos

Es posible establecer algunos estilos diferentes a cada campo de la barra de estado, aunque esto no está disponible en todas las plataformas. Por ejemplo, en Windows parece que no funciona.

Estos estilos afectan al modo en que se visualiza cada campo, concretamente al borde. Esto permite dar una sensación de volumen, o aspecto 3D, de modo que parezca que ciertos campos están levantados o hundidos.

Los valores posibles son:

  • wxSB_NORMAL (por defecto): El campo aparece con el borde nativo por defecto.
  • wxSB_FLAT: No se pinta ningún borde alrededor del campo para que aparezca plano.
  • wxSB_RAISED: Se pinta un borde 3D en relieve alrededor del campo.
  • wxSB_SUNKEN: Se pinta un borde 3D hundido alrededor del campo (este estilo es nuevo desde wxWidgets 2.9.5).

Para establecer los estilos da cada campo se usa el método SetStatusStyles, indicando el número de campos y un array con los valores de los estilos para cada uno de ellos.

    sb = new wxStatusBar(this);
    sb->SetFieldsCount(2);
    int style[] = {wxSB_RAISED, wxSB_SUNKEN};
    sb->SetStatusStyles(2, style);

Tamaño de los campos

Si no se indica nada al respecto, todos los campos de la barra de estado tendrán la misma anchura. Sin embargo esto no siempre será deseable. Es probable que queramos que ciertos campos tengan un tamaño fijo, o que el espacio se reparta en ciertas proporciones.

La altura depende exclusivamente del tamaño de la fuente, pero para las anchuras tenemos varias opciones de personalización.

Las anchuras se establecen mediante el método SetStatusWidths, indicando el número de campos y un array con la anchura de cada uno.

También se puede usar el segundo parámetro del método SetFieldsCount, pasando el mismo array:

    sb = new wxStatusBar(this);
    int width[] = {-1, -2, -1, -3, -2, 100};
    sb->SetFieldsCount(6);
    sb->SetStatusWidths(6, width);
    // Las dos líneas anteriores equivalen a :
    // sb->SetFieldsCount(6, width);

Los valores positivos indican una anchura fija en pixels. Los valores negativos se usan para indicar una proporción. En este ejemplo el último campo tiene una anchura de 100 pixel, y los cinco restantes se reparten el resto del siguiente modo. Se divide el espacio en nueve partes iguales: (1+2+1+3+2), y se asigna a cada campo el número de partes de esas nueve correspondiente, una para el primero, dos para el segundo, una para el tercero, tres para el cuarto y 2 para el quinto.

Los tamaños que dependen de las proporciones se calculan cada vez que el tamaño de la barra de estado cambia.

Si no se especifica, la altura del control se calcula automáticamente a partir del tamaño del texto, pero podemos establecer la altura mínima mediante el método SetMinHeight:

    sb->SetMinHeight(30);

Push y Pop

Para cada campo de la barra de estado se mantiene una pila de textos, podemos usar el método PushStatusText, indicando como parámetros el nuevo texto y el índice del campo. Esto almacenará en la pila de ese campo el valor actual del texto y lo sustituirá por el nuevo. Posteriormente podemos usar el método PopStatusText, indicando el índice del campo para recuperar el último valor almacenado en la pila para ese campo.

Insertar controles en barra de estado

No tenemos por qué limitarnos a mostrar texto en la barra de estado, podemos añadir controles estáticos con mapas de bits o de texto, botones, etc.

Para insertar cualquier control dentro de la barra de estado primero deberemos asegurarnos de que la barra de estado ya ha sido asignada a la ventana, ya que de otro modo sus valores de posición y tamaño no serán válidos.

Después necesitamos recuperar el rectángulo de la zona donde queramos insertar el control. Esto se hace mediante el método GetFieldRect, indicando el índice de la zona y una referencia a una estructura wxRect que recibirá la información.

Finalmente podemos insertar el control, utilizando el puntero a la barra de estado como ventana padre.

Este ejemplo inserta un control estático de mapa de bits:

    sb = new wxStatusBar(this);
...
    wxRect rect;
    SetStatusBar(sb);
    sb->GetFieldRect(zonaColor, rect);
    bm = new wxStaticBitmap(sb, wxID_ANY, wxBITMAP_PNG(verde), wxPoint(rect.x+3, rect.y+3));
...

De forma similar podemos insertar botones o controles de texto estáticos. Además, de este modo podemos definir estilos para esos controles, como wxBORDER_SUNKEN, en lugar de usar los estilos de las zonas que aparentemente no funcionan en todas las plataformas.

Para añadir un botón:

    sb->GetFieldRect(zonaBoton, rect);
    bt = new wxButton(sb, idBoton, _T("Cambio"), wxPoint(rect.x, rect.y), wxSize(rect.GetWidth(), rect.GetHeight()));

O un control de texto estático:

    sb->GetFieldRect(zonaHora, rect);
    st = new wxStaticText(sb, idHora, _T("00:00:00"), wxPoint(rect.x+4, rect.y), wxSize(rect.GetWidth(), rect.GetHeight()), wxBORDER_SUNKEN);

Debemos ser cuidadosos y liberar recursos al cerrar la ventana. En este caso deberemos destruir los objetos correspondientes a la barra de estado y los controles que hayamos insertado, (aunque al ser hijos de la barra de estado, probablemente se destruyan automáticamente):

wx015Frame::~wx015Frame()
{
    delete st;
    delete bt;
    delete bm;
    delete sb;
}

Como los controles se insertan dentro de la barra de estado, y las coordenadas de cada zona dependen del tamaño de la ventana, deberemos procesar el evento EVT_SIZE, que se envía a la ventana cada vez que ésta cambie de tamaño.

BEGIN_EVENT_TABLE(wx015Frame, wxFrame)
...
EVT_SIZE(wx015Frame::OnSize)
...

El método OnSize se encargará de mover los controles a sus nuevas posiciones cada vez que sea necesario:

void wx015Frame::OnSize(wxSizeEvent& event) {
    if(!sb) return;
    wxRect rect;
    sb->GetFieldRect(zonaColor, rect);
    bm->Move(wxPoint(rect.x+3, rect.y+3));
    sb->GetFieldRect(zonaBoton, rect);
    bt->Move(wxPoint(rect.x, rect.y));
    sb->GetFieldRect(zonaHora, rect);
    st->Move(wxPoint(rect.x+4, rect.y));
}

Ejemplo 15

Para este ejemplo hemos utilizado un hilo que actualiza la zona que muestra la hora dentro de la barra de estado.

En lugar de utilizar la clase wxThread, hemos usado la clase estándar std::thread, como la propia documentación de wxWidgets recomienda. Para ello es necesario activar la bandera de compilación correspondiente para que se siga el estándar de C++ 11.

Puedes consultar la documentación de esta clase en cppreference thread.

Nombre Fichero Fecha Tamaño Contador Descarga
Ejemplo 15 wx015.zip 2025-01-02 5890 bytes 6