Wymagane jest zapoznanie się z następującymi podrozdziałami:
P019 - Pierwszy program dla Windows
OL031 - instalacja biblioteki SDL w środowisku Dev-C++
OL032 - inicjalizacja biblioteki SDL
OL033 - powierzchnie graficzne w SDL
OL034 - przygotowanie plików własnej biblioteki graficznej
OL035 - rysowanie po powierzchni graficznej
OL036 - algorytm Bresenhama rysowania odcinka
OL037 - obcinanie grafiki do prostokąta
OL038 - podstawowe algorytmy wypełniania obszarówOL039 - algorytm Smitha
OL040 - praca w środowisku sterowanym zdarzeniami
OL041 - czcionka bitmapowa
OL042 - czcionka wektorowa
OL043 - przyciski poleceń
OL044 - menu
OL045 - edytor jednowierszowy
OL046 - kontrolki opcji
UWAGA!!!
Bieżące opracowanie NIE JEST KURSEM programowania biblioteki SDL. Są to materiały przeznaczone do zajęć na kole informatycznym w I LO w Tarnowie.
Przed pracą z tym rozdziałem utwórz w środowisku Dev-C++ nowy projekt SDL i dołącz do niego pliki SDL_gfx.cpp oraz SDL_gfx.h. Jeśli nie przeczytałeś zalecanych rozdziałów, koniecznie zrób to, a wszystko stanie się jasne. W przeciwnym razie odpuść sobie również ten rozdział. Opis funkcji bibliotecznych znajdziesz w podsumowaniu SDL100 i GUI004.
Artykuł nie jest już rozwijany
Pasek przewijania (ang. scroll bar) jest standardową kontrolką, stosowaną do sterowania przewijaniem zawartości innych kontrolek. W naszym wykonaniu będzie to bardzo prosty element, reagujący jedynie na zdarzenia myszki - w przypadku klawiatury musielibyśmy bardzo rozbudować system obsługi zdarzeń, jeśli program korzystałby z kilku takich kontrolek.
Pasek przewijania będzie występował w dwóch odmianach - poziomej i pionowej. Typ paska rozpoznaje automatycznie jego konstruktor na podstawie wymiarów ograniczającego prostokąta. Jeśli pasek jest dłuższy w poziomie, to jest traktowany jako poziomy, a jeśli jest dłuższy w pionie, to będzie paskiem pionowym.
Pasek przewijania będzie zawierał następujące pola graficzne sterujące jego wartością:
- Kliknięcie myszką zmniejsza wartość paska o 1.
- Kliknięcie myszką przed suwakiem zmniejsza wartość paska o zadany krok. Kliknięcie za suwakiem zwiększa wartość paska o zadany krok.
- Przeciąganie myszką powoduje odpowiednie zmiany wartości paska.
- Kliknięcie myszką zwiększa wartość paska o 1.
Przy każdej zmianie wartości paska będzie wywoływana odpowiednia funkcja zewnętrzna, która może dokonywać zmian w innym obiekcie na podstawie tej wartości.
Utwórz projekt SDL. Dodaj do niego pliki biblioteki SDL_gfx,(nie zapomnij o ustawieniach linkera). Następnie dołącz pliki interfejsu GUI z podsumowania GUI004.
Na koniec pliku nagłówkowego SDL_gui.h dopisz poniższy fragment tekstu:
class gfxScrollBar : public gfxGUIObject { private: Sint32 sblen, klen, kpos, mpos; void DrawBoxFace(SDL_Rect * r); void DrawButton(Uint32 t); void Calc(); void Modify(bool mode, Sint32 x); public: Uint32 value, vmax, vprop, vstep; gfxScrollBar(Uint32 tg, bool en, SDL_Surface * s, SDL_Rect * r, Uint32 v, Uint32 m, Uint32 p, Uint32 st, void (* fn)(gfxGUIObject *)); bool DoEvents(SDL_Event * e); void Refresh(); };gfxScrollBar
Klasa obsługuje element paska przewijania. Dziedziczy wszystkie pola i metody z gfxGUIObject. Pola i funkcje składowe klasy posiadają następujące znaczenie:
value - aktualna wartość paska przewijania. Wartość ta jest zawsze w przedziale od 0 do vmax. vmax - maksymalna wartość paska przewijania. vprop - jest to wartość określająca względną szerokość suwaka. Jeśli wynosi 0, to suwak posiada kształt kwadratu. Każda inna wartość powoduje, iż suwak przyjmuje względną długość równą szerokość suwni x vprop / vmax. Pozwala to dostosowywać szerokość suwaka do wielkości przesuwanego obszaru. vstep - określa krok o ile zostaje zwiększona lub zmniejszona wartość paska przewijania przy kliknięciu myszką na suwni. gfxScrollBart() - konstruktor
gfxScrollBar(tg,en,s,r,v,m,p,st,fn)
tg - numer paska przewijania
en - określa, czy pasek jest aktywny - true, czy zablokowany - false
s - wskaźnik struktury SDL_Surface
r - prostokąt definiujący położenie położenie paska przewijania oraz jego wymiary.
v - aktualna wartość paska
m - maksymalna wartość paska
p - wartość względnej szerokości suwaka
st - krok suwaka
fn - wskaźnik funkcji wywoływanej przy każdej zmianie wartości paskaDoEvents() - obsługuje zdarzenia dla paska przewijania. Jeśli zdarzenie zostanie obsłużone, zwraca false.
DoEvents(e)
e - wskaźnik struktury SDL_Event.Refresh() - wyświetla pasek przewijania Na końcu pliku SDL_gui.cpp dopisz poniższy fragment programu:
// ******************************* // *** Obsługa klasy ScrollBar *** // ******************************* // Funkcja rysuje powierzchnię obramowaną cieniem // r - prostokąt obejmujący powierzchnię //----------------------------------------------- void gfxScrollBar::DrawBoxFace(SDL_Rect * r) { SDL_FillRect(screen, r, C_FACE); gfxHLine(screen, r->x, r->y, C_UPPER, r->w); gfxVLine(screen, r->x, r->y, C_UPPER, r->h); gfxHLine(screen, r->x + 1, r->y + r->h - 1, C_LOWER, r->w - 1); gfxVLine(screen, r->x + r->w - 1, r->y + 1, C_LOWER, r->h - 1); } // Funkcja rysuje przycisk znajdujący się na końcach paska // t - rodzaj przycisku: // 0 - góra // 1 - dół // 2 - lewo // 3 - prawo //-------------------------------------------------------- void gfxScrollBar::DrawButton(Uint32 t) { SDL_Rect r; switch(t) { case 0 : r.x = rect.x; r.y = rect.y; r.w = r.h = rect.w; break; case 1 : r.x = rect.x; r.y = rect.y + rect.h - rect.w; r.w = r.h = rect.w; break; case 2 : r.x = rect.x; r.y = rect.y; r.w = r.h = rect.h; break; case 3 : r.x = rect.x + rect.w - rect.h; r.y = rect.y; r.w = r.h = rect.h; break; }; DrawBoxFace(&r); Uint32 x = r.x + (r.w >> 1); Uint32 y = r.y + (r.h >> 1); Uint32 c = enabled ? C_TEXT : C_DIS; switch(t) { case 0 : gfxMoveTo(r.x + 3, r.y + r.h - 4); gfxLineTo(screen, x, r.y + 3, c); gfxLineTo(screen, r.x + r.w - 4, r.y + r.h - 4, c); break; case 1 : gfxMoveTo(r.x + 3, r.y + 3); gfxLineTo(screen, x, r.y + r.h - 4, c); gfxLineTo(screen, r.x + r.w - 4, r.y + 3, c); break; case 2 : gfxMoveTo(r.x + r.w - 4, r.y + 3); gfxLineTo(screen, r.x + 3, y, c); gfxLineTo(screen, r.x + r.w - 4, r.y + r.h - 4, c); break; case 3 : gfxMoveTo(r.x + 3, r.y + 3); gfxLineTo(screen, r.x + r.w - 4, y, c); gfxLineTo(screen, r.x + 3, r.y + r.h - 4, c); break; }; } // Wylicza wielkości obszarów paska przewijania //--------------------------------------------- void gfxScrollBar::Calc() { if(type) { sblen = rect.w - (rect.h << 1); klen = rect.h; } else { klen = rect.w; sblen = rect.h - (rect.w << 1); } if(vprop) klen = (sblen * vprop) / (vmax + 1); kpos = ((sblen - klen) * value) / vmax; } // Modyfikuje wartość paska // mode : true - wartość dv jest dodawana do value // false - wartość określa współrzędną myszki //--------------------------------------------------- void gfxScrollBar::Modify(bool mode, Sint32 dv) { if(mode) { value += dv; if(value < 0) value = 0; if(value > vmax) value = vmax; } else { Sint32 d; if(type) d = rect.x + rect.h; else d = rect.y + rect.w; kpos += dv - d - kpos - mpos; if(kpos < 0) kpos = 0; if(kpos > sblen - klen) kpos = sblen - klen; value = (kpos * vmax) / (sblen - klen); Calc(); // Korygujemy położenie suwaka!!! } Refresh(); if(call)(* call)(this); } // Konstruktor paska przewijania //------------------------------ gfxScrollBar::gfxScrollBar(Uint32 tg, bool en, SDL_Surface * s, SDL_Rect * r, Uint32 v, Uint32 m, Uint32 p, Uint32 st, void (* fn)(gfxGUIObject *)) { tag = tg; enabled = en; screen = s; rect = * r; value = v; vmax = m; vprop = p; vstep = st; call = fn; type = (rect.w > rect.h) ? 1 : 0; sel = false; Refresh(); } // Obsługuje zdarzenia w pasku //---------------------------- bool gfxScrollBar::DoEvents(SDL_Event * e) { if(enabled) { switch(e->type) { case SDL_MOUSEMOTION: if(sel) { if(type) Modify(false, e->motion.x); else Modify(false, e->motion.y); return false; } else break; case SDL_MOUSEBUTTONDOWN: if((e->button.button == SDL_BUTTON_LEFT) && MouseHit(e->button.x, e->button.y)) { if(type) { if(e->button.x < rect.x + rect.h) { Modify(true, -1); return false; } if(e->button.x > rect.x + rect.w - rect.h) { Modify(true, 1); return false; } if(e->button.x < rect.x + rect.h + kpos) { Modify(true, -vstep); return false; } if(e->button.x > rect.x + rect.h + kpos + klen) { Modify(true, vstep); return false; } sel = true; mpos = e->button.x - rect.x - rect.h - kpos; return false; } else { if(e->button.y < rect.y + rect.w) { Modify(true, -1); return false; } if(e->button.y > rect.y + rect.h - rect.w) { Modify(true, 1); return false; } if(e->button.y < rect.y + rect.w + kpos) { Modify(true, -vstep); return false; } if(e->button.y > rect.y + rect.w + kpos + klen) { Modify(true, vstep); return false; } sel = true; mpos = e->button.y - rect.y - rect.w - kpos; return false; } } else break; case SDL_MOUSEBUTTONUP: if(sel && (e->button.button == SDL_BUTTON_LEFT)) { sel = false; return false; } else break; } } return true; } // Rysuje pasek przewijania //------------------------- void gfxScrollBar::Refresh() { SDL_Rect r; if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); Calc(); if(type) { DrawButton(2); DrawButton(3); r.x = rect.x + rect.h; r.y = rect.y; r.w = sblen; r.h = rect.h; } else { DrawButton(0); DrawButton(1); r.x = rect.x; r.y = rect.y + rect.w; r.w = rect.w; r.h = sblen; } SDL_FillRect(screen, &r, enabled ? C_TEXTBG : C_DIS); if(type) { r.x += kpos; r.w = klen; } else { r.y += kpos; r.h = klen; } DrawBoxFace(&r); if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); Update(); }Poniższy program testuje kontrolki paków przewijania. Program kończymy klikając na przycisk zamknięcia aplikacji.
// I Liceum Ogólnokształcące // w Tarnowie // Koło informatyczne // // P040 - Pasek przewijania //------------------------- #include <SDL/SDL_gfx.h> #include <SDL/SDL_gui.h> const int SCRX = 320; // stałe określające szerokość i wysokość const int SCRY = 240; // ekranu w pikselach const int SBSIZE = 15; // grubość paska przewijania // ************************ // *** Zmienne globalne *** // ************************ SDL_Surface * screen; gfxFont * font = gfxOpenFont("vecprop9x12.fnt"); gfxScrollBar * sb1, * sb2; // **************** // *** Funkcje **** // **************** // Funkcja zamienia liczbę na 3 cyfrowy tekst //------------------------------------------- void NumberToASCII(Sint32 n, char * t) { Sint32 x = 100, i; for(i = 0; i < 3; i++) { t[i] = 48 + (n / x); n %= x; x /= 10; } t[i] = 0; } // Funkcja suwaka poziomego //------------------------- void sb1f(gfxGUIObject * sender) { char t[4]; NumberToASCII(((gfxScrollBar *)sender)->value, t); Uint32 l = gfxTextLength(font,t); Uint32 x = sender->rect.x + (sender->rect.w >> 1) - (l >> 1); Uint32 y = sender->rect.y - font->h - 10; if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); gfxDrawText(screen, font, t, x , y, 0xff0000, 0); if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); SDL_UpdateRect(screen, x, y, l, font->h); } // Funkcja suwaka pionowego //------------------------- void sb2f(gfxGUIObject * sender) { char t[4]; NumberToASCII(((gfxScrollBar *)sender)->value, t); Uint32 l = gfxTextLength(font,t); Uint32 x = sender->rect.x - l - 10; Uint32 y = sender->rect.y + (sender->rect.h >> 1) - (font->h >> 1) ; if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); gfxDrawText(screen, font, t, x , y, 0xff0000, 0); if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); SDL_UpdateRect(screen, x, y, l, font->h); } //*********************** // *** Program główny *** //*********************** int main(int argc, char * argv[]) { if(SDL_Init(SDL_INIT_VIDEO)) exit(-1); atexit(SDL_Quit); if(!(screen = SDL_SetVideoMode(SCRX, SCRY, 32, SDL_HWSURFACE))) exit(-1); SDL_WM_SetCaption("Test paska przewijania", ""); // Tworzymy dwa paski przwijania, jeden po prawej stronie okna, a drugi na dole SDL_Rect r; r.x = 0; r.y = screen->h - SBSIZE; r.w = screen->w - SBSIZE; r.h = SBSIZE; sb1 = new gfxScrollBar(0, true, screen, &r, 200, 200, 25, 10, sb1f); r.x = screen->w - SBSIZE; r.y = 0; r.w = SBSIZE; r.h = screen->h - SBSIZE; sb2 = new gfxScrollBar(0, true, screen, &r, 0, 100, 25, 10, sb2f); sb1f(sb1); sb2f(sb2); // Obsługujemy zdarzenia SDL_Event event; bool running = true; while(running && SDL_WaitEvent(&event)) { if(sb1->DoEvents(&event) && sb2->DoEvents(&event)) switch(event.type) { case SDL_QUIT: running = false; break; } } // zamykamy czcionkę gfxCloseFont(font); return 0; }
![]() | I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe