10 Aralık 2014 Çarşamba

Numpy: Veri Dosyaları


Python programındaki anlık veriler fiziksel bellek üzerinde depolanır ve program sonlandırıldığında kaybolur. Bu yüzden verileri kalıcı hale getirmek ve daha önceden kaydedilmiş veri blokları programımızda kullanmak için dosyadan veri alışverişi yapma ihtiyacı duyarız. Veri dosya içerisinde yazılı metin olarak durduğundan biçimi, verinin nasıl okunup yazılmasını gerektiğini belirler. Bu bölümde Numpy kütüphanesinin dosya işlemleri için bize sunduğu fonksiyonlarıyla düzenli dosya okuyup yazmanın nasıl yapıldığını göreceğiz.

Hızlı okuyup yazma
Dizileri dosyaya yazdırmanın en basit yolu tofile komutunu kullanmaktır. Bu fonksiyon fiziksel hafızada depolandığı biçimiyle yani ikili(binary) olarak diziyi kaydeder. Bu yöntem hızlı olsa da veri dosyalarının taşınabilir olması istenen durumlar için tavsiye edilmez çünkü kayıt formatı mevcut donanıma ve işletim sistemine bağlıdır. Kaydedilen ikili dosyalar fromfile komutu ile okunabilir. 
>>> from numpy import *                      # Numpy kütühanesini ekliyoruz
>>> dizi = ndarray(shape(2,2), dtype='int')  # 2x2'li dizi oluşturup değer atıyoruz
>>> dizi[0,0] = 1; dizi[0,1] = 2; dizi[1,0] = 3; dizi[1,1] = 4;
>>> print(dizi)
[[1, 2]
[3, 4]]
>>> dizi.tofile('dizi.dat')
>>> dizi_kopya = fromfile('dizi.dat', dtype='int')
>>> print(dizi_kopya)
[1, 2, 3, 4]
dizi.dat dosyasını açmaya çalıştınızda ascii karakterlerden oluştuğunu göreceksiniz. Dosya ikili formatta olduğu için yalnızca yine Python kodu tarafından açılıp okunabilir. Ayrıca görüldüğü gibi dizimizin şekli korumayıp geri alındığında tek boyutlu dizi olarak elde edilmektedir. Bu sebeplerden ötürü kalıcı dosya kayıtları için yukarıda bu tip dosya okuyup yazma tercih edilmemektedir. Yerine daha işlevsel olan savetxt, loadtxt komutları kullanılır.

Metin biçiminde okuyup yazma
Metin veri dosyası istenilen biçimde şekillendirilebilir. Örneğin; birçok ölçüm cihazının yazılım arayüzü ölçüm değerlerini kaydettiği dosyada öncelikle ölçüme ait ortam parametrelerini verir ve ardından sütunlar halinde sonuçları sıralar. Başka bir örnek de HDF gibi yapısal veri dosya biçimleridir. Bu dosyalarda veri ait olduğu nesnenin sınıfın altında verilir. Benzer birçok örnek de verilebilir. İşte bu sebepten ötürü yazılımcılar genellikle farklı biçimleri de sorunsuzca okuyup yazmaya imkan tanıyacak fonksiyonlar ararlar. Python programlama dili, Numpy kütüphanesi sayesinde bize oldukça işlevsel olan loadtxt, savetxt komutlarını bize sunar.  İki komut benzer yapıda olup, adından da anlaşılacağı üzere biri dosyaya kaydetmeyi, diğeri de dosyadan veri okumayı sağlar. Öncelikle bir örnekle dizimizi farklı biçimlerde nasıl dosyaya yazdırabildiğimizi görelim ardından da bu dosyalardaki verileri okumaya çalışalım.
>>> dizi = random.radom(6)          # 6'lık dizi oluşturup rastgele değer atıyoruz
>>> matris = reshape(dizi, (3,2))   # diziyi matris biçiminde şekillendiriyoruz
>>> print(matris)                   # matrisi ekrana yazdırıyoruz
[[ 0.71822401, 0.59663587]
 [ 0.5858213 , 0.12121402]
 [ 0.32291168, 0.32205304]]
>>> # herbir iki sütun da farklı formatta olacak biçimde dosyaya yazdırıyoruz.
>>> savetxt('matris.txt', matris, fmt=['%.2','%.5f'], delimiter=',', newline='\n',\
... header='Dizi yazdiriliyor...', footer='Dizi yazdirildi.', comment='#')
Görüldüğü gibi tek bir komutla veri dosyamızdaki sütünların formatını belirleyip yorum satırları da ekleyerek yazdırabiliyoruz. Buradaki fmt veri sütunlarının formatını, delimiter sütunların hangi karakterle birbirinden ayrılacağını, newline satırların hangi karakterle ayrılacağını, header ve footer sırasıyla alt ve üst yorum cümlelerini, comment yorum cümlelerinin hangi karakterle başlayacağını belirtir. Şimdi dosyamız içindeki verilerin nasıl göründüğünü bakalım.
# Dizi yazdiriliyor...
0.72,0.59664
0.59,0.12121
0.32,0.32205
# Dizi yazdirildi.
Dosyamızı yazdırdıktan sonra benzer şekilde loadtxt komutu ile verileri otomatik olarak dizi nesnesine aktarabiliriz. Sadece değerler diziye aktarılacağı için yorum cümleleri göz ardı edilir.
>>> # matrisi geri al
>>> matris = loadtxt('matris.txt', dtype='float', comments='#', delimiter=',')
>>> print(matris)
[[0.72 0.59664]
 [0.59 0.12121]
 [0.32 0.32205]]
>>> # ilk iki sütunu ayrı ayrı dizilere al
>>> s1, s2 = loadtxt('matris.txt', dtype='float', comments='#', delimiter=','\
... usecols=(0,1), unpack=True) )
>>> print(s1)
[0.72 0.59 0.32]
>>> print(s2)
[0.59664 0.12121 0.32205]
Görüldüğü gibi Numpy kütüphanesinin sunduğu fonksiyonlar sayesinde verilerimizi; standart dosya açma, kapama işlemlerine ve döngü ile değerleri teker transfer etmeye gerek kalmadan kolayca okuyup yazabiliriz.

26 Ekim 2014 Pazar

Numpy: Matrisler ve Basit Lineer Cebir

Sayısal analiz kitaplarının muhtevasını incelediğinizde fark ederseniz; birçoğu ilk bölümlerde doğrusal denklem sistemleri yani lineer cebir konusunu ele alır. Lineer cebirin bu kadar önemli olmasının sebebi, sayısal hesaplamaların çoğunun nihayetinde matris ve vektörlerden oluşan  doğrusal denklemlere indirgeniyor olmasıdır. Derslerimizin şu ana kadar ki kısımlarında genel olarak tek boyutlu vektörlerden bahsettik. Şimdi matrisleri biraz ayrıntılı irdeleyip Numpy kütüphanesini kullanarak temel lineer cebir işlemleri nasıl yapabileceğimiz öğrenelim.  
Matrisler
Matrisleri vektörler gibi oluşturabiliriz. Ancak matrislere özgü fonksiyonlar da mevcuttur. Bunları eye, identity, diag fonskiyonları olarak sıralayabiliriz. eye, identity fonksiyonları birbirine çok benzer olup birim matris oluşturmaya yarar.
>>> from numpy import *    # Numpy kütüphanesini ön alan adı eki olmadan ekliyoruz
>>> print(identity(3))     # birim köşegen matris
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
>>> print(eye(3))          # birim köşegen matris
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
>>> print(eye(3, k=1))     # köşegenin bir üst çapraza birim vektör ekleme 
[[ 0.  1.  0.]
 [ 0.  0.  1.]
 [ 0.  0.  0.]]
>>> print(eye(3, k=-2))    # köşegenin iki alt çapraza birim vektör ekleme 
[[ 0.  0.  0.]
 [ 0.  0.  0.]
 [ 1.  0.  0.]]
diag ise oldukça işlevsel bir fonksiyondur ve girilen bir vektörden köşegen matris oluşturur. Bu komut sayesinde aynı zamanda bant matrisleri de çok kolay oluşturabiliriz.
>>> print(diag([2,3,4], k=0))       # [2,3,4] dizisinden köşegen matris
[[2 0 0]
 [0 3 0]
 [0 0 4]]
>>> print(diag([2,3,4], k=1))       # aynı diziden bir üst köşegen matris
[[0 2 0 0]
 [0 0 3 0]
 [0 0 0 4]
 [0 0 0 0]]
>>>
>>> # üçlü bant matris oluşturma
>>> print(diag(ones(4),k=-1) + diag(2*ones(5),k=0) + diag(ones(4), k=1))
[[ 2.  1.  0.  0.  0.]
 [ 1.  2.  1.  0.  0.]
 [ 0.  1.  2.  1.  0.]
 [ 0.  0.  1.  2.  1.]
 [ 0.  0.  0.  1.  2.]]

