Örnek Yazılım
Önceki Ncurses'a Giriş Sonraki
Örnek Yazılım
Burada inceleyeceğimiz örnek yazılım basit ama öğretici bir yazılımdır. Bu yazılımda ncurses kullanılarak menüler oluşturulmuş ve menüdeki seçeneklerden bir tanesinin seçilmesi basit bir biçimde uygulanmıştır. Bu yazılımda önemli olan ncurses'in pencere bileşenlerini menü etkisi yaratabilecek şekilde kullanmaktır. Yazılımın ekran görüntüsünü aşağıda görüyorsunuz:
Yazılımda her zaman olduğu gibi önce kullanılan kütüphanelerin başlık dosyaları yazılır. Bir de yazılım içerisinde kullanacağımız <enter> ve <escape> tuşlarının ASCII karşılıkları yerine kullanılacak sabitler tanımlanır.
#include <curses.h>
#include <stdlib.h>

#define ENTER 10
#define ESCAPE 27
Aşağıdaki init_curses işlevi yazılımın ilk çalıştığı zaman çağırdığı işlevdir. Önce initscr çağrısı yaparak ncurses çalıştırılır, daha sonra start_color ile renkler kullanılır hale getirilir ve ardından da yazılım boyunca kullanılacak renk çiftleri tanımlanır. curs_set(0) çağrısı fiziksel imlecin ekran üzerinde görünmemesini sağlarken, noecho çağrısı da kullanıcının klavyeden girdiği karakterlerin ekrana yazılmasını engeller. noecho işlevini girdileri kontrol ederek almak ve sadece kabul edilen karakterleri ekrana aktarmak gibi bir amaç için de kullanabilirsiniz. noecho işlevinin etkisini kaldırmak için gerektiği zaman echo çağrısı yapılır. Aşağıdaki işlev son olarak keypad çağrısı yaparak stdscr'den alınacak girdilerde işlev tuşlarının da kullanılabilmesini sağlar. F1 ve F2 ile ok tuşlarını kullabilmek için bu çağrı gereklidir.
void init_curses()
{
  initscr();

  start_color();
  init_pair(1, COLOR_WHITE, COLOR_BLUE);
  init_pair(2, COLOR_BLUE, COLOR_WHITE);
  init_pair(3, COLOR_RED, COLOR_WHITE);

  curs_set(0);
  noecho();
  keypad(stdscr, TRUE);
}
Bundan sonraki işlev üzerinde menü isimleri bulunan satırı yazan işlevdir. Biraz aşağılara inerek yazılımda yalnızca bir satır olarak görülen menü çubuğunun, main işlevi içerisinde stdscr'nin alt penceresi olarak tanımlanmış tek satırlık bir pencere olduğunu görebilirsiniz. İşte aşağıdaki işlev o pencereyi parametre olarak alıp önce artalan rengini değiştirir, sonra da menü isimlerini yazar. Menü isimlerini burada waddstr ile yazıyoruz. Bu tercihin belirli bir sebebi yok, istenilen işlev kullanılabilirdi. İlk satırdaki wbkgd çağrısı ile pencerenin renk çifti olarak tanımlanan 2 numaralı çiftin dışında bir renk çifti (3) ile yazmak istediğimizde wattron işlevini kullandığımıza dikkat edin. Yeniden 2 numaralı çift ile yazmak için ise wattroff kullanıyoruz.
void draw_menubar(WINDOW *menubar)
{
  wbkgd(menubar, COLOR_PAIR(2));
  waddstr(menubar, "Menu1");

  wattron(menubar, COLOR_PAIR(3));
  waddstr(menubar, "(F1)");
  wattroff(menubar, COLOR_PAIR(3));

  wmove(menubar, 0, 20);
  waddstr(menubar, "Menu2");

  wattron(menubar, COLOR_PAIR(3));
  waddstr(menubar, "(F2)");
  wattroff(menubar, COLOR_PAIR(3));
}
Sıradaki işlev F1 ya da F2 tuşlarına basıldığı zaman menülerin açılmasını sağlayan işlevdir. Menü açılma etkisi oluşturmak için artalanı oluşturan pencere (mavi renkli) üzerine menü çubuğu ile aynı renkte (beyaz) yeni bir pencere açılmaktadır. Ancak bu yeni pencere açıldığı zaman altta kalan pencerede yazılmış olan yazıların silinmesini istemiyoruz. Menü kapandığı zaman bu yazıların yeniden görünmesini istiyoruz. Bu sebeple yeni oluşturulan pencerenin stdscr'nin bir alt penceresi olarak oluşturulması doğru değildir. Aşağıda da görüldüğü gibi items[0] adlı pencere newwin işleviyle oluşturulmuştur. Diğer 8 tane items penceresi ise items[0]'ın alt pencereleri olarak oluşturulmuştur. Burada items[0] menüyü sınırlayan çerçeveyi çizmek için kullanılırken diğer pencereler ise hem çerçeveyi oluşturan karakterlerin üzerine yazmamak hem de menüde seçili olan elemanı göstermek için kullanılacaktır. Seçili olan elemanı göstermek için karşılık gelen items penceresinin artalan rengini diğerlerinden farklı yapmak yeterlidir. Sondan iki önceki satırda da bu yapılmaktadır ve menü ilk açıldığında birinci sıradaki eleman seçili olarak görünmektedir.
WINDOW **draw_menu(int start_col)
{
  int i;
  WINDOW **items;

  items = (WINDOW **) malloc(9 * sizeof(WINDOW *));
  items[0] = newwin(10,19,1,start_col);
  wbkgd(items[0], COLOR_PAIR(2));
  box(items[0], ACS_VLINE, ACS_HLINE);
  items[1] = subwin(items[0], 1, 17, 2, start_col + 1);
  items[2] = subwin(items[0], 1, 17, 3, start_col + 1);
  items[3] = subwin(items[0], 1, 17, 4, start_col + 1);
  items[4] = subwin(items[0], 1, 17, 5, start_col + 1);
  items[5] = subwin(items[0], 1, 17, 6, start_col + 1);
  items[6] = subwin(items[0], 1, 17, 7, start_col + 1);
  items[7] = subwin(items[0], 1, 17, 8, start_col + 1);
  items[8] = subwin(items[0], 1, 17, 9, start_col + 1);

  for (i = 1; i < 9; i++)
    wprintw(items[i], "Item%d", i);

  wbkgd(items[1], COLOR_PAIR(1));
  wrefresh(items[0]);

  return items;
}
Sıradaki işlev yukarıdaki işlev tarafından oluşturulan menü pencerelerini yokeden işlevdir. Bunun için önce pencereler tek tek delwin ile yokedilip daha sonra da items akım göstericisi için alınan bellek geri verilmektedir.
void delete_menu(WINDOW **items, int count)
{
  int i;

  for (i = 0; i < count; i++)
    delwin(items[i]);

  free(items);
}
scroll_menu işlevi menüler arasında ve menü içinde gezmeyi sağlayan işlevdir. Sonsuz bir döngü içinde getch işlevi ile klavyeden girilen tuşları okumaktadır. Kullanıcı aşağı yukarı ok tuşlarına basarsa menüde aşağıdaki ya da yukarıdaki eleman seçili olarak gösterilmektedir. Bu, yukarıda da bahsettiğim gibi, seçili olan elemanın bulunduğu pencerenin artalan rengini diğerlerinden farklı yaparak sağlanmaktadır. Kullanıcı eğer sağ ve sol ok tuşlarına basarsa içinde bulunulan menü kapatılmakta ve diğer menü açılmaktadır. Kullanıcı <Enter> tuşuna basarsa seçilmiş olan elemanın değeri geri döndürülür. <Escape> tuşu ise herhangi bir elemanı seçmeden menüleri kapatmaya yarar. İşlev diğer tuşları dikkate almamaktadır. Bu işlevde getch ile klavyeden ok tuşlarının okunabilmesi için iki hatırlatma yapmakta fayda var. Öncelikle en baştaki init_curses işlevinde keypad(stdscr, TRUE) çağrısı yapılarak stdscr'den işlev tuşlarının okunabilmesi sağlanmıştı. Buna ek olarak bir de getch ile okunan değer int türünde bir değişkende saklanmaktadır, çünkü ok tuşları ve diğer işlev tuşlarının sayısal değerleri char türünde bir değişkenin tutabileceğinden büyüktür.
int scroll_menu(WINDOW **items, int count, int menu_start_col)
{
  int key;
  int selected=0;

  while(1)
  {
    key = getch();
    if (key == KEY_DOWN || key == KEY_UP)
    {
      wbkgd(items[selected + 1], COLOR_PAIR(2));
      wnoutrefresh(items[selected + 1]);

      if (key == KEY_DOWN)
        selected = (selected + 1) % count;
      else
        selected = (selected + count - 1) % count;

      wbkgd(items[selected + 1], COLOR_PAIR(1));
      wnoutrefresh(items[selected + 1]);
      doupdate();
    }
    else if (key == KEY_LEFT || key == KEY_RIGHT)
    {
      delete_menu(items, count + 1);
      touchwin(stdscr);
      refresh();
      items = draw_menu(20 - menu_start_col);
      return scroll_menu(items, 8, 20 - menu_start_col);
    }
    else if (key == ESCAPE)
      return -1;
    else if (key == ENTER)
      return selected;
  }
}
Son olarak sırada main işlevi var. main işlevi yukarıda anlatılan işlevleri kullanarak yazılımın çalışmasını sağlamaktadır. Bu işlev de getch ile basılan tuş değerleri okumakta ve eğer F1 ya da F2 tuşlarına basılmışsa draw_menu ile karşılık gelen menüyü çizdirmektedir. Menü çizildikten sonra scroll_menu işlevi ile menülerden bir eleman seçilmesi sağlanmaktadır. scroll_menu işlevi geri döndükten sonra da önce menü pencereleri silinmekte ve ardından seçilen eleman messagebar penceresine yazdırılmaktadır.
Burada touchwin işlevine değinmekte fayda var. Menüler kapandıktan sonra touchwin çağrılmadan refresh yapılsaydı en son açılan menü ekranda durmaya devam ederdi. Bunun sebebi menüler oluşturulduğu zaman stdscr üzerinde hiçbir değişiklik yapılmaması ve refresh çağrıldığı zaman stdscr hiç değişmemiş olarak görüldüğü için yeniden yazılmamasıdır. touchwin işlevi parametre olarak aldığı pencerenin tüm satırlarındaki satırın değiştiğini belirten bayrakları doğrulayarak bir sonraki refresh'te pencerenin, hiç değişmemiş olsa bile, en baştan çizilmesini sağlar. Menüler oluşturulduğu zaman stdscr'ye hiç dokunulmamış olması sayesinde, menüler kapandığı zaman stdscr'de yazan bilgi kaybolmamıştır.
int main()
{
  int key;
  WINDOW *menubar, *messagebar;

  init_curses();

  bkgd(COLOR_PAIR(1));
  menubar = subwin(stdscr, 1, 80, 0, 0);
  messagebar = subwin(stdscr, 1, 79, 23, 1);
  draw_menubar(menubar);
  move(2, 1);
  printw("Press F1 or F2 to open the menus. ");
  printw("ESC quits.");
  refresh();

  do {
    int selected_item;
    WINDOW **menu_items;

    key = getch();
    werase(messagebar);
    wrefresh(messagebar);

    if (key == KEY_F(1)) {
      menu_items = draw_menu(0);
      selected_item = scroll_menu(menu_items, 8, 0);
      delete_menu(menu_items, 9);

      if (selected_item < 0)
        wprintw(messagebar, "You haven't selected any item.");
      else
        wprintw(messagebar, "You have selected menu item %d.", selected_item + 1);

      touchwin(stdscr);
      refresh();
    } else if (key == KEY_F(2)) {
      menu_items = draw_menu(20);
      selected_item = scroll_menu(menu_items, 8, 20);
      delete_menu(menu_items, 9);
      wprintw(messagebar, "You have selected menu item %d.", selected_item + 1);

      if (selected_item < 0)
        wprintw(messagebar, "You haven't selected any item.");
      else
        wprintw(messagebar, "You have selected menu item %d.", selected_item + 1);

      touchwin(stdscr);
      refresh();
    }
  } while (key != ESCAPE);

  delwin(menubar);
  delwin(messagebar);
  endwin();

  return 0;
}
Aralara yazdığım açıklamaları çıkarıp kaynak kodunu example.c adlı dosyaya kaydettiğinizi varsayarak,
gcc example.c -o example -lcurses
komutu ile kodu derleyebilir ve yazılımı test edebilirsiniz.
Önceki Üst Ana Başlık Sonraki
İşlev Tuşları Başlangıç Sonuç
Bir Linux Kitaplığı Sayfası