Python ve Curses

Weechat Ekran Görüntüsü

Curses, kullandığınız terminal tipinden bağımsız olarak bir ekrana çizim ve klavye denetim için oluşturulmuş tamamen taşınabilir bir kütüphanedir. Unix tabanlı bir terminalde renk kodu olarak dizgemizin başına '\033' gibi eklentiler koyarak renklendirme yapmak, hatta çoğu terminalde bu renklendirme standartlarının değişik olmasından kaynaklanan vakit kaybı, uygulama çalışırken kullanıcının bastığı harfin ekrandaki yazılara eklenip çirkin bir görüntü oluşturması, uygulamamızın ekranın sadece sağ üst köşesindeki çıktılarımızı temizlemesi için X,Y koordinatlarıyla ilgili birtakım algoritmalar üretmek gibi dertlerden bizi kurtaran naçizane bir kütüphanemizdir. Weechat, tmsnc, GNU Midnight Commander, YAST gibi uygulamalarda kullanılan bir kütüphanedir.

Midnight Commander ekran görüntüsü

Python ile Curses kütüphanesi fonksiyonları erişimi basitleştirilmiş, kullanımı kolaylaştırılmış ve gereksiz ayrıntılar kullanıcıdan saklanarak vakit kaybı azaltılmıştır.

Curses'ın ne olduğu hakkında temel bilgi sahibi olduktan sonra artık bir uygulama yapma zamanımız geldi. İlk örnek olarak 'ifconfig' çıktımızı renklendirelim. Haydi başlayalım, az laf çok iş!

Şimdi ifconfig çıktımızda, her ağ arayüzü (eth0, wlan0, lo, eth1) için farklı bir renkte çıktı alalım. Aynı anda sadece tek bir arayüz görelim ve boşluk tuşuna basınca sıradaki arayüzü farklı bir renkle ekranda görelim. Q tuşuna basınca programdan çıkalım ve başka bastığımız tuşlar hiçbir şey yapmasın ekranda.

Öncelikle dosyamızın ismi ifacecontroller.py olsun.

İçine;

import curses
import os

satırlarını ekleyelim. Os kütüphanesini de eklememin sebebi ifconfig çıktısını bu yolla alacak olmamız. Daha sonra bizim terminalimizin başlangıç ayarlarının yapılacağı ve terminal bilgimizin saklanacağı bir nesne oluşturuyoruz. Bu nesne daha sonra Curses uygulamamız olan main fonksiyonumuza parametre olarak geçecek.

stdscr = curses.initscr()

Bu stdscr nesnesi, içinde terminalimizle ilgili her şeyi tutuyor. Fiziksel olarak da açık olan terminalin tüm genişliğini ve yüksekliğini ana pencere olarak kabul ediyor. Daha sonra istersek bu ana pencereden alt pencereler oluşturabiliyoruz.

Daha sonra uygulamamızı yapılandırmak için :

curses.noecho()
curses.cbreak()
stdscr.keypad(1)
curses.start_color()

noecho methodu : Program çalışırken tuşa bastığınızda ekranda gözükmesini engelleyici önlemleri alır.
cbreak methodu: Klavyede bir tuşa bastığınızda Enter'a basınca okumaktansa, tuşa basıldığı anda uygulamanın bundan hemen haberi olmasını sağlıyor.

keypad methodu: Parametre 1 göndererek terminale PageUp, PageDown ya da Sol Sağ yön tuşları gibi birden çok byte tutan özel tuşlara bastığınızda bunları kendiniz algoritmik olarak tanımaktansa, curses kütüphanesinden KEY_LEFT,KEY_RIGHT gibi etiketlerle bunu size döndürmesini istediğinizi belirtmiş oluyoruz.

start_color methodu: Uygulamamızda renk kullanmak istediğimizi belirtmemize yarıyor.

Curses kütüphanesinin belki de en tehlikeli ve zayıf yanı, siz özel bir önlem almadığınızda, programdan herhangi bir şekilde beklenmedik çıkış yaşanırsa ( CTRL+C ya da exception gibi) programın çalıştığı terminal ayarlarını yukarıda anlatılan şekilde değiştirdiğimizden dolayı terminalimizin tabir-i caizse kendinden geçmesi ve hâlâ Curses uygulamamızda çalışıyor gibi davranmasıdır. Bunu engellemek için bir uzun bir de kısa yol var. Uzun yol şu şekilde:

if __name__=='__main__':
try:
    stdscr=curses.initscr()
    curses.noecho()
curses.cbreak()
    stdscr.keypad(1)
    curses.start_color()
    main(stdscr)
  finally:
    stdscr.keypad(0)
    curses.echo()
    curses.nocbreak()
    curses.endwin()

stdscr ekran nesnemiz oluştuktan sonra ve bahsettiğimiz terminalimizi bizim isteğimize göre ayarlayan kodlardan sonra main (stdscr) fonksiyonunu çağırıyoruz. Eğer program çalışırken beklenmedik bir durum olursa exception oluşur ve kod mainden çıktıktan sonra finally bloguna geçer. Yaptığımız ayarları

