Menu

Powrót do spisu treści

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ów
OL039 - algorytm Smitha
OL040 - praca w środowisku sterowanym zdarzeniami
OL041 - czcionka bitmapowa
OL042 - czcionka wektorowa
OL043 - przyciski poleceń

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 GUI001.

 

Artykuł nie jest już rozwijany


obrazekMenu jest jednym z podstawowych elementów sterujących, które są obecne w prawie każdym programie. Niestety, jest ono również najtrudniejszym elementem do zaprogramowania w środowisku sterowanym zdarzeniami - o ile oczywiście ma być uniwersalne i dobrze współpracować z aplikacją.

Podstawową strukturą danych dla menu jest lista (ang. list) i drzewo (ang. tree). Zatem rozpoczniemy od omówienia własności tych elementów i sposobu ich implementacji w języku C++.

Lista

Lista jest sekwencyjną strukturą danych składającą się z powiązanych ze sobą elementów. Ułożenie elementów w obszarze pamięci komputera nie jest określone dla listy. Elementy mogą występować w dowolnej kolejności w pamięci komputera oraz mogą być przedzielone obszarami, które nie należą do listy. Z tego powodu nie można wyliczyć, jak w przypadku tablicy, adresu elementu listy na podstawie jego numeru na liście. Elementy listy są powiązane ze sobą przy pomocy wskaźników. Zwykle element listy posiada dwa takie wskaźniki:

next - wskazuje następny element na liście
prev - wskazuje element poprzedzający

obrazek


obrazek

Lista, której elementy posiadają oba rodzaje wskaźników, nosi nazwę listy dwukierunkowej - ponieważ można poruszać się wzdłuż kolejnych elementów listy w obie strony. Jeśli lista posiada tylko wskaźnik next, to nazwiemy ją jednokierunkową.  Pierwszy element listy będziemy nazywać głową (ang. list head), a ostatni ogonem (ang. list tail) - nazewnictwo glizdowe.... ale oddaje istotę sprawy.

Głowę listy można rozpoznać po tym, iż nie posiada poprzednika - pole prev zawiera wskaźnik NULL. Ogon listy z kolei nie posiada następnika - pole next zawiera wskaźnik NULL. Po liście poruszamy się przechodząc przez kolejne elementy. Wykorzystujemy do tego celu wskaźnik, który zawiera adres elementu listy.

Poniższy przykład tworzy prostą listę dwukierunkową, następnie przechodzi ją w przód i wstecz wyświetlając zawartość kolejnych elementów:

// I Liceum Ogólnokształcące
// w Tarnowie
// Koło informatyczne
//
// P032 - lista dwukierunkowa
//----------------------------

#include <iostream>

using namespace std;

class ListElement
{
  public:
         
    ListElement * next, * prev;
    int data;
    
    ListElement(int d, ListElement * n)
    {
      data = d;
      prev = NULL;
      next = n;
      if(n) n->prev = this;
    };
    void Print()
    {
      cout << data << " ";
    };
};

main()
{
  ListElement * head = new ListElement(10,
                       new ListElement(15,
                       new ListElement(25,
                       new ListElement(45,
                       new ListElement(13,
                       new ListElement(0,NULL))))));
  ListElement * p, * t;
  
// p będzie wskazywał kolejne elementy listy

  p = head; // głowa listy
  while(p)
  {
    p -> Print();  // drukujemy zawartość elementu
    t = p;         // zapamiętujemy adres elementu
    p = p -> next; // przechodzimy do następnego elementu listy
  }
  
// teraz idziemy od ogona do głowy

  cout << endl;
  
  while(t)
  {
    t -> Print();
    t = t -> prev;  // przechodzimy do poprzedniego elementu listy
  }
  cout << endl << endl;
  system("PAUSE");
}
10 15 25 45 13 0
0 13 45 25 15 10

Aby kontynuować, naciśnij dowolny klawisz . . .

Lista jest dynamiczną strukturą danych - w przeciwieństwie do tablicy zawiera tyle elementów ile w danej chwili jest potrzebne. Listę można rozbudowywać zarówno od ogona jak i od głowy. Można również wstawiać nowy element pomiędzy dwa dowolne elementy listy oraz usuwać dowolny element. Więcej informacji na ten temat znajdziesz w artykule OL013.

Drzewo

Podobnie jak lista, drzewo jest również sekwencyjną strukturą danych. Zbudowane jest z węzłów tworzących pewną hierarchię:

obrazek