Lineer Cebire Giriş
Lineer cebir temel olarak matrislerin özelliklerini ve tek boyutlu vektörlerle olan işlemlerinin halidir. En genel halde bir lineer cebrik sistem A matris x ve b tek boyutlu vektör olmak üzere Ax=b şeklinde bir forma sahiptir. Bu sistemin çözülebilmesi için gerekli olan temel işleçler çarpım ve bölme işlemleridir. Matris-matris, matris-vektör çarpma/bölme işlemi bir önceki yazımızda anlattığımız vektörel aritmetikten farklı olup birebir elemanların çarpımı veya bölümüyle yapılmaz. O yüzden Numpy'de bu amaçla hususi fonksiyonlar tanımlanmıştır. Farkı anlamak için aşağıdaki örneklere göz atalım.
>>> A = ones((4,4))    # 1'lerden oluşan matris
>>> x = ones(4)        # 1'lerden oluşan vektör
>>> b = A*x            # matrisin her bir sütununun x ile vektörel çarpımı
>>> print(b)
[[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
>>> b = dot(A,x)      # lineer cebir çarpımı
>>> print(b)
[ 4.  4.  4.  4.]
Görüldüğü gibi ' operatörü bizim istediğimiz manada lineer cebir çarpımını değil vektörel formdaki çarpım işlevini yerini getirir. Bu yüzden Numpy'de matris-vektör çarpımı için dot fonksiyonu tanımlanmıştır. Benzer şekilde lineer cebrik sistemin çözümü için bölme işlemine yani x=b/A ifadesini hesaplayabilmemiz lazım. Bu işlem için yine direkt bölme operatörünü kullanmak yerine linalg alt kütüphanesi içerisindeki inv komutuyla matrisin tersini bulup b vektörüyle çarpabiliriz. 
>>> A = random.random((4,4))     # rastgele kare A matrisi
>>> print(A)
[[ 0.69769186  0.79776825  0.09984681  0.21271922]
 [ 0.05979394  0.72758335  0.0570817   0.59825989]
 [ 0.61698744  0.29374527  0.82004994  0.41084264]
 [ 0.02961924  0.86964469  0.63311203  0.82975882]]
>>> b = random.random(4)         # rastgele b vektörü
>>> print(b)
[ 0.20801453  0.81169016  0.84603751  0.74985329]<
>>>
>>> x = dot(linalg.inv(A), b)    # Ax=b çözümü olarak x=A^-1*b
>>> print(dot(A,x))              # bulduğumuz çözümün sağlamasını yapıyoruz (Ax=b) 
[ 0.20801453  0.81169016  0.84603751  0.74985329]
Lineer sistemin çözümünü yukarıdaki gibi tersini alıp çarpmayla uğraşmak yerine linalg.solve komutunu kullanarak kısa yoldan gerçekleştirebiliriz.
>>> x = linalg.solve(A,b)
>>> print(dot(A,x))       # yine sağlamasını yapıp A*x=b olduğunu kontrol ediyoruz
[ 0.20801453  0.81169016  0.84603751  0.74985329]
Üniversitede lineer cebir almış olanlar bilirler matrisin determinantı ve öz değer/vektörlerini kağı kalemle bulmak oldukça meşakkatlidir. Numpy'nin lineer cebir paketi sayesinde tek bir komutla bu işlemlerimizi basitçe halledebiliriz.
>>> A = diag([2,3,4], k=0)
>>> print(A)             # köşegen A matrisi
[[2 0 0]
 [0 3 0]
 [0 0 4]]
>>> print(linalg.det(A)) # determinantı
24.0
>>> l, v = linalg.eig(A) # eig komutu öz değer ve öz vektörden oluşan iki döndürür
>>> print(l)             # öz değerler
[ 2.  3.  4.]
>>> print(v)             # öz vektörler yazdırılan matrisin sütunlarıdır
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
Oldukça geniş bir konu lineer cebrik sistemlere ilişkin yazımızı, Scipy kütüphanesinin konuları arasında daha fazla değinmek üzere şimdilik bitiriyoruz.

21 Ekim 2014 Salı

Django Purge Pagination

Django'da sayfalama için kullanabileceğimiz uygulama olan purge-pagination'dan bahsedeceğiz. Django'nun sayfalama yapısı bizim tam olarak işimizi görmediği için bu sayfalama uygulamasını kullanabiliriz. Genelde sayfa sayısının çok fazla olduğu yerlerde tüm sayfalar gösterilmektense baştan bir kaç sayfa bulunulan sayfa ve sondan bir kaç sayfa gösterilerek güzel bir görüntü oluşması sağlanır. Purge Pagination bu işi halletmemizi sağlıyor. Kurmak için
pip install django-pure-pagination
Uygulamayı kurduktan sonra projemize eklememiz gerekiyor. Bunun için;
INSTALLED_APPS = (
    ...
    'pure_pagination',
)
Uygulamayı yükledikten sonra settings.py içerisinde ayarlamalarını yapabiliriz.
PAGINATION_SETTINGS = {
    'PAGE_RANGE_DISPLAYED': 10,
    'MARGIN_PAGES_DISPLAYED': 2,
}
Buradaki PAGE_RANGE_DISPLAYED ayarı ortada kaç tane sayfa göstericeğini belirtiyor. MARGIN_PAGES_DISPLAYED ise başta ve sonra kaç sayfa olacağını gösteriyor. Yani sayfalama başta 2 sayfa...ortada 10 sayfa...sonda 2 sayfa şeklinde olacak.
Uygulamayı eklediğimize göre kullanabiliriz. Django'nun kendi Pagination yapısı ile kullanımı hemen hemen aynı. Django'da Pagination metodlarınışu şekilde yürklüyoruz.
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
Purge Pagination'da ise sadece uygulama değişiyor. Metodlar ve kullanımları aynı.
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger
View içerisinde şu şekilde kullanabiliriz.
tum_yazilar = Yazilar.objects.filter(onay=1)
yazi_sayfalari = Paginator(tum_yazilar, 10, request=request) 
yazilar = yazi_sayfalari.page(page)
Son olarak ise template içerisinde sayfaları şu şekilde gösterebiliriz.
        {% if yazilar.has_previous or yazilar.has_next %}
            {% load i18n %}
            
    {% if yazilar.has_previous %}
  • {% else %}
  • ‹‹
  • {% endif %} {% for page in yazilar.pages %} {% if page %} {% ifequal page yazilar.number %}
  • {{ page }}
  • {% else %}
  • {{ page }}
  • {% endifequal %} {% else %}
  • ...
  • {% endif %} {% endfor %} {% if yazilar.has_next %}
  • {% else %}
  • ››
  • {% endif %}
{% endif %}
Artık sayfalamamız şuna benzer bir şekilde görünecektir. Sizin temanıza göre stili değişir. Fakat sayfa sayısı bu şekilde olacaktır. Burada resmi uygulamanın github hesabından aldık.
Kaynakça

6 Ekim 2014 Pazartesi

Numpy: Vektörleştirme ve Dilimleme


Bilimsel hesaplamalarda ekseriyetle büyük veri kümeleri üzerinden işlem yapılır. Klasik programlamada, bu türden hesaplamalar liste halindeki sayısal değerlerin döngü içerisinde birer birer çağrılmasıyla yapılır. Ancak günümüzde ise mümkün mertebe döngü kullanımından kaçınılmaktadır. Hatta büyük firmalar tarafından bu amaca yönelik optimize edilmiş program arayüzleri ve kütüphaneler ticari olarak geliştirilmektedir (Matlab, Intel MKL). Bu yazımızda da Python'un Numpy kütüphanesi sayesinde dizi halindeki sayısal veriler üzerinden nasıl hızlı ve basit işlemlerimizi gerçekleştirebileceğimizden bahsedeceğiz. 

Vektörleştirme

Girişte de bahsettiğimiz gibi bir matematiksel işlemi çoğunlukla dizi halindeki verinin tüm elemanları üzerinden gerçekleştirmek isteriz. Bu durumda işlemi for döngüsü içerisinde dizinin herbir elemanı için teker teker yapmak yerine Numpy kütüphanesi sayesinde tek değer üzerinden işlem yapıyormuş gibi gerçekleştirebiliriz. Şimdi aşağıdaki örnekte, polinom ve trigonometri ifadeleri içeren bir hesaplamayı hem döngü ile hem de vektörel formda yapıp karşılaştıralım.
>>> import time as tm   # süre tutma için gerekli olan modül
>>> import numpy as np  # Numpy kütüphanesi 'np' ön adıyla ekliyoruz
>>>
>>> N = 10000               # dizinin eleman uzunluğu
>>> x = np.random.random(N) # argüman dizisi
>>> y = np.zeros_like(x)    # sonuç dizisi
>>> 
>>> t0 = tm.clock()         # kronometre başlangıcı
>>> 
>>> # döngü ile hesap
>>> for i in np.arange(N):
...     y[i] = x[i]**2 + 3*x[i] - x[i]/5 + np.sin(x[i])
>>> t1 = tm.clock()
>>> 
>>> # vektörel hesap
>>> y = x**2 + 3*x - x/5 + np.sin(x)
>>> t2 = tm.clock()
>>> 
>>> print("Döngü ile hesaplama: %5.2f ms" %((t1-t0)*1E3))
>>> print("Vektörel hesaplama: %5.2f ms" %((t2-t1)*1E3))
Döngü ile hesaplama: 106.15 ms
Vektörel hesaplama:  0.67 ms
Görüldüğü gibi vektörel hesaplamayla basit bir hesaplamada bile en az 100 kat daha hızlı işlem yapılabilmektedir. Ayrıca kod metnimiz daha sade ve anlaşılır hale gelmiştir.
Numpy kendi dizi yapıları için temel aritmetik işlemleri (+,-,x,/) ve standart math/cmath kütüphanelerindeki fonksiyonları vektörel formda sağlamaktadır. Eğer harici fonksiyonlar da aynı verimlilikle hesap yapabilmek için vektörleştirmek istenirse bu, vectorize fonksiyonu kullanarak sağlanabilir. 
>>> from math import sqrt           # standart kütüphanedeki kök alma fonksiyonu
>>> def afunc(x):
...    if x<0:
...        return sqrt(-x) + x**2
...    else:
...        return sqrt(x) + x**2
>>> 
>>> afunc_v = np.vectorize(afunc)   # fonksiyonu vektörel hale getiriyoruz
>>> 
>>> N = 10000                       # dizinin eleman uzunluğu
>>> x = np.random.uniform(-1,+1,N)  # argüman dizisi
>>> y = np.zeros_like(x)            # sonuç dizisi
>>> 
>>> t0 = tm.clock()                 # kronometre başlangıcı
>>> 
>>> # döngü ile hesap
>>> for i in np.arange(N):
...    y[i] = afunc(x[i])
>>> t1 = tm.clock()
>>> 
>>> # vektörel hesap
>>> y = afunc_v(x)
>>> t2 = tm.clock()
>>> 
>>> print("Döngü ile hesaplama: %5.2f ms" %((t1-t0)*1E3))
>>> print("Vektörel hesaplama: %5.2f ms" %((t2-t1)*1E3))
Döngü ile hesaplama: 45.30 ms
Vektörel hesaplama:  10.99 ms
Eğer harici fonksiyonumuz sadece temel aritmetik işleçler ve standart kütüphanedeki fonksiyonları içeriyorsa yukarıdaki gibi vektörleştirmeye gerek kalmadan fonksiyonun direk kendisiyle çalışılabilir.

Dilimleme
Önceki konu başlığında tüm dizi elemanları üzerinden nasıl hızlı işlem yapabileceğimizden bahsettik. Ancak bazı durumlarda dizinin tamamıyla değil de belli kısımlarıyla işlem yapmak isteyebiliriz. Mesela; dizinin yarıdan sonrası, çift indisli elemanları gibi... Dilimleme operatörü de işte dizilerdeki elemanlara bu açıdan erişmemizi sağlar. Kullanılışı köşeli parantez içerisindeki iki nokta üst üste işaretleriyle sağlanır [ilk:son:adım]. Parantez içerisindeki tüm değerler tam sayı olmalıdır. Python'daki standart indisleme kuralları geçerlidir. Yani; son indisteki değer aralığa dahil değildir ve adım aralığı geriye doğru ilerlemek için negatif değer alabilir. Aşağıdaki kısa örneklerle kullanışını açıklamaya çalışalım.
>>> N = 10
>>> dizi = np.arange(N, dtype='int')
>>> print(dizi[::])         # dizinin tüm elemanları
[0 1 2 3 4 5 6 7 8 9]
>>> print(dizi[0:N/2:2])    # dizinin yarısına kadar 2'şer aralıklarla
[0 2 4]
>>> print(dizi[::-1])       # tersten geriye doğru birer adımlama
[9 8 7 6 5 4 3 2 1 0]
Dilimleme tekniği özellikle iteratif işlem gerektiren algoritmaların programlanmasında çok önemlidir. Şimdi bize nasıl bir kolaylık sağladığını iyice görmek açısından gerçekçi bir örnek yapalım. Bilindiği gibi analitik türevi mümkün olmayan fonksiyonların ilgili aralıktaki örnek değerleri üzerinden sayısal türevi sonlu farklar yöntemiyle belli doğrulukta hesaplanabilmektedir. Algortimayla alakalı detaylı bilgiyi http://tr.wikipedia.org/wiki/Sonlu_fark referansına bırakıp nasıl kodlandığına bakalım. Karşılaştırmayı mümkün kılmak için analitik türevini bildiğimiz sin fonksiyonunun türevini sayısal olarak üç farklı sonlu fark formülüyle aşağıdaki gibi hesaplıyoruz.
>>> # adım aralığı bilgisini de alacak şekilde eş aralıklı örnekleme
>>> N = 10  # örnekleme sayısı
>>> x, dx = np.linspace(0,+np.pi,N,retstep=True) # [0,+pi]
>>> 
>>> # test fonksiyonu ve analitik türevi
>>> y = np.sin(x)
>>> yp_analitik = np.cos(x)
>>> 
>>> # sonlu farklar
>>> yp_merkezi = ( y[2:N]-y[0:N-2] )/(2*dx) # merkezi fark
>>> yp_ileri = ( y[1:N]-y[0:N-1] )/dx       # ileri fark
>>> yp_geri = ( y[1:N]-y[0:N-1] )/dx        # geri fark
Görüldüğü gibi her bir sonlu fark hesabını dilimleme operatörü sayesinde birer satırda gerçekleştirebildik. Not olarak belirtmek gerekir ki, ileri ve geri fark ifadeleri birbirine eşit görünmekle birlikte açı dizisinde (x) karşılık geldiği noktalar farklıdır.
Yazımızı, bulduğumuz sonuçları görselleştirip, çıktılarını inceleyerek bitirelim. Aşağıdaki kodda Matplotlib kütüphanesi kullanılarak analitik türevle birlikte sayısal türevler tek bir grafik üzerinde gösterilmek istenmiştir. İleri ve geri fark sonuçları ise birbirleriyle benzer hata oranıyla analitik değere iyi bir biçimde yakınsamaktadır. Ancak beklediğimiz gibi, merkezi fark yöntemiyle hesaplanan türev diğer ikisinden daha az yanılmayla sonuca yaklaşmıştır. Örnekleme sayısını arttıracak olsaydık sayısal türev değerleri giderek daha fazla analitik değere benzeyecek, grafik eğrileri üzerinde ayırt edilemez hale gelecekti.
>>> import matplotlib.pyplot as plt # matplotlib kütüphanesini çizdiricisi
>>> 
>>> fig = plt.figure()              # yeni grafik ekranı
>>> 
>>> plt.plot(x,yp_analitik, color='blue', label='analitik')
>>> plt.plot(x[1:N-1],yp_merkezi, color='red', label='merkezi')
>>> plt.plot(x[0:N-1],yp_ileri, color='yellow', label='ileri')
>>> plt.plot(x[1:N],yp_geri, color='green', label='geri')
>>> plt.legend(loc='upper right')
>>> plt.title('Sinüs Fonksiyonunun Türevi')
>>> plt.xlabel('x')
>>> plt.ylabel('y\'(x)')
>>> plt.grid()
>>> plt.xlim(0,+np.pi)
>>> plt.ylim(-1,1)
>>> plt.show()

Kaynaklar:
[1] Langtangen H. P., Python Scripting for Computational Science, Springer, 2007

29 Eylül 2014 Pazartesi

PyQt Class Kullanımı

       Grafiksel kullanıcı arayüzüne sahip programlar genellikle bir çok pencere ve işlev içermektedir. Dolayısıyla bütün bu pencere ve işlevleri tek bir dosyada tutmak oldukça kafa karıştırıcı bir hale gelmeye başlar. Bu tür bir karmaşıklığı önlemek ve programımızı daha modüler bir hale getirmek için classları kullanırız.

Şimdi bir önceki konuda yazdığımız programı class kullanarak tekrar yazalım:
# !/usr/bin/env python
# -*- coding: cp1254 -*-
 
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class sinifProgrami(QDialog):
    def __init__(self, parent=None):
        super(sinifProgrami, self).__init__(parent)

        self.metin = QLabel('
PythonDersleri.com
') self.butonKirmizi = QPushButton('Kırmızı') self.connect(self.butonKirmizi, SIGNAL('pressed()'), self.kirmiziMetin) self.butonMavi = QPushButton('Mavi') self.connect(self.butonMavi, SIGNAL('pressed()'), self.maviMetin) izgara = QGridLayout() izgara.addWidget(self.metin, 0, 1, 2, 1) izgara.addWidget(self.butonKirmizi, 0, 0) izgara.addWidget(self.butonMavi, 1, 0) self.setLayout(izgara) self.setWindowTitle('PyQt Grid Layout') self.setFixedSize(450, 150) def kirmiziMetin(self): self.metin.setText('
Merhaba Dünyalı :)
') def maviMetin(self): self.metin.setText('
Uygar Köroğlu
') uygulama = QApplication([]) pencere = sinifProgrami() pencere.show() uygulama.exec_()

Bu kodu çalıştırdığımızda da çıktı değişmeyecektir:

PyQt classları QWidget nesnesi olabileceği gibi QDialog nesnesi de olabilir. Hangisinin nesnesi ise ona ait tüm özellikleri de taşıyacaktır. 
Yazmış olduğumuz kodları satır satır açıklamaktan ziyade bu koda baktığımızda farklı olarak gözümüze ilk şu satır çarpmaktadır:
super(sinifProgrami, self).__init__(parent)
Bu satırda parenttan bahsettik yani ebeveyn. Program alt pencerelerden oluşmaya başladığında, hangi pencerenin hangi pencereye ait alt pencere olduğunu ayırt etmek için bu yapı kullanılır. Biz bu pencerenin bir alt pencere olmadığını, bizim penceremizin bir ana pencere olduğunu parent=None ifadesiyle belirttik.
Bir class'ın başlamasını sağlamak için super() metodu kullanılmakta. super() metodu parametre olarak; ilk parametrede class'ın adını, ikinci parametrede ise self olarak kendisini alır. __init__() metoduna ise hangi pencerenin alt penceresi olduğunu parametre olarak yazarız.

28 Eylül 2014 Pazar

Veri Tabanından Model Dosyası Oluşturma

Bildiğiniz gibi Django'da veritabanı oluşturmak için ilk önce models.py dosyasında veritabanımınızın nasıl olacağına dair tanımlamaları yapıyoruz ve ardından
python manage.py syncdb
komutu ile tablolarımızı oluşturubiliyoruz. Peki ya tasarımını yaptığımız bir veritabanını model dosyası içerisine aktarmak istersek ne yapacağız. Bunun çözümüde yukarıdaki komut kadar basit. Vermemiz gereken komut şu şekikde.
python manage.py inspectdb > app/models.py
Bu şekilde app uygulaması içerisindeki models.py dosyası içerisine veritabanına uygun olan model tanımlamaları yapılacaktır. Şu tarz tanımlamalar görebilirsiniz.
class Message(models.Model):
    id = models.IntegerField(primary_key=True)
    message = models.CharField(max_length=30)
    class Meta:
        managed = False
        db_table = 'app_message'
Peki Django'nun kendi çekirdek tablolarını oluşturmak için ne yapacağız. Bunun için yine modelden tablo oluşturmamızı sağlayan komutu verebilirsiniz.
python manage.py syncdb
Kaynakça

27 Eylül 2014 Cumartesi

PyQt Pencere Düzenleri

       Grafiksel arayüze sahip programlar genellikle birden çok pencereye sahiptirler. Ve bu pencereler de genellikle kendi içlerinde farklı parçacıklar bulundurmaktadırlar. Yani kendilerine ait butonları, labelları, text alanları gibi parçacıkları olmaktadır. Biz de programlarımızı yazarken kullandığımız parçacıkların sayısı arttığında, bunları penceremize nasıl yerleştireceğimiz konusunda birtakım pencere düzeni uygulama gereksinimi duymaktayız.

Örneğin; yerleştirmek istediğimiz bir label ve bir butonumuz olsun. Bunları yandaki şekildeki gibi yan yana veya alt alta koymak isteyebiliriz.

Bu yapılar Layout olarak isimlendirilirler. Biz burada kutu demeyi tercih ediyoruz. Bu şekillerden ilki dikey bir kutu (QVBoxLayout) diğeri ise yatay bir kutudur (QHBoxLayout). Bu kutulara eleman eklemek istediğimizde (addWidget) dikey kutuda her eklenen eleman alta gelecek şekilde, yatay kutuda ise sağ tarafa gelecek şekilde ekleme işlemi gerçekleşmektedir. Bir parçacık eklemek için addWidget() metodu kullandığımız için penceremizin de QWidget() nesnesi olması gerekir.

Şimdi bu bahsettiklerimiz hakkında bir örnek yazalım ve bu örnek üzerinden kodları açıklayalım.

# !/usr/bin/env python
# -*- coding: cp1254 -*-
from PyQt4.QtGui import *

uygulamam = QApplication([])
pencere = QWidget()
etiket = QLabel('PythonDersleri.com')
buton = QPushButton('Butonum')

yatayKutu = QHBoxLayout()
yatayKutu.addWidget(etiket)
yatayKutu.addWidget(buton)

pencere.setLayout(yatayKutu)
pencere.setWindowTitle('Programım')
pencere.show()

uygulamam.exec_()

1. Satır = Yazdığımız kodların Python kodu olduğunu ve Python'un dizinini belirtiyoruz. (Linux için)
2. Satır = Türkçe karakterlerin desteklenmesini istediğimizi belirtiyoruz.
3. Satır = Grafiksel arayüz için gerekli modülü programımıza dahil ettik.
5. Satır = Bir QApplication nesnesi oluşturuyoruz.
6. Satır = Bir tane Widget oluşturduk.
7. Satır = İçeriği "PythonDersleri.com" olan bir Label oluşturduk.
8. Satır = Üzerinde "Butonum" yazan bir buton oluşturduk.
10. Satır = Yatay şekilde eleman ekleyebileceğimiz bir kutu oluşturduk.
11. Satır = Oluşturduğumuz yatay kutunun içine Labelımızı ekledik.
12. Satır = Yine yatay kutunun içine butonumuzu da ekledik.
14. Satır = Pencere düzenimizin oluşturduğumuz yatay kutu olacağını belirttik.
15. Satır = Program penceremizin başlığında "Programım" yazmasını belirttik.
16. Satır = Penceremizin görüntülenmesini istedik.
18. Satır = Uygulamamızın çalışmasını istedik.

       Kodu çalıştırdığımızda ise bize şöyle bir çıktı verecektir:

       Çalışma Sorusu: Yukarıda yatay bir kutu için yazmış olduğumuz kodu dikey bir kutu için yeniden yazın; ancak bu kez üstte buton altta label bulunsun.

PENCERE BOYUTLARI VE YERİ

       Yukarıda yazmış olduğumuz gibi bir kod yazdığımızda programımız parçacıkları yerleştirebildiği minimum boyutlarda açılacaktır. Biz istersek bu boyutları değiştirebiliriz (resize). Ancak bu değiştirme işlemi küçültme yönünde değil, büyütme yönünde yapılabilmektedir. Küçültmeye çalıştığınızda ise parçacıkların yerleştirildiği minimum boyutlarda açılacaktır. Boyutları değiştirebileceğimiz gibi programın sol üst köşeden itibaren kaç piksel uzaklıkta başlayacağını da belirleyebiliriz (move). Bu değişikliklerin nasıl olduğunu görmek için ise yukarıda yazmış olduğumuz koda pencere.setWindowTitle('Programım') satırından sonra aşağıdaki kodları ekleyin ve değişikliği görmek için çalıştırın.
pencere.resize(300, 100) # Yeni boyutlar
pencere.move(50, 50) # Sol üst köşeden uzaklık

25 Eylül 2014 Perşembe

Numpy: Dizi Oluşturma

Bu bölümde sayısal verilerin depolandığı dizileri oluşturma yöntemlerini öğreneceğiz. Python programlama dili Fortran ve C türevi dillerden farklı olarak veri bloğu için fiziksel bellekteki hafıza ayarlama işini otomatik olarak yapar. Dolayısıyla biz sadece dizimizin niteliğini ve niceliğini belirtip oluşturabiliriz. Diziyle işimiz bittiğinde Python yine bizim ek bir komut çalıştırmamıza gerek kalmadan hafızada ayrılmış yeri boşaltır. Böylece diğer programlar için de yer açılmış olur.
 
Dizi Nesnesi
Python nesne tabanlı bir programlama dilidir. Bu yüzden herbir modül veya kütüphane bir sınıf olarak düşünülebilir. Bu sınıfların nesneleri temelde constructor adı verilen inşa fonskiyonları ile oluşturulur. İnşa fonksiyonlarının parametrelerini inceleyerek nesnelerimizin temelde hangi özelliklerini barındırdığını öğrenebiliriz. Aşağıdaki örneğe göz atalım.
>>> from numpy import * # Numpy kütüphanesini ad alanı ön eki olmadan ekliyoruz
>>> ndarray(shape=(2,3), dtype=float32)
array([[  3.77839489e+22,   9.18355102e-39,   1.38829441e-40],
       [ -3.76174156e-37,   7.62234898e-39,   7.00649232e-45]], dtype=float32)
İnşa fonksiyonunun bazı parametreler aldığını görüyoruz. Bunlardan shape, oluşturmak istediğimiz boyutu bildiren bağlı sıralılardır (tuples). Yukarıdaki örnekte de bu parametreyle birlikte 2x3'lük yani iki satırdan 3 sütundan oluşan bir dizi oluşturmak istediğimiz belirtmiş olduk. dtype özelliği ise bu dizide hangi tip verilerin saklanacağını belirtir. Biz burada standart 'float32' tip veri (varsayılan) türünden bir diziyi tercih ettik. Farklı tip Python veril tipleri ('int', 'float64' vb.) de dizilerde depolanabilir.
ndarray sınıfı hafızanın elverdiği ölçüde keyfi boyutlu dizileri destekler. Örneğin; aşağıda tamsayılardan oluşan 2x2x2x2'lik bir dizi oluşturulmuştur. 
>>> ndarray((2,2,2), 'int32')
array([[[ 50398851, 505910976],
        [505910976, 505910976]],
       [[ 68431072, 657601396]]]),
        [   657961,  48016344]]])