stdscr.keypad(0)
curses.echo()
curses.nocbreak()

satırlarıyla tersine çeviriyoruz. endwin methodumuzla curses uygulamamızdaki tüm pencereleri de kapatıyoruz.

Şimdi kısa yola bakalım;

if __name__=='__main__':
curses.wrapper(main)

Evet, Curses'ın wrapper fonksiyonu bizim main uygulamamızı tamamen korumaya alarak yukardaki kodların yaptığının aynısını yapıyor, eğer exception oluşursa terminal ayarlarını düzeltip tüm pencereleri kapatıyor. Yani yukarıda yazdığımız uzun kod parçası, Wrapper fonksiyonunun iç yapısıydı. Artık içini bildiğimize göre gönül rahatlığıyla kullanabiliriz.

Artık gerekli hazırlıkları yaptığımıza göre uygulamamıza geçebiliriz. Haydi main fonksiyonumuzu yazalım.

def main(stdscr):
 curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
  curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK)
  curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_BLACK)

init_pair methodu ile renk temalarımızı ayarlayalım. İlk parametre, o temanın numarası; ikinci yazı rengi, üçüncü ise arka plan rengi olmak üzere üç tane tema ayarladık.

    quit = "no"
our_color = 0
strno = 0
outputstr = os.popen("ifconfig").read()
strarray = [""]

for line in outputstr.splitlines():
if line == '':
      strarray.append("")
      strno = strno +1;
    else:
     strarray[strno] = strarray[strno] + line + '\n'

String değişkenimiz outputstr içine, ifconfig komutumuzun çıktısını os.popen(komutismi).read() satırıyla atıyoruz.

For döngümüzdeki algoritma, ifconfig komut çıktısının her satırını listemizin strno'uncu elemanına ekliyor. Eğer boş bir satır döndüyse ( ifconfig'de yeni arayüze geçmeden boş bir satır bulunur) yani yeni bir arayüzün çıktısına geldiysek, listemizde yeni bir göz açıp artık bu göze yazmaya başlıyoruz.

Döngü sonunda strarray listemizin ilk elemanı ilk arayüzün metinlerini, ikinci elemanı ikinci arayüzün metinlerini içeriyor.

    while( quit== "no"):
ch = stdscr.getch()

    if (ch == ord('q')):
     quit= "yes"
    elif (ch == ord(' ') or ch == curses.KEY_F1):
      our_color = (our_color % 3) + 1
      strno = (strno +1)% (len(strarray) -1)
      stdscr.clear()
      stdscr.addstr( strarray[strno] ,curses.color_pair( our_color ))
      stdscr.refresh()

Şimdi devam edelim... While içinde artık ifconfig'i parse ettiğimize göre ekrana basabiliriz.. Bir tuş okuyup ch değişkenine getch() yardımıyla Enter beklemeden saklayalım. Eğer kullanıcı q tuşuna bastıysa döngüden çıkacağız. Eğer kullanıcı Space'e bastıysa ekrana basacağız. Burada Space yanındaki 2. şartta kullanıcı F1 tuşuna bastıysa kontrolü yapılıyor, hatırlarsanız keypad methoduyla bastığımız tuşları etiket şeklinde almak istediğimizi belirmiştik. Burada Curses'da F1 tuşu curses. KEY_F1 olarak etiketlenmiş. Else If kolumuza girecek olursak, ilk satır renklerin her seferinde (0,1,2) renk temasında dolaşmamız için değiştiğini, strno ise arayüzlerimizi attığımız strarray dizisini dolaşmamız için kullanacağımız indis.

stdclear.clear() methodu ile ekranı temizliyoruz öncelikle.

stdscr.addstr() methodu üzerinde duralım. Curses kütüphanesinde birşey ekrana basmak istiyorsak önce basacağımız metni bu methoda gönderiyoruz. İlk parametre ile ekrana gelecek yazımızı veriyoruz; color_pair metoduyla our_color=(0,1,2) nolu temayı seçeceğimizi belirtiyoruz. refresh() methodu ile stdscr nesnesinin tuttuğu yazının ekrana basılmasını onaylıyor, ekranı tazeliyoruz.

Curses Ekran Görüntüsü - 1

Çalıştırdığımızda Space tuşuna her bastığımızda farklı bir renkte farklı bir ağ arayüzü göreceğiz. Ifconfig çıktısını While döngüsü içinde alarak güncelliği koruyabilirdik.

Curses Ekran Görüntüsü - 2

Curses Ekran Görüntüsü - 3

Yazımızın sonuna geldik. Curses kütüphanesi daha birçok methodlara sahip. Window ve pad oluşturma methodları, ekranda tüm ekranı değil de sadece bir pencerenin işaret ettiği alanı yeniden çizmenizi, tuş yakalamalarda tamamen kontrole sahip olmanızı ve daha birçok özelliğe sahip geniş bir kütüphane.

Umarım eğlenerek okumuşsunuzdur.

For the power of the shell!

2 yorum .

yazdır
Son güncelleme: 08 Haziran 2009