Jeśli dokładnie przyjrzysz się pokazanej na rysunku strukturze danych, to dojdziesz do następujących wniosków:

Te spostrzeżenia wskazują nam metodę implementacji drzewa - elementy list muszą posiadać dwa pola:

next - wskazuje następny element drzewa na tym samym poziomie hierarchii
sub - wskazuje głowę listy niższego poziomu

Poniżej mamy prosty program tworzący strukturę hierarchiczną drzewa:

// I Liceum Ogólnokształcące
// w Tarnowie
// Koło informatyczne
//
// P033 - drzewo
//--------------

#include <iostream>

using namespace std;

class ListElement
{
  public:
         
    ListElement * next, * sub;
    int data;
    
    ListElement(int d, ListElement * n, ListElement * s)
    {
      data = d;
      next = n;
      sub = s;
    };
    void Print()
    {
      cout << data << " ";
      ListElement * p;
      p = sub;
      if(p)
      {
        cout << "(";
        while(p)
        {
          p -> Print();
          p = p -> next;
        }
        cout << ") ";
      }
    };
};

// Funkcja tworzy strukturę drzewa
//--------------------------------

ListElement * MakeTree()
{
  ListElement * s34  = new ListElement(34, NULL,NULL);
  ListElement * s333 = new ListElement(333,NULL,NULL);
  ListElement * s332 = new ListElement(332,s333,NULL);
  ListElement * s331 = new ListElement(331,s332,NULL);
  ListElement * s33  = new ListElement(33, s34, s331);
  ListElement * s32  = new ListElement(32, s33, NULL);
  ListElement * s31  = new ListElement(31, s32, NULL);
  ListElement * m3   = new ListElement(3,  NULL,s31);
  ListElement * s24  = new ListElement(24, NULL,NULL);
  ListElement * s23  = new ListElement(23, s24, NULL);
  ListElement * s22  = new ListElement(22, s23, NULL);
  ListElement * s21  = new ListElement(21, s22, NULL);
  ListElement * m2   = new ListElement(2,  m3, s21);
  ListElement * s12  = new ListElement(12, NULL,NULL);
  ListElement * s11  = new ListElement(11, s12, NULL);
  return new ListElement(1,m2,s11);
}

main()
{
  
  ListElement * p = MakeTree();
  
// p będzie wskazywał kolejne elementy listy

  while(p)
  {
    p -> Print();  // drukujemy zawartość elementu
    cout << endl;
    p = p -> next; // przechodzimy do następnego elementu listy
  }
  
  cout << endl;
  system("PAUSE");
}
1 (11 12 )
2 (21 22 23 24 )
3 (31 32 33 (331 332 333 ) 34 )

Aby kontynuować, naciśnij dowolny klawisz . . .

Menu

Utwórz projekt SDL. Dodaj do niego pliki biblioteki SDL_gfx, które znajdziesz w podsumowaniu SDL100 (nie zapomnij o ustawieniach linkera). Następnie dołącz pliki interfejsu GUI z podsumowania GUI001. Do katalogu projektowego przekopiuj czcionkę vecprop9x12.fnt. Jesteś gotowy do tworzenia systemu menu dla interfejsu GUI.

W pliku nagłówkowym SDL_gui.h umieścimy deklarację dwóch klas:

gfxMenuItem  - klasa elementu menu
gfxMenu  - klasa struktury drzewa menu

Na końcu pliku SDL_gui.h pod deklaracją klasy gfxButton dopisz poniższy tekst deklaracji obu nowych klas:

class gfxMenu;

class gfxMenuItem : public gfxGUIObject
{
  private:

    Uint32      * buf;

  public:
    
    gfxMenuItem * next, * sub;
    SDL_Rect      subrect;
    gfxMenu     * owner;
    gfxMenuItem(Uint32 tg, bool en, char * t, void (* fn)(gfxGUIObject *), 
                gfxMenuItem * nmi, gfxMenuItem * s);
    ~gfxMenuItem();
    bool DoEvents(SDL_Event * e);   
    void Fix();
    void Refresh();
    void Unsel();
};      

class gfxMenu : public gfxGUIObject
{
  public:
    gfxMenuItem * item;
     
    gfxMenu(SDL_Surface * s, gfxFont * f, gfxMenuItem * mi);
    ~gfxMenu();
    bool DoEvents(SDL_Event * e);    
    void Fix();
    void Refresh();
    void Unsel();
};

Znaczenie pól danych i funkcji powyższych klas jest następujące:

gfxMenuItem