Yazımızın bundan sonraki bölümlerinde ise anlatımı kolaylaştırmak amacıyla genelde tek boyutlu dizilerle çalışılacaktır.

Elemanlara Erişim
Dizinin herhangi bir elemanına erişmek için köşeli parantez '[ ]' operatörünü kullanabiliriz. Python'da ilk indis '0'dan başlar, ve diğer programlama dillerinden farklı olarak negatif indisleri destekler. Negatif indislerde ise ilerleme yönü sondan başa doğrudur.
>>> dizi = ndarray(5) 
>>> print(dizi)
[  3.83049187e+238   3.45262638e-316   0.00000000e+000   3.83711926e+238
   6.35862486e-321]
>>> dizi[1] = 5.0  # baştan ikinci elemana değer atandı
>>> dizi[-1] = 5.0 # en sondaki elemana değer atandı
>>> print(dizi)
[  3.83049187e+238   5.00000000e+000   0.00000000e+000   3.83711926e+238
   5.00000000e+000]
Dizinin boyutu shape fonksiyonuyla elde edilir. Tek boyutlu diziler için standart kütüphanedeki len fonksiyonu da kullanılabilir. 
>>> shape(dizi)
(5,)
>>> len(dizi)
5
Diziye ait elde edilmek istenen en önemli bilgilerden biri de maximum ve minimum değerleri, ve bunların indis konumlarıdır. max/min fonksiyonları bu değerleri, argmax/argmin fonksiyonları da bu değerlerin bulunduğu indisleri bize bildirir.
>>> min(dizi)
0.0
>>> argmin(dizi)
2
>>> max(dizi)
3.837119259946211e+238
>>> argmax(dizi)
3

Ön Tanımlı Dizi Oluşturma
Numpy dizilerini oluşturmanın aslında birçok yolu vardır. İlk olarak standart liste tipindeki verilerin nasıl diziye dönüştüğünü görelim.
>>> liste = ([1,2,3])
>>> dizi = array(liste, 'float32')  # tam sayı yerine ondalıklı olarak depolar
>>> print(dizi)
[ 1.  2.  3.]
Dizileri de tolist fonksiyonuyla tekrardan listeye dönüştürebiliriz.
>>> liste = ([4,6,7])
>>> dizi = array(liste, 'int32')
>>> liste2 = dizi.tolist()
>>> print(liste2)
[4, 6, 6]
Dizi elemanlarını baştan '0' veya '1' atayarak, veya inşa fonksiyonunda olduğu gibi varsayılan değer atayarak oluşturabiliriz.
>>> dizi = zeros(4)
>>> print(dizi)
[ 0.  0.  0.  0.]
>>> dizi = ones(4)
>>> print(dizi)
[ 1.  1.  1.  1.]
>>> dizi = empty(4)
>>> print(dizi)
[  7.35794000e-295   7.01521574e-295   7.01647004e-295   7.01440942e-295]
Dizileri önceden belirli aralıklarla da oluşturabiliriz. arange fonksiyonu sırasıyla başlangıç, bitiş ve adım aralığını parametre olarak alıp bitiş noktasının dahil olmadığı bir dizi oluşturur. linspace başlangıç ve bitiş değerleri arasındaki istenilen sayıda eş aralıklı değer türetir. arange'ten farklı olarak linspace'te adım aralığı değil örnek sayısı parametre olarak girilir ve bitiş noktası da türetilen değerler içindedir. 
>>> arange(1,10,1)
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> linspace(1,10,3)
array([1., 5.5, 10.])
logspace ise eş aralıklı örnek değerleri, istenilen tabanda logaritmik olarak verir.
>>> logspace(1, 10, N=2) # varsayılan taban değeri '10' kullanıldı
array([  1.00000000e+01,   1.00000000e+10])
>>> logspace(1, 10, N=3, base=2)
array([2., 45.25, 1024.]) # log2(2)=1, log2(45.25)=5.5, log2(1024)=10

Rastgele Dizi Oluşturma
Numpy kütüphanesindeki random sınıfı ve alt fonksiyonlarını kullanarak rastgele değerlerle doldurulmuş diziler elde edebiliriz.
>>> random.random(3)
array([ 0.5878516 ,  0.01153192,  0.84747563])
Değerler görüldüğü gibi [0,1) aralığında türetilmiştir. Eğer keyfi aralıkta olması istenirse bu uniform alt fonksiyonu kullanarak sağlanabilir
>>> # [a=3,b=5) yarı açık aralıkta rastgele N=4 adet değer
>>> random.uniform(3,5,4)
array([ 4.37716131,  3.04042835,  3.08056492,  4.89028642])

Kaynaklar:
[1] Langtangen H. P., A Primer on Scientific Programming with Python, Springer, 2009

24 Eylül 2014 Çarşamba

Numpy & Scipy

pythondersleri.com yeni bir yazı dizisi "Numpy ve Scipy : Bilimsel Hesaplamalar İçin Python" ile karşınızda! Bu yazı sayesinde akademik çalışmalar ve endüstriyel uygulamalardaki hesaplamalar için Python programlama diline bir miktar vakıf olabilmeyi amaçlıyoruz. Meselenin kapsamı geniş olduğu için ilk yazımızda içerik hakkında özet bilgi vermeyi uygun gördük.
Python'un günümüzdeki popülerliğinin en önemli sebeplerinden biri de hesaplamalı bilimlerdeki işlevselliğidir. Üst seviye bir programlama dili olan Python bu işlevselliği sayesinde; alt seviye programa dillerinde (C, C++, Fortran) yapılabilen karmaşık büyük çaptaki hesaplamaları kıyaslanabilir bir performansta, kullanıcıya büyük kolaylıklar sağlayarak (Matlab vb.) gerçekleştirebilmektedir. Python aslında bu fonksiyonelliğini biraz da modül, paket veya kütüphane olarak adlandırılan eklentilere borçludur. Bu paketlerden en meşhurları yazı dizimizin kapsamını da oluşturan Numpy ve Scipy kütüphaneleridir. Numpy genel olarak dizi/vektör/matris hesaplamaları için özelleşmiş bir kütüphane olup, büyük çaptaki veri kümeleri üzerinden işlem yapmayı kolaylaştırır. Scipy ise bünyesinde, sık kullanılan matematiksel rutinleri ve fiziksel problemlerinin bilgisayar ortamında ifade edilmesine yönelik fonksiyonları barındırmaktadır. Dersler kapsamında yeri geldiğinde ayrıca, işlenilen ve sonuç olarak elde edilen verilerin görselleştirilmesi amacıyla Matplotlib kütüphanesinde bahsedilip pratik bilgiler verilmeye çalışılacaktır.

?

Yazılardaki örnekler, Python 3.3 sürümünde çalışan kodlar olup Numpy 1.8 ve Scipy 0.13 kütüphaneleri uyumludur. Ancak ilgili kütüphanelerin kurulu olduğu herhangi bir Python 3x sürümü kullanılmasının bir sıkıntı oluşturmayacağı kanaatindeyiz. Paketlerin yüklenmesi ile ilgili yönergeler için http://www.scipy.org sitesine göz atabilirsiniz. Windows kullanıcılarına kolaylık sağlamak amacıyla üçüncü şahıslar tarafından ikili(binary) dosyalar hazırlanıp ücretsiz olarak dağıtılabilmektedir. Bunların içerisinde, diğer pek çok eklentiyi de bulabileceğiniz http://www.lfd.uci.edu/~gohlke/pythonlibs adresini tavsiye edebiliriz.
Scipy kütüphanesi arka planda Numpy dizilerinden istifade etmektedir. Bu yüzden derslerimizde öncelikle Numpy anlatılacak ardından Scipy'e geçilecektir. Numpy kapsamında aşağıdaki konulara değinilecektir.
  • Dizi oluşturma
  • Vektörleştirme ve dilimleme
  • Matrisler ve basit lineer cebir
  • Veri dosyaları
