Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: 'NiceDog'
Biblioteki C++

StatusBar

[lekcja]

Statusbar

Wiele aplikacji posiada na dole taki fajny pasek zwany '''Statusbar'''em albo paskiem statusu. Programy wykorzystują go do wyświetlania różnych, zwykle mało przydatnych informacji. Jeżeli chcesz zobaczyć przykład Statusbara to spójrz na sam dół okna przeglądarki, a zapewne go tam znajdziesz. Jeżeli masz wyjątkowego pecha i go tam nie ma to zawsze możesz spojrzeć tutaj:

To jest właśnie StatusBar ;-) (Windows Vista)
To jest właśnie StatusBar ;-) (Windows Vista)

Tworzenie Statusbar'a

Co może się wydać dziwne początkującym, Statusbar jest kontrolką. I to w dodatku z grupy ''Common Controls'' więc należy pamiętać o dolinkowaniu odpowiedniej biblioteki. Na początku inicjujemy kontrolki funkcją InitCommonControlsEx:

C/C++
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof( INITCOMMONCONTROLSEX );
icc.dwICC = ICC_BAR_CLASSES; // toolbary, statusbary i tooltipy
InitCommonControlsEx( & icc );

Teraz możemy utworzyć Statusbar. Tworzymy go tak samo jak inne kontrolki - funkcją CreateWindowEx. Nazwa klasy to STATUSCLASSNAME. Zauważ, że jest to nazwa stałej reprezentująca nazwę klasy:

C/C++
HWND hStatusBar = CreateWindowEx( 0, STATUSCLASSNAME, NULL, SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE
, 0, 0, 0, 0, hwnd,( HMENU ) 200, hInstance, NULL );

Wymiary oraz położenie okna ustawiliśmy na 0, ponieważ system automatycznie ustawi nasz pasek statusu na dole okna - jest to jedna z niewielu rzeczy, które Windows robi za nas. Użyliśmy też stylu SBARS_SIZEGRIP. Wszystkie style zostały zebrane w poniższej tabelce (jak widać nie ma ich zbyt wiele):

StylZnaczenie
SBARS_SIZEGRIPW prawym rogu paska statusu wyświetli się prostokątny obszar, za pomocą którego można zmieniać rozmiar okna.
SBT_TOOLTIPSStatusbar będzie obsługiwał tooltipy.

Zawartość Statusbar'a

Zanim wpiszemy jakiś tekst do paska statusu, trzeba powiedzieć nieco o jego budowie. Mianowicie składa się on z kilku części (max 256), a każda z nich może wyświetlać różny tekst i ewentualnie także ikonkę. Na początku trzeba ustalić ile części chcemy mieć. Oczywiście będziemy mogli później zmieniać ilość części. A można to zrobić wysyłając komunikat SB_SETPARTS. W parametrze wParam wstawiamy ilość części, a w lParam wskaźnik to tablicy liczb int. Liczby te oznaczają długości kolejnych części statusbar'a. Jeśli wartością jest -1, system sam sobie dobierze szerokość z tego co zostało ;-). Oto przykład:

C/C++
int iStatusBarWidths[] = { 200, 300, - 1 };
SendMessage( hStatusBar, SB_SETPARTS, 3,( LPARAM ) iStatusBarWidths );

Trzeba jeszcze wspomnieć o pułapce, w którą wpadają amatorzy Statusbarów:
Szerokości, których używamy przy SB_SETPARTS nie oznaczają prawdziwej szerokości fragmentu StatusBara ale odległość jego końca od lewej strony.
Jak zwykle programiści Microsoftu znowu dali upust swojemu niezwykłemu talentowi w tworzeniu beznadziejnego API. Wystarczy narzekania - zobaczmy co to wszystko oznacza w praktyce:

  • Każdy kolejny fragment musi poza własną szerokością zawierać sumę wszystkich poprzednich.
  • Druga część StatusBara o szerokości 300 ma w praktyce szerokość 100 bo 300-200=100.
  • Ustawianie wartości -1 w innym miejscu niż na końcu nie ma sensu, gdyż taki element zasłoni wszystkie kolejne.

Skoro już dostatecznie się natrudziliśmy przy dzieleniu StatusBara na części, wypełnijmy go treścią. Możemy to zrobić za pomocą komunikatu SB_SETTEXT. W parametrze wParam podajemy index (numer liczony od 0) części, w której ustawiamy tekst, a w lParam sam tekst:

C/C++
SendMessage( hStatusBar, SB_SETTEXT, 2,( LPARAM ) "To jest mój własny StatusBar !!!" );

A oto efekt naszych działań:

Prosty przykład StatusBara (Windows Vista)
Prosty przykład StatusBara (Windows Vista)

Czasami zachodzi potrzeba pobrania tekstu ze StatusBara. Standardowo służy do tego odpowiedni komunikat czyli SB_GETTEXT. Wcześniej jednak musimy pobrać rozmiar bufora (komuniakt SB_GETTEXTLENGTH). Oto przykład:

C/C++
DWORD dlugosc = SendMessage( hStatusBar, SB_GETTEXTLENGTH, 2, 0 );
LPSTR Bufor =( LPSTR ) GlobalAlloc( GPTR, dlugosc + 1 );
SendMessage( hStatusBar, SB_GETTEXT, 2,( LPARAM ) Bufor );
// operacje na tekscie ...
GlobalFree( Bufor );