buf  -  wskaźnik obszaru pamięci, który przechowuje fragment powierzchni graficznej przykryty przez podmenu
owner  - zawiera adres klasy gfxMenu, która jest właścicielem tego elementu - umożliwia elementom menu dostęp do powierzchni graficznej oraz zestawu znaków
next  - wskaźnik następnego elementu na tym samych poziomie hierarchii struktury drzewa
sub  - wskaźnik głowy listy podmenu skojarzonego z tym elementem
subrect  - prostokąt podmenu, wykorzystywany do rysowania ramki otaczającej skojarzone elementy podmenu
gfxMenuItem()  - konstruktor klasy
    gfxMenuItem(tg,en,t,fn,nmi,s)
        tg - identyfikator umieszczany w polu tag
        en - określa, czy element będzie wybieralny - true, czy zablokowany - false
        t - wskaźnik tekstu dla elementu menu
        fn - wskaźnik funkcji wywoływanej przy wyborze w menu tego elementu
        nmi - wskaźnik następnego elementu na liście
        s - wskaźnik głowy listy elementów podmenu
~gfxMenuItem()  - destruktor klasy
DoEvents()  - obsługa zdarzeń dla elementów menu.
    DoEvents(e)
        e - wskaźnik struktury SDL_Event
Fix()  - oblicza rozmiar prostokąta subrect dla podmenu. Ustawia wszystkie prostokąty poszczególnych elementów w podmenu i wywołuje dla nich rekurencyjnie funkcję Fix(), co powoduje ustawienie rozmiarów całej gałęzi menu.
Refresh()  - rysuje element na powierzchni graficznej
Unsel()  - zamyka wszystkie podmenu otwarte w bieżącym elemencie. Kasuje wybór elementu.

gfxMenu

item  -  wskaźnik głowy listy elementów menu znajdujących się w pasku menu
gfxMenu()  - konstruktor
    gfxMenu(s,f,mi)
        s - wskaźnik struktury SDL_Surface
        f - wskaźnik struktury gfxFont
        mi - wskaźnik głowy listy elementów menu
~gfxMenu()  - destruktor
DoEvents()  - obsługa zdarzeń dla menu.
    DoEvents(e)
        e - wskaźnik struktury SDL_Event
Fix()  - wylicza prostokąty dla wszystkich elementów menu.
Refresh()  - rysuje pasek menu u góry ekranu
Unsel()  - zamyka całe menu

Teraz przechodzimy do pliku SDL_gui.cpp. Na końcu dopisz do tego pliku poniższy fragment z definicjami funkcji składowych dla klas gfxMenuItem oraz gfxMenu.

// *************************
// *** Obsługa klas Menu ***
// *************************

// Konstruktor elementu menu
//--------------------------

gfxMenuItem::gfxMenuItem(Uint32 tg, bool en, char * t, void (* fn)(gfxGUIObject *),
                         gfxMenuItem * nmi, gfxMenuItem * s)
{
  type    = 0;
  tag     = tg;
  next    = nmi;
  sub     = s;
  enabled = en;
  sel = open = false;
  text    = t;
  call    = fn;
  buf     = NULL;
}

// Destruktor elementu menu
//-------------------------

gfxMenuItem::~gfxMenuItem()
{
  if(next) delete next;
  if(sub)  delete sub;
  if(buf)  delete [] buf;
}

// Zamyka podmenu i usuwa zaznaczenie elementu
//--------------------------------------------

void gfxMenuItem::Unsel()
{
  if(open)                  // jeśli jest otwarte podmenu, zamykamy je
  {
    gfxMenuItem * p = sub;  // zamykamy wszystkie otwarte podmenu w tej gałęzi drzewa
    while(p)
    {
      p -> Unsel();
      p = p -> next;
    }
    Uint32 * p1, * p2;      // odtwarzamy tło podmenu
    p1 = (Uint32 *)(screen->pixels) + subrect.y * screen->w + subrect.x;
    p2 = buf;

    if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
    for(int i = 0; i < subrect.h; i++)
    {
      for(int j = 0; j < subrect.w; j++) * (p1 + j) = * p2++;
      p1 += screen->w;
    }
    if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);

    SDL_UpdateRect(screen, subrect.x, subrect.y, subrect.w, subrect.h);
        
    delete [] buf;         // bufor tła nie jest już potrzebny
    open = false;
    buf = NULL;
  }
  sel = false; Refresh();
}

// Ustawia prostokąty dla podmenu
//-------------------------------

void gfxMenuItem::Fix()
{
  gfxMenuItem * p;
  Sint32        len;
  if(sub)                  // w zależności od rodzaju elementu, podmenu leży albo 
  {                        // poniżej (type = 1), albo obok (type = 0) danego elementu menu
    if(type)
    {
      subrect.x = rect.x;
      subrect.y = rect.y + rect.h;
    }
    else
    {
      subrect.x = rect.x + rect.w;
      subrect.y = rect.y;
    }
    subrect.w = 8;         // obliczamy rozmiar prostokąta podmenu
    subrect.h = 0;
    p = sub;
    while(p)
    {
      p->screen = screen;
      p->font   = font;
      p->owner  = owner;
      p->rect.x = subrect.x;
      p->rect.y = subrect.y + subrect.h;
      if(* (p->text) == '-')
      {
        subrect.h++;
        p->rect.h = 1;
      }
      else
      {
        len = gfxTextLength(font, p->text);
        if(len > subrect.w - 8) subrect.w = len + 8;
        p->rect.h = font->h + 8;
        subrect.h += p->rect.h;
      }
      p = p -> next;
    }
    p = sub;
    while(p)
    {
      p->rect.w = subrect.w;  // ustawiamy szerokość elementów podmenu
      if(p->sub) p->Fix();    // wywołanie rekurencyjne
      p = p->next;
    }
  }
}

// Rysuje element menu
//--------------------

void gfxMenuItem::Refresh()
{
  SDL_Rect r = ShrinkRect();  
  Uint32 fc, bc;
  
  fc = enabled ? C_TEXT : C_DIS;
  bc = sel ? C_UPPER : C_FACE;
  
  if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);  
  if(* text == '-') SDL_FillRect(screen, &rect, C_LOWER);
  else
  {
    SDL_FillRect(screen, &r, bc);
    gfxDrawText(screen, font, text, r.x + 3, r.y + 3, fc, -1);
  }
  if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);  

  Update();
}     

// Obsługa zdarzeń w elemencie menu
//---------------------------------

bool gfxMenuItem::DoEvents(SDL_Event * e)
{
  bool result;
  switch(e -> type)
  {
    case SDL_MOUSEMOTION:
      if(MouseHit(e->motion.x, e->motion.y))
      {
        if(enabled)
        {
          sel = true; Refresh();
        }
        return false;
      }
      if(open)
      {
        gfxMenuItem * p = sub;
        result = true;
        while(p)
        {
          if(result) result = p -> DoEvents(e);
          else p -> Unsel();
          p = p->next;        
        }
        if(!result) return false;
      }
      Unsel();
      return true;
    case SDL_MOUSEBUTTONDOWN: 
      if(e->button.button == SDL_BUTTON_LEFT)
      {
        if(MouseHit(e->button.x, e->button.y))
        {
          if(enabled)
          {
            if(call)  // jeśli element posiada funkcję, wywołujemy ją najpierw zamykając
            {         // całe menu
              owner->Unsel();
              (* call)(this);
              return false;
            }
            if((!open) && sub)  // jeśli istnieje zamknięte podmenu, otwieramy je
            {
              Uint32 * p1 = (Uint32 *)(screen->pixels) + subrect.y * screen->w + subrect.x;
              Uint32 * p2 = buf = new Uint32[subrect.w * subrect.h];
              SDL_Rect r = subrect;

              r.x++; r.y++; r.w -= 2; r.h -= 2;

              if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
 
              for(int i = 0; i < subrect.h; i++) // zapamiętujemy w buforze tło podmenu
              {
                for(int j = 0; j < subrect.w; j++)  * p2++ = * (p1 + j);
                p1 += screen->w;
              }

              SDL_FillRect(screen, &r, C_FACE);
              gfxHLine(screen, subrect.x, subrect.y, C_UPPER, subrect.w);
              gfxVLine(screen, subrect.x, r.y, C_UPPER, r.h + 1);
              gfxHLine(screen, r.x, r.y + r.h, C_LOWER, r.w + 1);
              gfxVLine(screen, r.x + r.w, r.y, C_LOWER, r.h);
                        
              if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);  

              gfxMenuItem * p = sub;

              while(p)   // rysujemy poszczególne elementy podmenu
              {
                p -> Refresh();
                p = p -> next;
              }
           
              SDL_UpdateRect(screen, subrect.x, subrect.y, subrect.w, subrect.h);            

              open = true;
              return false;
            }
          }
        }
        else if(open)
        {  // jeśli podmenu otwarte, to sprawdzamy, czy zdarzenie dotyczy podmenu
          result = true;
          gfxMenuItem * p = sub;
          while(p)
          {
            result = result && (p -> DoEvents(e));
            p = p -> next;
          }
          return result;
        }
      }
  }
  return true;  
}     