Scipy kapsamında ise aşağıdaki konu başlıkları takip edilmeye çalışılacaktır.
  • Lineer cebir
  • İnterpolasyon ve eğri uydurma
  • Sayısal integral ve türev alma
  • Fourier dönüşümü
  • Özel fonksiyonlar
  • Fizksel büyüklükler ve sabitler
  • Sembolik matematik
  • Dosya okuyup yazma

22 Eylül 2014 Pazartesi

Daha önce Django Projesini Apache ve Mod_WSGI ile Yayınlamak yazısında Apache sunucusu üzerinde nasıl proje yayınlanacağından bahsetmiştik. Bu yazıda ise çok basit bir şekilde bir apache sunucu üzerinde birden fazla Django projesi nasıl çalıştırılır bundan bahsedeceğiz. Çözümü oldukça basit. Yapmamız gereken Apache VirtualHost tanımlaması yaparken projeleri process'lere bölmek. Bu şekilde diğer projenin süreçleri projemizi hataya sürüklemeyecek ve birden fazla proje tek bir sunucuda sorunsuz bir şekilde çalışabilecektir.
Birinci proje için VirtualHost tanımlaması :

ServerAdmin info@proje1.com
ServerName proje1.com
DocumentRoot /var/www/proje1


Alias /static/ /var/www/proje1/static/
WSGIDaemonProcess proje1
WSGIScriptAlias / "/var/www/proje1/proje1/wsgi.py" process-group=proje1
ErrorLog /var/log/apache/proje1/error_log
TransferLog /var/log/apache/proje1/access_log
...

İkinci proje için VirtualHost tanımlaması :

ServerAdmin info@proje2.com
ServerName proje2.com
DocumentRoot /var/www/proje2


Alias /static/ /var/www/proje2/static/
WSGIDaemonProcess proje2
WSGIScriptAlias / "/var/www/proje1/proje1/wsgi.py" process-group=proje1
ErrorLog /var/log/apache/proje1/error_log
TransferLog /var/log/apache/proje1/access_log
...

Burada öenmli olan 8 ve 9. satırlar. 8. satırda proje için bir Process tanımlaması yapıyoruz. 9. satırda ise bu processi projemize atama işlemini yapıyoruz. Eğer bu tanımlamaları yaparsanız bir sunucu üzerinden istediğiniz kadar projeyi çalıştırabilirsiniz.

18 Eylül 2014 Perşembe

Pushover Kullanımı

Pushover, Telefona bildirim almanızı sağlayan bir servistir. Bunun için kullanımı oldukça basit olan bir api sağlamaktadır. Bu yazıda pushover apisinin Python ile nasıl kullanıldığından bahsedeceğiz?
Yapmamız gereken ilk önce https://pushover.net/ adresini ziyaret ederek üye olmak. Üye olduktan sonra ana sayfada size bir key verildiğini göreceksiniz.
Bize verilen keyi birazdan kullanacağız. Ama ondan önce resmin altında gördüğünüz Register an Application linkinden bir uygulama oluşturmamız gerekiyor. Zorunlu olan alanları doldurduktan sonra Create Application diyerek uygulamayı oluşturuyoruz.
Ve bize bu uygulamayı kullanabilmek için bir token veriliyor.
İşte bize gerekli olan kullanıcı key'ini ve uygulama token'ini elde ettik. Bundan sonra Device Clients sayfasından uygulamayı telefonumuza indirip kullanıcı girişi yapıyoruz. Şimdi apiyi kullanabiliriz. Pushover için Python ile yazılı kütüphane mevcut. İlk önce onu kurmalıyız.
sudo pip install python-pushover
Pushover kullanabilmek için bu kütüphaneyi kullanmak zorunda değilsiniz. requests kütüphanesini kullanarak isteği kendiniz de yapabilirsiniz. Ama kullanımı daha basit olduğu için bu kütüphaneyi kullanacağız. Basit bir şekilde kullanımı şöyle:
from pushover import Client

client = Client("User Key", api_token="Api Token")
client.send_message("Test içeriği", title="Test Başlığı")
Eğer her şey yolunda ise bu programı çalıştırdığınızda telefonunuza bildirim gelmiş demektir. Eğer gelmedi ise adımları tekrar gözden geçiriniz. Daha ayrıntılı bilgiye https://pushover.net/api adresinden ulaşabilirsiniz.

Kaynakça

3 Eylül 2014 Çarşamba

Django 1.7 ve Migrations

Ve Django'nun 1.7 sürümü yayınlandı. Bu bizim için çok anlam ifade ediyor. Çünkü artık biz de Migration özelliğine sahibiz. Veritabanımızda oluşturmuş olduğumuz tablolara sütünlar ekleyebilir veya silebiliriz. Bildiğiniz gibi Django'nun 1.7'den önceki sürümünde bir tablo sadece bir kere oluşturuluyordu. Yani projeyi yaptıktan bir süre sonra tablo üzerinde değişiklik yapmanız demek tablo içerisindeki verileri kaybetmeniz demektir. Güncellenmiş halini yeniden oluşturmak için tabloyu silerek tekrardan oluşturmanız gerekiyordu. İşte bu sorun 1.7 ile birlikte gelen Migration ile ortadan kalktı.

20 Ağustos 2014 Çarşamba

PyQt Akıllı Diyaloglar

     Akıllı diyalogların akılsız diyaloglardan oluşturulma yönünde bir farkı yoktur. Sadece akılsız diyaloglara oranlara birtakım avantajları vardır. Bu avantajlar ise kullanılacak duruma göre dezavantaj da olabilir. Akıllı ve akılsız diyalogların farklılıklarına kısaca değinelim.

Akılsız diyaloglarda bir pencere açıldığında onay butonları veya çarpı işaretinden kapatılması sonucu sadece kullanıcıya görünmez olur; ama bellekte yer kaplar. Ve her yeni çağrılışında yeni bir pencere oluşturmaktadır. Bunu diyalog sonuna ekleyebileceğimiz del diyalog komutu ile çözebiliriz.
Ayrıca akılsız diyaloglar kendisini çağıran pencere ile etkileşim içinde değildir. Yani yapılan değişiklikler onaylanmadan görüntülenemez. Onaylandığında da kalıcı olarak değişiklik yapılmış olur. Bu durumda önceki duruma dönülemez.

İşte bu bahsettiğimiz durumları akıllı diyaloglar giderir. Akılsız diyaloglarda yapılan değişiklikler, kendisini çağıran pencerede gerçekleşmekte; fakat akıllı diyaloglarda yapılan değişiklikler diyaloğun kendisinde yapılır.
Diyalog kapatıldıktan sonra kendisini sildiğinden bellekte yer kaplama durumu da söz konusu değildir. Bunu da örneğimizde self.setAttribute(Qt.WA_DeleteOnClose) kodu ile sağlayacağız. Bu kodu akılsız diyaloglara koyamıyoruz; çünkü akılsız diyaloglar kendisini çağıran pencereye değişikliklere dair veri aktarmaktadır. Oysaki bu değişiklikler akıllı diyaloglarda kendi içinde halledilmiştir.

Şimdi bir metnin yazı tipini akıllı diyalog ile değiştirebileceğimiz bir örnek yapalım. Kodlarımız şu şekilde:
from PyQt4.QtCore import *
from PyQt4.QtGui import *

simgeler = 'D:/Simgeler/orange-moonlight-icons/png/64x64/'
# simgeler => http://dryicons.com/free-icons/preview/orange-moonlight-icons/

class yaziTipiDiyalogu(QDialog):
    def __init__(self, parent=None):
        super(yaziTipiDiyalogu, self).__init__(parent)
        self.parent = parent

        self.setAttribute(Qt.WA_DeleteOnClose)
        # Üst satırda yazmış olduğumuz kod pencere kapatılırken doğrudan silinmesini sağlar.
        # Böylelikle bellekte yer kaplamamış olur.

        self.yaziTipiListesi = QFontComboBox()
        self.yaziTipiListesi.setCurrentFont(QFont(self.parent.yaziTipi))

        butonKutusu = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        #Butonların üstündeki yazıları Tamam ve İptal olarak değiştirelim.
        butonKutusu.button(QDialogButtonBox.Ok).setText('Tamam')
        butonKutusu.button(QDialogButtonBox.Cancel).setText('İptal')
        self.connect(butonKutusu, SIGNAL('accepted()'), self.kabul)
        self.connect(butonKutusu, SIGNAL('rejected()'), self.reject)

        pencere = QGridLayout() # Izgara pencere düzeni
        pencere.addWidget(QLabel('Yazı Tipi Seçimi: '), 0, 0)
        pencere.addWidget(self.yaziTipiListesi, 0, 1)
        pencere.addWidget(butonKutusu, 1, 0, 1, 2)
        self.setLayout(pencere)

        self.setWindowTitle("Yazı Tipini Ayarla")
        self.setWindowIcon(QIcon(simgeler + 'edit.png'))

    def kabul(self):
        self.parent.yaziTipi = self.yaziTipiListesi.currentFont().family()
        self.parent.label.setText(self.parent.metin % self.parent.yaziTipi)
        QDialog.accept(self)

class akilliDiyaloglar(QDialog):
    def __init__(self, parent=None):
        super(akilliDiyaloglar, self).__init__(parent)
        self.yaziTipi = 'Comic Sans MS'
        self.metin = '
PythonDersleri.com
' self.label = QLabel(self.metin % self.yaziTipi) yatayKutu = QVBoxLayout() yatayKutu.addWidget(self.label) yaziTipiDugme = QPushButton('Yazı Tipini Değiştir') self.connect(yaziTipiDugme, SIGNAL('pressed()'), self.yaziTipiDegistir) yatayKutu.addWidget(yaziTipiDugme) self.setLayout(yatayKutu) self.setWindowTitle("Akıllı Diyaloglar") self.setWindowIcon(QIcon(simgeler + 'page.png')) def yaziTipiDegistir(self): diyalog = yaziTipiDiyalogu(self) diyalog.show() uygulama = QApplication([]) anaPencere = akilliDiyaloglar() anaPencere.show() uygulama.exec_()
Kodlarımızı çalıştırdığımızda karşımıza şöyle bir pencere gelecektir:
"Yazı Tipini Değiştir" butonuna tıkladığımızda ise pencere şu şekle gelecektir:
Buradaki kodlarımızda "Tamam" butonuna tıkladığımızda oluşan kabul durumunu kabul metodu ile bu diyalog içinde gerçekleştirdik. Bu sayede pencereyi kapattıktan sonra bellekten silebiliyoruz. İptal denildiğinde ise hiç bir değişiklik olmadan pencereyi kapatıp bellekten silebiliyoruz.