Komunikat SB_GETTEXTLENGTH w parametrze wParam przyjmuje index części StatusBara, której długość tekstu chcemy poznać. Tak samo jest w przypadku SB_GETTEXT, tylko ten dodatkowo w parametrze lParam przyjmuje adres bufora, do którego ma zapisać tekst.

Ikonki

Wiele "profesjonalnych" aplikacji ma w swoich StatusBarach ikonki. Jeżeli chcemy by nasze programy także posiadały zaszczytny tytuł "profesjonalnych" powinniśmy je w takie ikonki wyposażyć. Na nasze szczęście nie wymaga to żadnych dodatkowych zabiegów i sprowadza się do odpowiednich komunikatów. Tak więc do dzieła!

Ikonkę można ustawić za pomocą komunikatu SB_SETICON. Parametr wParam to tradycyjnie index części, natomiast lParam to uchwyt do ikony. Najpierw trzeba jednak załadować ikonę:

C/C++
HICON hIcon =( HICON ) LoadImage( hInstance, MAKEINTRESOURCE( 100 )
, IMAGE_ICON, 16, 16, LR_SHARED | LR_LOADTRANSPARENT );

Zauważ, że użyliśmy funkcji LoadImage zamiast LoadIcon. A to dlatego, że funkcja LoadIcon ładuje ikonę o wymiarach 32x32 a nie pasującym do StatusBara 16x16. Po prostu StatusBar nie skaluje ikon, więc gdybyśmy użyli funkcji LoadIcon to w StatusBarze pojawił by się jedynie wycinek ikony, co jest efektem raczej niepożądanym ;-)

Skoro mamy już ikonę o odpowiednich rozmiarach, możemy już wysłać omówiony wcześniej komunikat:

C/C++
SendMessage( hStatusBar, SB_SETICON, 1,( LPARAM ) hIcon );

A oto nasz StatusBar z ikonką:

StatusBar z ikonką (Windows Vista)
StatusBar z ikonką (Windows Vista)

Tooltipy

StatusBar możemy łatwo wyposażyć w tooltipy. Podobnie jak z większością rzeczy w WinAPI służą do tego odpowiednie komunikaty. W tym przypadku jest to SB_SETTIPTEXT. W parametrze wParam wstawiamy index części a w lParam tekst:

C/C++
SendMessage( hStatusBar, SB_SETTIPTEXT, 1,( LPARAM ) "Odśwież" );

Żeby nasz tooltip się pojawił, musimy użyć stylu SBT_TOOLTIPS przy tworzeniu kontrolki. I to tyle. Nasz tooltip działa:

StatusBar z ikonką i tooltipem (Windows Vista)
StatusBar z ikonką i tooltipem (Windows Vista)

Komunikaty

Choć zazwyczaj gdy klikamy na StatusBar nic się nie dzieje, to wcale nie znaczy, że tak musi być. Gdy użytkownik kliknie na StatusBarze do okna-rodzica wysyłane są odpowiednie powiadomienia. Oto kilka z nich:

PowiadomienieZnaczenie
NM_CLICKKliknięcie lewym przyciskiem myszy.
NM_DBLCLKPodwójne kliknięcie lewym przyciskiem myszy.
NM_RCLICKKliknięcie prawym przyciskiem myszy.
NM_RDBLCLKPodwójne kliknięcie prawym przyciskiem myszy.

Od każdego z powyższych powiadomień otrzymujemy strukturę NMMOUSE. Oto niektóre parametry:

PoleZnaczenie
hdrNagłówek struktury powiadomienia.
ptStruktura POINT zawierająca współrzędne kursora myszy na ekranie.
dwItemSpecIndex części StatusBar'a, w którym nastąpiło kliknięcie
dwItemDataW StatusBarze nie oznacza niczego.

Warto zwrócić uwagę na to, że NMMOUSE może pochodzić od różnych kontrolek, nie tylko StatusBar'a, dlatego znaczenie pól dwItemSpec i dwItemData może być inne niż w tabelce powyżej. Oto przykład obsługi takiego powiadomienia:

C/C++
case WM_NOTIFY:
switch((( LPNMHDR ) lParam )->code ) {
case NM_CLICK:
    if((( LPNMHDR ) lParam )->hwndFrom == hStatusBar ) {
        char buf[ 20 ];
        itoa(((( LPNMMOUSE ) lParam )->dwItemSpec ), buf, 10 );
        MessageBox( hwnd, buf, "Index:", MB_ICONINFORMATION );
    }
    break;
}
break;

Zmiana rozmiaru okna

Potrafimy już stworzyć StatusBar z (prawie) wszystkimi bajerami i w sumie można by na tym zakończyć ten artykuł, gdyby nie jeden bardzo poważny problem. Mianowicie, gdy zmieniamy rozmiar okna programu to StatusBar zostaje na swoim starym miejscu zamiast się ładnie dopasować do okna! Niestety o to dopasowanie musimy zadbać my sami.

A oto i proste rozwiązanie tego skomplikowanego problemu: wystarczy, że obsłużymy komunikat WM_SIZE w ten sposób:

C/C++
SendMessage( hStatusBar, WM_SIZE, 0, 0 );

Po prostu wysyłamy komunikat WM_SIZE do StatusBara. Nie są potrzebne żadne parametry. Trzeba mu "przypomnieć", że rozmiar okna został zmieniony i musi się on dopasować do niego na nowo.
Poprzedni dokument Następny dokument
ScrollBar Drzewo (TreeView)