// Konstruktor menu
//-----------------

gfxMenu::gfxMenu(SDL_Surface * s, gfxFont * f, gfxMenuItem * mi)
{
  screen = s;
  font   = f;
  item   = mi;
  rect.x = rect.y = 0;
  rect.w = screen->w;
  rect.h = font->h + 8;
  Fix();
  Refresh();
}

// Destruktor menu
//----------------

gfxMenu::~gfxMenu()
{
  if(item) delete item;
}

// Dezaktywuje menu
//-----------------

void gfxMenu::Unsel()
{
  gfxMenuItem * p = item;
  while(p)
  {
    p -> Unsel();
    p = p ->next;
  }
}
    
// Ustawia prostokąty dla menu
//----------------------------

void gfxMenu::Fix()
{
  Sint32 x = 0;
  gfxMenuItem * p = item;
   
  while(p)
  {
    p->type   = 1;     // element paska menu
    p->screen = screen;
    p->font   = font;
    p->owner  = this;
    p->rect.x = x;
    p->rect.y = 0;
    p->rect.w = gfxTextLength(font, p->text) + 8;
    p->rect.h = rect.h;
    x += p->rect.w;
    p->Fix();
    p = p->next;
  }     
}
     
// Odświeża menu
//--------------

void gfxMenu::Refresh()
{
  if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);

  rect.h--;
  SDL_FillRect(screen, &rect, C_FACE);
  gfxHLine(screen, 0, rect.h, C_LOWER, rect.w);
  rect.h++;

  if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
  
  gfxMenuItem * p = item;

  while(p)
  {
    p -> Refresh();
    p = p->next;
  }  
  
  Update();
}

// Obsługa zdarzeń w menu
//-----------------------

bool gfxMenu::DoEvents(SDL_Event * e)
{
  gfxMenuItem * p = item;
  bool result = true;
  if((e -> type == SDL_KEYDOWN) && (e->key.keysym.sym == SDLK_ESCAPE))
  {
    while(p)
    {
      result = result && !(p->sel) && !(p->open);
      p = p -> next;
    }
    Unsel();
    return result;
  }
  
  while(p)
  {
    if(result) result =  p -> DoEvents(e);
    else p -> Unsel();
    p = p -> next;
  }
  return result; 
}

Do testu menu przygotowaliśmy prostą aplikację, która tworzy drzewo menu. Wyjście z programu następuje po wybraniu opcji menu Plik/Zakończ lub po kliknięciu ikony zamykania aplikacji na pasku tytułowym. Program wykorzystuje czcionkę wektorową vecprop9x12.fnt. Nie zapomnij jej umieścić w katalogu projektowym (możesz poeksperymentować również z innymi czcionkami).

// I Liceum Ogólnokształcące
// w Tarnowie
// Koło informatyczne
//
// P034 - Menu
//------------

#include <SDL/SDL_gfx.h>
#include <SDL/SDL_gui.h>
#include <time.h>

const int SCRX = 320;      // stałe określające szerokość i wysokość
const int SCRY = 240;      // ekranu w pikselach

SDL_Surface * screen;
gfxFont * font = gfxOpenFont("vecprop9x12.fnt");

// Funkcje wywoływane z menu
//--------------------------

void fn(gfxGUIObject * sender)
{
  SDL_Rect r;
  
  r.x = 0;
  r.h = font->h + 8;
  r.y = screen->h - r.h;
  r.w = screen->w;
  
  if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);

  SDL_FillRect(screen, &r, 0xff0000);

  Sint32 x = r.x + 4;

  x += gfxDrawText(screen, font, "Wybrana opcja menu : ", x, r.y + 4, 0xffffff, -1);
  gfxDrawText(screen, font, sender->text, x, r.y + 4, 0xffff00, -1);

  if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);

  SDL_UpdateRect(screen, r.x, r.y, r.w, r.h);       
}

void f38(gfxGUIObject * sender)
{
  if(SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);

  gfxLine(screen, rand() % screen->w, 32 + rand() % (screen->h - 32),
                  rand() % screen->w, 32 + rand() % (screen->h - 32),
                  ((rand() % 256) << 16) | ((rand() % 256) << 8) | (rand() % 256));

  if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);

  SDL_UpdateRect(screen, 0, 0, 0, 0);       
}