Akıllı diyaloglarla ilgili dikkatinizi çekmek istediğim bir nokta daha var. "Yazı Tipini Ayarla" penceremizi sürükleyip ana pencere üzerinden başka bir yere çektikten sonra ana pencere üzerinde "Yazı Tipini Değiştir" butonuna tekrar tıklamanıza yani ana pencere üzerinde işlem yapmanıza izin verir, bu durum akılsız diyaloglarda yoktur. Bu durum yapacağınız uygulamalara göre avantaj ya da dezavantaj oluşturabilir. Buna dikkat etmekte fayda var.

Akıllı diyaloglarda bir de kullanıcının yaptığı değişikliklerin kalıcı olmadığından bahsettik. Peki bu durum nasıl oluyor? Penceremize bazı uygulamalarda görmüş olabileceğiniz "Uygula" ve "Sıfırla" isminde iki buton daha eklememiz gerekiyor. Bu butonları da ekledikten sonra bütün butonları metotlara bağlamamız gerekiyor.
# Butonların eklenmiş hali
butonKutusu = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel | QDialogButtonBox.Apply | QDialogButtonBox.Reset)
butonKutusu.button(QDialogButtonBox.Apply).setText('Uygula')
# Butonun üzerindeki yazıyı "Uygula" yaptık
butonKutusu.button(QDialogButtonBox.Reset).setText('Sıfırla')
# Butonun üzerindeki yazıyı "Sıfırla" yaptık 


# Eklediğimiz butonların sinyallerini metotlara bağlıyoruz
self.connect(butonKutusu.button(QDialogButtonBox.Apply), SIGNAL('clicked()'), self.uygula)
self.connect(butonKutusu.button(QDialogButtonBox.Reset), SIGNAL('clicked()'), self.sifirla)


# Tüm butonlara ait metotların son hali de bu şekilde olmalı
def kabul(self):
        self.parent.yaziTipi = self.yaziTipiListesi.currentFont().family()
        self.parent.label.setText(self.parent.metin % self.parent.yaziTipi)
        QDialog.accept(self)

def uygula(self):
        self.parent.label.setText(self.parent.metin % self.yaziTipiListesi.currentFont().family())

def sifirla(self):
        self.parent.label.setText(self.parent.metin % self.parent.yaziTipi)
        self.yaziTipiListesi.setCurrentFont(QFont(self.parent.yaziTipi))

def reject(self):
        self.parent.label.setText(self.parent.metin % self.parent.yaziTipi)
        QDialog.reject(self)
Uygulamamıza yukarıdaki kodları da ekleyip çalıştırdığımızda bahsetmiş olduğumuz durumları gerçekleştirebilir hale gelmekteyiz. Pencerelere ait ekran görüntüsü de şu şekilde olacaktır:
Burada listeden yazı tipini seçtikten sonra Uygula diyerek kalıcı değişiklik yapmadan ve pencere kapanmadan yaptığımız değişiklikleri görebiliriz. Sıfırla diyerek de pencereyi açtığımızdaki ilk haline döndürebiliriz.


Kaynaklar:
http://zetcode.com/gui/pyqt4/dialogs/
Mustafa Başer - Python Kitabı

14 Ağustos 2014 Perşembe

PyQt Akılsız Diyaloglar

Akılsız diyaloglara neden akılsız diyalog denildiğinden çok bu diyalogların çalışma şekline değinelim. Akılsız diyaloglarda parçacıkların değerleri çağırıcı işlev tarafından ayarlanır ve yapılan değişiklikler de çağırıcı işlev tarafından yakalanır. Bu diyaloglar yalnızda parçacıkları ekranda görüntüleme işlevi görür. Ayrıca bu penceredeki işlem tamamlanmadan bu pencereyi çağıran ana pencerede başka bir işlem yapılamaz. Öncelikle açılan akılsız diyalog kapatılmalıdır.

Şimdi ana penceremiz üzerinde var olan bir label'ımızın içindeki yazının rengini bir alt pencere ile seçebileceğimiz bir örnek kod yazalım:
from PyQt4.QtGui import *
from PyQt4.QtCore import *

simgeler = 'D:/Simgeler/orange-moonlight-icons/png/64x64/'
# simgeler => http://dryicons.com/free-icons/preview/orange-moonlight-icons/

class yaziRengiDlg(QDialog):
    def __init__(self, parent=None):
        super(yaziRengiDlg, self).__init__(parent)
        izgara = QGridLayout()
        izgara.addWidget(QLabel('Yazı Rengi: '), 0, 0)
        self.yaziRengiListe = QComboBox()
        self.yaziRengiListe.addItems(('Red', 'Blue', 'Green', 'Yellow', 'Brown'))
        izgara.addWidget(self.yaziRengiListe, 0, 1)

        onayButonu = QPushButton('Tamam')
        redButonu = QPushButton('İptal')
        onayButonu.setDefault(True)

        butonKutusu = QHBoxLayout()
        butonKutusu.addWidget(onayButonu)
        butonKutusu.addWidget(redButonu)
        izgara.addLayout(butonKutusu, 1, 0, 1, 2)

        self.connect(onayButonu, SIGNAL('pressed()'), self.accept)
        self.connect(redButonu, SIGNAL('pressed()'), self.reject)

        self.setLayout(izgara)
        self.setWindowTitle('Yazı Rengini Seç')
        self.setWindowIcon(QIcon(simgeler + 'paint_brush.png'))

class akilsizDiyaloglar(QDialog):
    def __init__(self, parent=None):
        super(akilsizDiyaloglar, self).__init__(parent)
        self.yaziRengi = 'Blue'
        self.metin = 'PythonDersleri.com'
        self.label = QLabel(self.metin % self.yaziRengi)
        kutu = QVBoxLayout()
        kutu.addWidget(self.label)
        yaziRengiButonu = QPushButton('Yazı Rengini Değiştir')
        self.connect(yaziRengiButonu, SIGNAL('pressed()'), self.yaziRengiDegistir)
        kutu.addWidget(yaziRengiButonu)

        self.setLayout(kutu)
        self.setWindowTitle('Akılsız Diyaloglar')
        self.setWindowIcon(QIcon(simgeler + 'page.png'))

    def yaziRengiDegistir(self):
        diyalog = yaziRengiDlg()
        yaziRengiIndis = diyalog.yaziRengiListe.findText(self.yaziRengi)
        diyalog.yaziRengiListe.setCurrentIndex(yaziRengiIndis)
        if diyalog.exec_():
            self.yaziRengi = diyalog.yaziRengiListe.currentText()
            self.label.setText(self.metin % self.yaziRengi)

uygulama = QApplication([])
anaPencere = akilsizDiyaloglar()
anaPencere.show()
uygulama.exec_()
Bu programı çalıştırdığımızda ve "Yazı Rengini Değiştir" butonuna tıkladığımızda şu şekilde bir pencere gelecektir.

Burada da farklı olarak yazmış olduğumuz kodlardan bahsedelim.

4. Satır = Bu satırda simge dosyalarımın bulunduğu dizinin yolunu bir değişkene atadık. Programımızda kullandığımız simgeleri 5. satırda belirtmiş olduğumuz linkten ücretsiz temin edebilirsiniz.
30 ve 46. Satır = Bu satırlarda belirtilen QIcon nesneleri ile pencerelerin sol üst köşesinde görünen simgeleri belirledik.
51. Satır = Bu satır ile alt pencere açıldığında ana penceredeki yazının renginin seçili olarak alt pencerede gelmesini istedik.
18. Satır = Izgara pencerenin en altına yerleştirdiğimiz yatay buton kutumuzda "Tamam" butonunu ön tanımlı olarak belirledik. Bu tarz butonlar genellikle programların sağ alt köşesine yerleştirilir. Aynı hizanın sol tarafı boş kalmaktadır. Bunu sağlamak için 20. satırdan sonra butonKutusu.addStretch() kodunun eklenmesi yeterli olacaktır. Değişikliği farkedebilmek için pencerenin boyutunu artırmanız yeterli.
25 ve 26. Satır = Diyalog pencereleri kapatıldığında geri değer döndürürler. Bu değerler 0 ve 1'dir (accept ve reject). Biz buradan dönen 1 değerini "Tamam" butonuna atadık. Bunun anlamı o pencerede yapılan değişikliklerin uygulanacağı anlamına gelmektedir.


Kaynaklar:
-Mustafa Başer - Python Kitabı

10 Ağustos 2014 Pazar

PyQt Diyaloglar

      Şu ana kadar PyQt'ye ait temel elemanlardan bir kaçını kullanarak değişik uygulamalar yaptık. Ancak grafiksel arayüze sahip programlar bunlardan daha fazlasını içerir. Kullanıcılarla etkileşimi artırmak ve kullanıcıyı daha iyi yönlendirebilmek için Diyaloglar kullanılır. Peki nedir bu diyaloglar? Diyaloglar ana pencerenin üzerine açılan ve üzerinde Qt elemanları olan pencerelerdir. Yani bir başka deyişle alt pencerelerdir.
Örneğin ana pencereniz üzerinde bulunan bir yazının rengini veya yazı tipini seçmek için açılabilecek yeni bir pencere bir diyalogdur. Diyaloglar çeşitli gruplara ayrılmaktalar. Referans olarak aldığım bir kaynakta diyaloglar üç grupta incelenmiş ben de bu şekilde ele alıp ifade etmeye çalışacağım. Bu gruplar akıllı, akılsız ve canlı diyaloglar.

İlerleyen bölümlerde kullanacağımız simgeleri http://dryicons.com/free-icons/preview/orange-moonlight-icons/ adresinden ücretsiz temin edebilirsiniz. Ben bu simgeleri kullanacağım siz başka simgeleri de tercih edebilirsiniz.


8 Ağustos 2014 Cuma

PyQt Birbiriyle Bağımlı Parçacıklar

       Grafiksel kullanıcı arayüzüne sahip programlarda; kullanıcı tarafından fare tıklanması, klavyeden bir tuşa basılması gibi durumlar program tarafından dinlenilerek parçacıklarla ilgili tepkilerde belirli sinyaller için belirlediğimiz metotları çağırıyorduk. Biz bu oluşan sinyalleri bir başka parçacığa ait herhangi bir özellikle ilişkilendirebiliriz. Bu durumda ilk parçacıktaki değişim diğerinde de bir etki oluşturacaktır. Üstüne bir de ikinci parçacık için oluşacak bir sinyali de ilk parçacığın bir özelliğine bağlarsak, bu parçacıklar birbirlerini etkiler duruma gelecektir.

       Şöyle bir örnek ile açıklamaya devam edeyim. Örneğin ses seviyesini belirlediğimizi düşünelim. Seviye belirlediğimiz bir parçacıkla (QSlider) aynı seçimi sayıyla gösterir halde seçmemizi sağlayan bir döner kutu (QSpinBox) olabilir. Bu durumda ikisi de aynı değer üzerinde değişiklik yapmamızı sağlamaktadır. Bunun için bu parçacıkların birindeki değişim diğerini de değiştirmelidir.
       Bizim bu iki parçacığın aynı özelliklerini ortak bir değer için birbiriyle ilişkilendirebilmemiz için her iki parçacıkta da bu özelliklerin mevcut olması gerekir. Bizim burada QSlider ile QSpinBox parçacıklarını ilişkilendirmemizi sağlayan, ikisinin de valueChanged(int) sinyali ile setValue() metoduna sahip olmalarıdır. Parçacıklar ilişkilendirilirken bu duruma dikkat edilmelidir.