void fs19(gfxGUIObject * sender)
{
  exit(0);
}

// Tworzy menu
//------------

gfxMenu * Menu()
{
  gfxMenuItem * m5  = new gfxMenuItem(38,true, "Linia",       f38, NULL,NULL);
  gfxMenuItem * m4  = new gfxMenuItem(37,false,"Narzędzia",   NULL,m5,  NULL);
  gfxMenuItem * s34 = new gfxMenuItem(36,true, "Poszerzony",  fn  ,NULL,NULL);
  gfxMenuItem * s33 = new gfxMenuItem(35,true, "Normalny",    fn  ,s34, NULL);
  gfxMenuItem * s32 = new gfxMenuItem(34,true, "Uproszczony", fn  ,s33, NULL);
  gfxMenuItem * s31 = new gfxMenuItem(33,true, "Szkieletowy", fn  ,s32, NULL);
  gfxMenuItem * m3  = new gfxMenuItem(32,true, "Widok",       NULL,m4,  s31);
  gfxMenuItem * s28 = new gfxMenuItem(31,true, "Usuń",        fn  ,NULL,NULL);
  gfxMenuItem * s27 = new gfxMenuItem(30,false,"-",           NULL,s28, NULL);
  gfxMenuItem * s26 = new gfxMenuItem(29,true, "Wstaw",       fn  ,s27, NULL);
  gfxMenuItem * s25 = new gfxMenuItem(28,true, "Wytnij",      fn  ,s26, NULL);
  gfxMenuItem * s24 = new gfxMenuItem(27,true, "Kopiuj",      fn  ,s25, NULL);
  gfxMenuItem * s23 = new gfxMenuItem(26,false,"-",           NULL,s24, NULL);
  gfxMenuItem * s22 = new gfxMenuItem(25,true, "Powtórz",     fn  ,s23, NULL);
  gfxMenuItem * s21 = new gfxMenuItem(24,true, "Cofnij",      fn  ,s22, NULL);
  gfxMenuItem * m2  = new gfxMenuItem(23,true, "Edycja",      NULL,m3,  s21);
  gfxMenuItem * s19 = new gfxMenuItem(22,true, "Zakończ",     fs19,NULL,NULL);
  gfxMenuItem * s18 = new gfxMenuItem(21,false,"-",           NULL,s19, NULL);
  gfxMenuItem * s17 = new gfxMenuItem(20,true, "Drukuj",      fn  ,s18, NULL);
  gfxMenuItem * s16 = new gfxMenuItem(19,false,"-",           NULL,s17, NULL);
  gfxMenuItem * s15 = new gfxMenuItem(18,true, "Zapisz Jako", fn  ,s16, NULL);
  gfxMenuItem * s14 = new gfxMenuItem(17,true, "Zapisz",      fn  ,s15, NULL);
  gfxMenuItem * s13 = new gfxMenuItem(16,true, "Otwórz",      fn  ,s14, NULL);
  gfxMenuItem * s12 = new gfxMenuItem(15,false,"-",           NULL,s13, NULL);
  gfxMenuItem * b13 = new gfxMenuItem(14,true, "Zaawansowany",fn  ,NULL,NULL);
  gfxMenuItem * b12 = new gfxMenuItem(13,true, "Normalny",    fn  ,b13, NULL);
  gfxMenuItem * b11 = new gfxMenuItem(12,true, "Zwykły",      fn  ,b12, NULL);  
  gfxMenuItem * s11 = new gfxMenuItem(11,true, "Nowy",        NULL,s12, b11);
  gfxMenuItem * m1  = new gfxMenuItem(10,true, "Plik",        NULL,m2,  s11);  

  return new gfxMenu(screen, font, m1);     
}

//***********************
// *** 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 systemu Menu dla SDL_gfx",""); 
  
// inicjujemy generator liczb pseudolosowych

  srand((unsigned)time(NULL));
  
  SDL_Event event;
  gfxMenu * m = Menu();
    
  bool running = true;
  
  while(running && SDL_WaitEvent(&event))
  {

// najpierw obsługujemy zdarzenia w menu

    if(m->DoEvents(&event))

// a później reszta zdarzeń

    switch(event.type)
    {
      case SDL_QUIT: running = false;
                     break;
    }
  }
  
// zamykamy czcionkę

  gfxCloseFont(font);

// zamykamy menu

  delete m;
  
  return 0;
}

obrazek


Podsumowanie


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2023 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

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