Yapacağımız örneğe şöyle bir görsellik daha katalım; biri yatay biri dikey iki tane QSlider ve bir tane QSpinBox kullanalım. Ve bu üç parçacıktan herhangi birinin valueChange(int) sinyalini diğerlerinin setValue() özelliklerine bağlayalım.
Kodlarımız şu şekilde:
# !/usr/bin/env python
# -*- coding: cp1254 -*-

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class BirbiriyleBagimliParcaciklar(QDialog):
    def __init__(self, parent=None):
        super(BirbiriyleBagimliParcaciklar, self).__init__(parent)

        yataySlider = QSlider()
        yataySlider.setRange(0, 10)
        yataySlider.setOrientation(Qt.Horizontal) #Slider'ın yatay olması için

        dikeySlider = QSlider()
        dikeySlider.setRange(0, 10)
        dikeySlider.setOrientation(Qt.Vertical) #Slider'ın dikey olması için

        dKutu = QSpinBox()
        dKutu.setRange(0, 10)

        self.connect(dikeySlider, SIGNAL('valueChanged(int)'), yataySlider.setValue)
        self.connect(yataySlider, SIGNAL('valueChanged(int)'), dKutu.setValue)
        self.connect(dKutu, SIGNAL('valueChanged(int)'), dikeySlider.setValue)
        
        grid = QGridLayout()
        grid.addWidget(dikeySlider, 0, 0, 2, 1)
        grid.addWidget(yataySlider, 0, 1)
        grid.addWidget(dKutu, 1, 1)


        self.setLayout(grid)
        self.setFixedSize(300, 150)
        self.setWindowTitle('PyQt QSlider & QSpinBox')

uygulama = QApplication([])
pencere = BirbiriyleBagimliParcaciklar()
pencere.show()
uygulama.exec_()

Programımızı çalıştırdığımızda karşımıza şu şekilde bir pencere gelecektir.
Burada parçacıklar üzerinde herhangi bir değişiklik yaptığımızda diğer parçacıkların değiştiğini de göreceksiniz. Şimdi de koddaki  bir kaç noktaya değinelim.
13-17. Satırlar = Bu iki satırda yorumda da belirttiğimiz gibi Slider'ımızın yatay konumda mı yoksa dikey konumda mı olması gerektiğini belirtiyoruz. Bu satırı yazmazsak varsayılan olarak dikey konumlandırılıyor.
22-23-24. Satırlar = Bu satırlarda üç parçacığa ait sinyaller birbirlerini etkileyecek şekilde birbirlerine bağlanmışlardır. Halka gibi düşünülebilir. Böylelikle bir tanesinde oluşan değer değişikliği sonucu o değer diğer parçacıklara gönderilmektedir.


Kaynaklar:
-Mustafa Başer - Python Kitabı

5 Ağustos 2014 Salı

PyQT Klavye Kısayolları ve QRadioButton

Kes, kopyala, yapıştır, kaydet gibi bazı işlemler için klavyedeki kısayolları kullanmak birçok kullanıcı için vazgeçilmezdir. Grafiksel arayüze sahip programlarda da genellikle fareyi kullanırız; ancak bazı kullanıcılar klavyeyi kullanmak isteyebilirler. Bu durumda programımızı klavyedeki tuşlar ile ilişkilendirmemiz gerekecektir.

Bir örnek ile bunu nasıl yapabileceğimize bakalım. Pencere üzerine bir yazı koyalım ve bu yazının rengini değiştirebileceğimiz seçenekler ekleyelim.  Aynı zamanda kullanıcı bu renk seçeneklerini klavyeden de seçebilsin.

Kodlarımız şu şekilde:
# !/usr/bin/env python
# -*- coding: cp1254 -*-

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class Klavye_Kisayollari(QDialog):
    def __init__(self, parent=None):
        super(Klavye_Kisayollari, self).__init__(parent)

        self.renk = 'blue'
        self.yazi = '''PythonDersleri.com'''

        self.metin = QLabel(self.yazi % self.renk)

        aciklamaLabeli = QLabel('Yazı rengi:')

        self.maviButon = QRadioButton('&Mavi')
        self.maviButon.setChecked(True)
        self.yesilButon = QRadioButton('&Yeşil')
        self.kirmiziButon = QRadioButton('&Kırmızı')

        self.butonGrubu = QButtonGroup()
        self.butonGrubu.addButton(self.maviButon)
        self.butonGrubu.addButton(self.kirmiziButon)
        self.butonGrubu.addButton(self.yesilButon)
        self.connect(self.butonGrubu, SIGNAL('buttonClicked(int)'), self.metniGuncelle)

        izgara = QGridLayout()
        izgara.addWidget(self.metin, 0, 1, 4, 1)
        izgara.addWidget(aciklamaLabeli, 0, 0)
        izgara.addWidget(self.maviButon, 1, 0)
        izgara.addWidget(self.yesilButon, 2, 0)
        izgara.addWidget(self.kirmiziButon, 3, 0)

        self.setLayout(izgara)
        self.setWindowTitle('PyQt Klavye Kısayolları')
        self.setFixedSize(300, 100)

    def metniGuncelle(self):
        if self.maviButon.isChecked():
            self.renk = 'blue'
        elif self.kirmiziButon.isChecked():
            self.renk = 'red'
        elif self.yesilButon.isChecked():
            self.renk = 'green'

        self.metin.setText(self.yazi % self.renk)

uygulama = QApplication([])
pencere = Klavye_Kisayollari()
pencere.show()
uygulama.exec_()
Bu kodu çalıştırdığımızda karşımıza şu şekilde bir pencere gelecektir.
Windows işletim sisteminde renklerin baş harflerinin altı çizili olması için çalıştıktan sonra ALT tuşuna basılması gerekiyor.

Şimdi biz burada renkler için klavye kısayolları atamış olduk. Bu kısa yollar Qt'de & işareti ile belirtiliyor. & işaretinden sonra gelen karakteri kısayol olarak atamış oluyoruz. Pencerede de kısayol olarak belirlenmiş olan karakter altı çizili olarak gösteriliyor. Örneğin uygulamamızda yazımızın rengini kırmızı yapmak için klavyeden ALT + K tuşlarına basmamız yeterlidir.

Parçacıklar içinde QRadioButton, QPushButton gibi kısayol olarak atayabileceğimiz bir metin geçmiyorsa ne yapacağımız düşünüyor olabilirsiniz. Bunun çözümü de çok basit. İçinde metin geçmeyen bu parçacıklar için kullanıcıya o parçacığın ne işlev gördüğünü belirtmek amacıyla genellikle bir QLabel kullanılmaktadır. Yapmak istediğimiz kısayolu o labelde belirtip, label ile de o parçacığı ilişkilendirmemiz gerekir. Bunu da labelIsmi.setBuddy(parcacikIsmi) şeklinde belirtmemiz yeterlidir.

Bu programda yeni görmüş olduğumuz bir de Radio Butonların gruplandırılması var. Bu butonları gruplandırmamızın sebebi, çoklu seçimi önleyip, sadece bir tanesinin seçili olmasını sağlamaktır. Eğer penceremizde başka fonksiyonlar için oluşturduğumuz başka radio butonlar yoksa gruplandırmaya gerek yoktur; ancak varsa birbirlerinden ayırt edilmeleri için gruplandırmamız gerekmektedir.

Not: Programınızda kısayolları belirlerken aynı karaktere birden fazla atama yapmamaya dikkat ediniz.


Kaynaklar:
-Mustafa Başer - Python Kitabı

1 Ağustos 2014 Cuma

PyQt QLineEdit Kullanımı

       Bu yazımızda sizlere QLineEdit yani kullanıcıdan veri almamızı sağlayan kutucuklardan bahsedeceğiz. Kullanıcıdan bu kutucuklar ile bilgilerini alıp, aldığımız bu verileri de bir dosyaya kaydedeceğimiz örnek bir uygulama yapalım. Bu sayede anlaşılması kolay olur hem de dosya işlemlerini kısaca bir tekrar etmiş oluruz.
       Izgara pencere düzeni kullanarak kullanıcıdan adını, soyadını, yaşını ve bölümünü alacağımız alanları belirtelim, aldığımız bu verileri dosyaya kaydetmek için bir de buton oluşturalım ve bunları penceremize yerleştirelim.
Hazırlamış olduğumuz örnek kodlarımız şu şekilde:
# !/usr/bin/env python
# -*- coding: cp1254 -*-
 
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class QLineEdit_Kullanimi(QDialog):
    def __init__(self, parent=None):
        super(QLineEdit_Kullanimi, self).__init__(parent)

        self.ad = QLabel('Ad:')
        self.soyad = QLabel('Soyad:')
        self.yas = QLabel('Yaş:')
        self.bolum = QLabel('Bölüm:')

        self.adi = QLineEdit()
        self.soyadi = QLineEdit()
        self.yasi = QLineEdit()
        self.yasi.setInputMask('99')
        self.bolumu = QLineEdit()
        
        self.kaydet = QPushButton('Kaydet')
        self.connect(self.kaydet, SIGNAL('pressed()'), self.dosyayaYaz)

        izgara = QGridLayout()
        izgara.addWidget(self.ad, 0, 0,)
        izgara.addWidget(self.soyad, 1, 0,)
        izgara.addWidget(self.yas, 2, 0,)
        izgara.addWidget(self.bolum, 3, 0,)
        
        izgara.addWidget(self.adi, 0, 1,)
        izgara.addWidget(self.soyadi, 1, 1,)
        izgara.addWidget(self.yasi, 2, 1,)
        izgara.addWidget(self.bolumu, 3, 1,)

        izgara.addWidget(self.kaydet, 4, 1,)

        self.setLayout(izgara)
        self.setWindowTitle('PyQt QLineEdit')
        

    def dosyayaYaz(self):
        dosya = open('Çıktı.txt', 'w')
        dosya.write(self.adi.text() + '\n' + self.soyadi.text() + '\n' + self.yasi.text() + '\n' + self.bolumu.text())
        dosya.close()        
        self.adi.setText('')
        self.soyadi.setText('')
        self.yasi.setText('')
        self.bolumu.setText('')

uygulama = QApplication([])
pencere = QLineEdit_Kullanimi()
pencere.show()
uygulama.exec_()

Bu programımızı çalıştırdığımızda şekildeki gibi bir ekran bizi karşılayacaktır.

Sonrasında bu formu doldurup "Kaydet" butonuna tıkladığımızda kodlarımızı yazdığımız dosya ile aynı dizinde "Çıktı.txt" isimli bir dosya oluşacaktır. Bu dosyayı açıp baktığımızda ise içeriği şöyledir:
Uygar
Köroğlu
22
Bilgisayar Mühendisliği

Şimdi yukarıdaki yazmış olduğumuz kodları kısaca açıklayalım. Burada da sadece farklı olarak yazdığımız kodları açıklayacağız.

11-12-13-14. Satırlar  = Bu satırlarda kutucukları anlamlandırmak için Label oluşturuyoruz.
16-17-18-20. Satırlar = Bu dört satırda kullanıcıdan veri almak için kutucuk oluşturuyoruz.
19. Satır = Bu satırda kişiye ait yaşı alırken kullanıcının gireceği veriye bir sınırlama getirdiğimizi belirtiyoruz. Buraya yazdığımız '9' sayısının kaç adet olduğu ile kaç karakter girilebileceğini ve bu sayının kendisi ise buraya [0, 9] aralığında bir rakamın girilebileceğini belirtmektedir. Yani bu şekilde kullanıcının yalnızca sayı girmesi ve bu sayının da maksimum iki basamaklı olabileceğini belirtmiş olduk.
22. Satır = Bu satırda da "Kaydet" butonumuzu oluşturduk.
23. Satır = Bu satırda da butona tıklandığında verileri dosyaya yazacak olan metodu çağırdık.
42. Satır = Buton tıklandığında çalışacak olan metodu tanımladık.
43. Satır = "Çıktı.txt" isminde bir dosyayı yazma modunda açıyoruz.
44. Satır = Kutucuklardan aldığımız verileri satır satır dosyaya yazıyoruz.
45. Satır = Dosyamızı kapatıyoruz.
46-47-48-49. Satırlar = Bu satırlarda dosyaya yazma işleminden sonra kutucukların içini temizliyoruz. Bir nevi kaydettiğimizin de farkına varabilmemiz için bunu yazdık.

       Yukarıda 19. satırda bahsetmiş olduğumuz setInputMask() metodu ile verebileceğimiz kısıtlamalar için kullanabileceğimiz parametrelerden bahsetmek istiyorum. Bu parametreler ile kullanıcının gireceği karakterlere belli kısıtlamalar getiriyoruz, bu kısıtlamalar sayesinde kullanıcıların geçersiz karakterler girmesinin önüne geçilebilir. Bu metot ile kullanabileceğimiz parametreler şu şekilde:

h       =>       Hexadecimal (onaltılık) karakterler için kullanılır, zorunluluk gerektirmez.
H      =>       Hexadecimal (onaltılık) karakterler için. a-f, A-F, 0-9
b       =>       Binary (ikilik) karakterler için kullanılır, zorunluluk gerektirmez.
B      =>       Binary (ikilik) karakterler için. 0-1
0       =>       ASCII sayılar için kullanılır, zorunluluk gerektirmez. 0-9
9       =>       ASCII sayılar için
d       =>       ASCII sayılar için kullanılır, zorunluluk gerektirmez. 1-9 (0 yok)
D      =>       ASCII sayılar için
#       =>       ASCII sayılar ve artı eksi işareti için kullanılır, zorunluluk gerektirmez.
a       =>       ASCII alfabe karakterleri için kullanılır, zorunluluk gerektirmez. a-z, A-Z
A      =>       ASCII alfabe karakterleri için
n       =>       ASCII sayısal karakterler için kullanılır, zorunluluk gerektirmez.
N      =>       ASCII alfabe karakterler için a-z, A-Z, 0-9
x       =>       Herhangi bir karakter olabilir, zorunluluk gerektirmez.
X      =>       Herhangi bir karakter olabilir
>      =>       Bu karakterden sonra gelecek olan bütün alfabe büyük harf olacak.
<      =>       Bu karakterden sonra gelecek olan bütün alfabe küçük harf olacak.
!       =>       Büyük-Küçük harf zorunluluğunu kapatır.


Kaynaklar:
-Mustafa Başer - Python Kitabı

29 Temmuz 2014 Salı

PyQt QSpinBox ve QComboBox

       Şimdiye kadar yaptığımız örneklerde sadece Buton(QPushButton) ve Label(QLabel) kullanmıştık. Bu yazımızda iki tane yeni parçacık daha göreceğiz ve bunların kullanımına bakacağız.  Bu parçacıklarımız döner kutu ve açılan bir liste olan QSpinBox ve QComboBox. QSpinBox sayısal değerleri kullanıcıdan hatasız bir şekilde almak için kullandığımız bir parçacık. QComboBox da kullanıcıya verdiğimiz bir liste üzerinden seçim yapmasını sağladığımız bir parçacıktır.

       Şimdi bu parçacıkları nasıl kullanacağımıza dair bir örnek verelim:

# !/usr/bin/env python
# -*- coding: cp1254 -*-
 
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class QSpinBox_QComboBox(QDialog):
    def __init__(self, parent=None):
        super(QSpinBox_QComboBox, self).__init__(parent)

        self.yil = 2014
        self.mevsim = 'kış'
        self.metin = ('
%d yılının %s mevsimi.
') self.label = QLabel(self.metin % (self.yil, self.mevsim)) self.dKutu = QSpinBox() self.dKutu.setRange(2000, 2050) self.dKutu.setValue(self.yil) self.connect(self.dKutu, SIGNAL('valueChanged(int)'), self.yilDegistir) self.aListe = QComboBox() self.mevsimler = ['sonbahar', 'kış', 'ilkbahar', 'yaz'] self.aListe.addItems(self.mevsimler) self.aListeMevsimIndisi = self.aListe.findText(self.mevsim) self.aListe.setCurrentIndex(self.aListeMevsimIndisi) self.connect(self.aListe, SIGNAL('currentIndexChanged(QString)'), self.mevsimDegistir) izgara = QGridLayout() izgara.addWidget(self.label, 0, 0, 1, 2) izgara.addWidget(self.dKutu, 1, 0,) izgara.addWidget(self.aListe, 1, 1) self.setLayout(izgara) self.setWindowTitle('PyQt QSpinBox ve QComboBox') self.setFixedSize(350, 100) def yilDegistir(self, sinyaldenGelenYil): self.yil = sinyaldenGelenYil self.label.setText(self.metin % (self.yil, self.mevsim)) def mevsimDegistir(self, sinyaldenGelenMevsim): self.mevsim = sinyaldenGelenMevsim self.label.setText(self.metin % (self.yil, self.mevsim)) uygulama = QApplication([]) pencere = QSpinBox_QComboBox() pencere.show() uygulama.exec_()

Bu kodu çalıştırdığımızda karşımıza şöyle bir pencere gelecektir:

Kodlarımıza baktığımızda daha önceki programlarımızdan farklı bir connect kullandığımızı görebilirsiniz. Bunun sebebi bazı QT parçacıklarının sinyal ile birlikte bir de değer göndermesidir. Bu değer sinyalde parametre olarak belirtilmektedir. Bağlantıda yayımlanan sinyal sonucu çalışmasını istediğimiz metotlara bu şekilde değerler gönderebiliriz. Burada yilDegisitir() ve mevsimDegistir() metotlarına int ve QString şeklinde sinyal argümanları gönderdik. Bu sinyal ile gönderdiğimiz int ve QString değerleri parçacıkların o anki değerlerini ifade etmektedir.
       Bu yeni görmüş olduğumuz parçacıkları satırları ile birlikçe açıklayacak olursak:
17. Satır = Bir tane QSpinBox nesnesi oluşturuyoruz.
18. Satır = setRange() metodu ile döner kutunun alt ve üst sınırlarını belirtiyoruz.
19. Satır = setValue() metodu ile program başladığı andaki değerini belirtiyoruz. (Eğer bu değer alt değerden küçükse alt değeri, üst değerden büyükse de üst değeri otomatik olarak yazılır).
20. Satır = Döner kutu üzerinde değer değiştiği anda oluşan sinyale yilDegistir() metodunu bağlıyoruz.

22. Satır = Bir tane QComboBox nesne oluşturuyoruz.
23. Satır = Açılır listenin elemanlarını belirleyebilmek için bir liste oluşturuyoruz
24. Satır = Oluşturduğumuz bu mevsimler isimli listeyi, açılır listenin elemanları olarak gönderiyoruz.
25. Satır = findText ile listedeki bir elemanın konumunu bulduk.
26. Satır = Listenin seçilmiş olan elemanını belirttik.
27. Satır = Açılır listede bir index değişikliği olduğunda mevsimDegistir() metodunun çalıştırılacağı bağlantıyı kuruduk.

Bu tür parçacıkların sinyallarinin ve özelliklerinin akılda tutulması zordur. Bunlar genelikle sürekli kullandıkça akılda kalmaktadır. Ancak unutulması veya öğrenilmesi istenildiğinde hafif bir İngilizce bilgisi ile şuradaki dökümana bakarak anlaşılabilir:
Başlat > Tüm Programlar > PQt GPL vX.X.X for Python vX.X > Documentation > PyQt Class Reference


Kaynaklar:
-Mustafa Başer - Python Kitabı
-PyQt Class Reference

26 Temmuz 2014 Cumartesi

Yönetim Paneli Özelleştirme

Bu yazı da kısaca yönetim panelini nasıl özelleştirebiliriz ona değineceğiz. Django yönetim panelinde ana şablon olarak admin/base.html'i kullanır. Ve bize de kendi yönetim şablonumuzu oluşturma imkanı verir. Bu yönetim şablonunu sablonlar/admin/base_site.html olarak arar. Yönetim panelinde varsayılan olarak header kısmında Django Yönetimi yazmaktadır. Şimdi basit bir şekilde bunu nasıl değiştirebileceğimizi görelim.
İlk önce şun söyleyelim oluşturacağımız base_site.html artık bizim yönetim şablonumuz olacak. Bunun içine sadece 'merhaba' yazarsanız yönetim panelinde de sadece 'merhaba' yazısını görürsünüz. Django'nun kendi yönetim panelinin devam edebilmesi için bizim kendi şablonundan kalıtım almamız gerekiyor.
{% extends "admin/base.html" %}
{% load i18n %}

{% block title %}{{ title }} | {% trans 'Başlık' %}{% endblock %}

{% block branding %}

{% trans 'Header Başlık' %}

{% endblock %} {% block nav-global %}{% endblock %}
Burada ilk önce extends ifadesi ile kalıtım aldık. Kalıtım alırken her şey olduğu gibi alınır. Ancak aynı block ifadeleri hem kalıtım alınan şablonda hem de kalıtımı alan şablonda var ise kalıtımı alan şablondaki gösterilir. Biz block branding ifadesini yeniden yazdığımız için bizim yazdığımı görünecektir.
Bu şekilde block ifadelerini kullanarak yönetim panelini özelleştirebilirsiniz. Django'nun yönetim şablonlarını buradan inceleyebilirsiniz.