Bu yazımızda, daha
önce incelemiş olduğumuz düğme kontrollerini kullandığımız bir uygulama geliştireceğiz.
Uygulamamız, kullanıcıdan öğrencilerin isim ve cinsiyet bilgilerini alacak.
Bu bilgilerin yanısıra öğrencinin belli kurslardan hangilerini aldığını, hangilerini
almadığı bilgisini de alacak. Kullanıcıdan aldığı bu bilgileri bir dosyaya kaydedecek.
Windows API yazı dizimizde daha önce statik kontrolleri ve
yazı kutusu kontrollerini incelemiştik. Bu uygulamamızda o kontrollerden de
yararlanacağız. Ana penceremizde dört statik kontrol ve iki yazı kutusu kontrolümüz
olacak. Bunun yanısıra, bir basma düğmesi, iki seçenek düğmesi, üç seçenek kutusu
ve bir de grup kutusu oluşturarak düğme kontrollerinin uygulama içerisinde nasıl
kullanıldığını göreceğiz.
Öğrenci bilgilerini
uygulamanın ana penceresindeki kontrollerden kolay bir biçimde alabilmek için
bir yapı tanımlayalım. Böylece, kullanıcı kaydı yapmak üzere düğmeye bastığında,
kontrollerdeki bilgileri tanımladığımız yapı türünden bir nesnenin veri elemanlarına
atayarak bilgileri dosyaya bu yapı nesnesi aracılığıyla yazabiliriz. Yapımızı,
uygulamamızın başlık dosyasında şöyle tanımlayalım :
typedef struct
_person {
    char name[20];
    char surname[20];
    char maleorfemale;
    int lesson1;
    int lesson2;
    int lesson3;
}Person; |
Ana penceremizde
tüm bu veri elemanlarına atayacağımız değerleri tutan kontrollerimiz olacak.
Ana penceremizi oluşturma kısmını, daha önceki yazılarımızda ele aldığımız için
burada tekrar incelemeyeceğiz. Kaynak kod dosyamızın başında, kontrolleri oluştururken
CreateWindow fonksiyonunun hMenu parametresi yerine geçtiğimiz tanımlayıcı değerleri
sembolik sabitler olarak tanımlayalım :
#define ID_EDITBOX_1
101
#define ID_EDITBOX_2 102
#define ID_LABEL_1 103
#define ID_LABEL_2 104
#define ID_LABEL_3 105
#define ID_LABEL_4 106
#define ID_RD_BTN_1 107
#define ID_RD_BTN_2 108
#define ID_CKB_BTN_1 109
#define ID_CKB_BTN_2 110
#define ID_CKB_BTN_3 111
#define ID_PSH_BTN_1 112
#define ID_GRP_BTN_1 113 |
CreateWindow fonksiyonunun
geri döndürdüğü kontrol tutamaç değerlerini tutmak için uygulamanın global alanında
HWN türünden nesneler tanımlayalım :
static HWND
hEditBox1, hEditBox2;
static HWND hStatic, hGroupBox;
static HWND hRadioButton1, hRadioButton2;
static HWND hCheckBox1, hCheckBox2, hCheckBox3;
static HWND hPushButton; |
Kullanıcı kaydın
yapılması için basma düğmesine bastığında çağrılacak fonksiyonun prototip bildirimini
de global alanda yapalım :
Uygulamamızın WndProc
pencere fonksiyonunda, WM_CREATE mesajı alındığında (yani ana penceremiz oluştuğunda)
kontrollerimizi oluşturacağız. Kontroller, belli olaylar oluştuğunda ana pencereye,
kendi tanımlayıcı değerlerini ve oluşan olayı belirten bir kod değerini içeren
WM_COMMAND mesajı iletirler. Ana pencerenin pencere fonksiyonunda WM_COMMAND
mesajı alınması durumunda, bu mesajı gönderen kontrolün tanımlayıcı değerini
kontrol ederek mesajın basma düğmesi tarafından gönderilip gönderilmediğini
anlayabiliriz. Eğer mesaj basma düğmesinden geliyorsa ve gönderilme nedeni de
düğmeye tıklanmış olmasıysa bu durumda prototip bildirimini yapmış olduğumuz
OnPshButtonClick fonksiyonunu çağırmalıyız. Tüm bu işlemleri yaptığımız pencere
fonksiyonumuz şu şekildedir :
LRESULT CALLBACK
WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    switch(message) {
       case WM_COMMAND :
          if (LOWORD(wParam) == ID_PSH_BTN_1
&& HIWORD(wParam) == BN_CLICKED)
              OnPshButtonClick();
          break;
       case WM_CREATE
:
          hStatic = CreateWindow("static","İsim :",
WS_CHILD | WS_VISIBLE,
                                           10,50,75,20,hWnd,(HMENU)ID_LABEL_1,
                                           ((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
hEditBox1 = CreateWindow("edit","", WS_CHILD | WS_VISIBLE
| ES_LEFT,
                                              
100,50,200,20,hWnd,(HMENU)ID_EDITBOX_1,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
       ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
         
hStatic = CreateWindow("static","Soyisim :", WS_CHILD
| WS_VISIBLE,
                                          
10,90,75,20,hWnd,(HMENU)ID_LABEL_2,
                                          
((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
hEditBox2 = CreateWindow("edit","", WS_CHILD | WS_VISIBLE
| ES_LEFT,
                                              
100,90,200,20,hWnd,(HMENU)ID_EDITBOX_2,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
      
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
         
hStatic = CreateWindow("static","Cinsiyet :", WS_CHILD
| WS_VISIBLE,
                                              
10,130,75,20,hWnd,(HMENU)ID_LABEL_3,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
hGroupBox = CreateWindow("button","", WS_CHILD | WS_VISIBLE
| BS_GROUPBOX,
                                              
90,110,200,50,hWnd,(HMENU)ID_GRP_BTN_1,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
hRadioButton1 = CreateWindow("button","Bayan", WS_CHILD
| WS_VISIBLE | BS_AUTORADIOBUTTON,
                                              
100,130,75,20,hWnd,(HMENU)ID_RD_BTN_1,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
SendMessage(hRadioButton1,BM_SETCHECK,TRUE,0);
         
hRadioButton2 = CreateWindow("button","Erkek",
                                              
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
                                              
200,130,75,20,hWnd,(HMENU)ID_RD_BTN_2,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
      
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
         
hStatic = CreateWindow("static","Dersler :",
WS_CHILD | WS_VISIBLE,
                                              
10,170,75,20,hWnd,(HMENU)ID_LABEL_4,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
hCheckBox1 = CreateWindow("button","1. Kurs", WS_CHILD
| WS_VISIBLE | BS_AUTO3STATE,
                                              
100,170,100,20,hWnd,(HMENU)ID_CKB_BTN_1,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
hCheckBox2 = CreateWindow("button","2. Kurs",
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
                                              
100,200,100,20,hWnd,(HMENU)ID_CKB_BTN_2,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
hCheckBox3 = CreateWindow("button","3. Kurs",
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
                                              
100,230,100,20,hWnd,(HMENU)ID_CKB_BTN_3,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
      
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
         
hPushButton = CreateWindow("button","Kaydet",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                              
150,270,100,20,hWnd,(HMENU)ID_PSH_BTN_1,
                                              
((LPCREATESTRUCT)lParam)->hInstance,NULL);
         
break;
      
case WM_DESTROY :
          PostQuitMessage(0);
          break;
       default :
          return DefWindowProc(hWnd,message,wParam,lParam);
    }
    return 0;
}
|
Şimdi pencere fonksiyonumuzu
adım adım inceleyelim :
Pencere fonksiyonunda
WM_COMMAND mesajının alınması durumunda, mesajın basma düğmesi kontrolü tarafından
gönderilip gönderilmediğini, eğer basma düğmesi kontrolü tarafından gönderilmişse
kullanıcının düğmeye basmış olması nedeniyle mi gönderildiğini kontrol ediyoruz.
WM_COMMAND mesajının wParam parametresinin düşük anlamlı WORD değeri, mesajı
ileten kontrolün tanımlayıcı değerini içerir. Yüksek anlamlı WORD değeri ise
mesajın gönderilme nedenine ilişkin bir değer belirtir. LOWORD ve HIWORD makroları
kullanılarak wParam parametresinin düşük ve yüksek anlamlı WORD değerleri elde
edilebilir. Eğer LOWORD(wParam) değeri ID_PSH_BTN_1 değerine eşitse, mesaj basma
düğmesi kontrolümüz tarafından gönderilmiştir. Eğer HIWORD(wParam) değeri BN_CLICKED
değerine eşitse kulanıcı düğmeye basmıştır ve mesaj da bu nedenle iletilmiştir.
Hatırlayacağınız üzere düğme kontrolleri, basılma sırasında ana pencereye BN_CLICKED
mesajı iletiyorlardı. Bu koşulların sağlanması durumunda OnPshButtonClick isimli
fonksiyonumuzu çağırıyoruz. Bu fonksiyonda, alınan bilgileri bir dosyaya kaydedeceğiz.
Pencere fonksiyonunda
WM_CREATE mesajının alınması durumunda, kullanıcıdan bilgileri almak üzere kullanacağımız
standart kontrollerimizi oluşturacağız. Öncelikle isim bilgisini almak için
bir statik konrol ve hemen yanında bir yazı kutusu kontrolü oluşturduk. Hemen
ardından soyadı bilgisini almak için bir statik kontrol ve hemen yanında bir
yazı kutusu kontrolü daha oluşturduk. Şimdi cinsiyet bilgisini almak için bir
’Cinsiyet’ başlıklı statik kontrol oluşturuyoruz. Bu statik kontrolün yanında,
birisi ’Bayan’ birisi ’Erkek’ başlıklarına sahip iki seçenek düğmesi oluşturuyoruz.
Seçenek düğmelerini ’button’ pencere sınıf ismini kullanarak oluşturduk. Seçenek
düğmesi oluşturduğumuzu belirtmek için de, pencere biçimi parametresinde BS_AUTORADIOBUTTON
veya BS_RADIOBUTTON sembolik sabirlerinden birini belirtmemiz gereklidir. Kullanıcının
bu düğmelere basması durumunda yapılması gereken değişiklikleri sisteme bırakmak
için BS_AUTORADIOBUTTON sembolik sabitini kullanıyoruz. Seçenek düğmelerini
bir grup kutusu içerisinde göstermek için bu adımda bir de grup kutusu kontrolü
oluşturduk. Bu kontrol için de ’button’ pencere sınıf ismini kullandık, pencere
biçimi parametresinde grup kutusu kontrolü oluşturmak istediimizi belirtmek
amacıyla BS_GROUPBOX sembolik sabitini belirttik. Bu kontrole de bir başlık
yazısı belirtmemiz mümkündür, bu uygulama için başlık parametresini boş geçtik.
Şimdi seçenek düğmelerimiz bir grup kutusu içerisinde görüntülenecek.
Öğrencinin aldığı
kursların işaretlenmesi için bu adımda üç tane seçenek kutusu kontrolü oluşturduk.
Seçenek kutusu kontrolü de ’button’ pencere sınıf ismi kullanılarak oluşturulur.
Pencere biçimi parametresinde ise BS_AUTOCHECKBOX, BS_CHECKBOX, BS_3STATE veya
BS_AUTO3STATE sembolik sabiti belirtilir. Yine işaretlenme işlemlerini sisteme
bırakmak üzere BS_AUTOCHECKBOX sembolik sabitini kullanmayı tercih ettik. Sadece
ilk seçenek kutusunu oluştururken BS_AUTO3STATE sembolik sabitini kullanarak
diğerleri ile arasındaki farkı inceleyelim.
Son olarak bir
de basma düğmesi oluşturalım. Bu düğme kayıt bilgilerinin tamamen girildiğini
ve artık kaydın yapılabileceğini belirtmek amacıyla kullanılacak. Basma düğmeleri
oluştururken de ’button’ pencere sınıf ismi kullanılır. Pencere biçimi parametresinde
ise BS_PUSHBUTTON veya BS_DEFPUSHBUTTON sembolik sabitleri belirtilir. Kullanıcının
bu basma düğmesine basması durumunda OnPshBtnClick fonksiyonumuz çağrılacak.
Ekrandaki bilgileri alarak Person türünden bir yapı nesnesinin veri elemanlarına
yazan ve sonra bu yapı nesnesinin veri elemanlarının değerini bir dosyaya aktaran
SavePersonRecord isimli bir fonksiyon daha yazıyoruz. OnPshBtnClick fonksiyonunda,
yazmış olduğumuz bu fonksiyonu çağırıyoruz. OnPshBtnClick fonksiyonumuz şöyle
olacak :
void OnPshButtonClick()
{
    SavePersonRecord();
} |
Şimdi SavePersonRecord
fonksiyonumuza bakalım :
BOOL SavePersonRecord()
{
    LRESULT checked, les1, les2, les3;
    Person person;
    FILE *fp;
   
if (ControlForm() == FALSE) {
        MessageBox(NULL,"İsim veya soyisim
bilgisi eksik","Hata",MB_OK);
        return FALSE;
    }
   
GetWindowText(hEditBox1,&person.name,20);
    GetWindowText(hEditBox2,&person.surname,20);
    checked = SendMessage(hRadioButton1,BM_GETCHECK,0,0);
    person.maleorfemale = checked == TRUE ? ’F’ : ’M’;
    les1 = SendMessage(hCheckBox1,BM_GETCHECK,0,0);
    person.lesson1 = les1 == TRUE ? 1 : 0;
    les2 = SendMessage(hCheckBox2,BM_GETCHECK,0,0);
    person.lesson2 = les2 == TRUE ? 1 : 0;
    les3 = SendMessage(hCheckBox3,BM_GETCHECK,0,0);
    person.lesson3 = les3 == TRUE ? 1 : 0;
   
fp = fopen("person.txt","a");
    if (fp == NULL)
        return FALSE;
    fprintf(fp,"%-20s %-20s %c %d %d %d",person.name,person.surname,person.maleorfemale,
    person.lesson1,person.lesson2,person.lesson3);
    fputc(’\n’,fp);
    fclose(fp);
   
MessageBox(NULL,"Kayıt Yapıldı","Bilgi",MB_OK);
    ClearForm();
    return TRUE;
}
|
SavePersonRecord
fonksiyonu, BOOL
türden bir değer döndürüyor. Kaydın başarıyla yapılması durumunda TRUE değerini,
başarısızlık durumunda ise FALSE değerini döndürecek. Bu fonksiyon içerisinde
ControlForm ve ClearForm isimli iki fonksiyon daha çağırdık. Bu fonksiyonlar
sırasıyla, girilen bilgilerin tam olup olmadığını kontrol ediyor ve kayıt başarıyla
tamamlandıktan sonra ana penceredeki kontrollerin değerlerini sıfırlayarak formu
yeni bir kayıt için hazılıyor. ControlForm fonksiyonu kişiye ait isim ve soyisim
bilgilerinin girilip girilmediğini kontrol ediyor. Eğer bu fonksiyondan FALSE
değeri dönerse MessageBox API fonksiyonu ile kullanıcıya bir hata mesajı iletiliyor.
Eğer bu fonksiyondan TRUE değeri dönerse kayda devam ediliyor. Fonksiyonumuzun
başında Person türünden bir yapı nesnesi tanımladık. Kullanıcının girdiği değerleri
bu nesnenin veri elemanlarına aktaracağız. Sırasıyla isim ve soyisim alanlarına
girilen değerler GetWindowText API fonksiyonu ile Person türünden yapı nesnemizin
name ve surname isimli veri elemanlarına aktarılıyor. Ardından cinsiyet bilgisinin
öğrenilmesi için seçenek düğmelerinin işaretlenme durumları inceleniyor. İlk
seçenek düğmesine SendMessage API fonksiyonu ile BM_GETCHECK mesajı iletiliyor.
SendMessage fonksiyonu bu mesajın iletilmesiyle bize kontrolün işaretli olup
olmadığını belirten bir değer döndürecek. Kontrol işaretlenmişse 1 değeri, işaretlenmemişse
0 değeri döndürülür. Alınan bu bilgi kontrol edilerek, nesnenin maleorfemale
veri elemanına ’f’ veya ’m’ değeri atanıyor. Burada her iki seçenek düğmesinin
işaret durumunun da kontrol edilmesine gerek yoktur. Çünkü aynı anda bu seçenek
düğmelerinden sadece birisi işaretli olabilir. Öğrencinin hangi kursları aldığını
seçmek için oluşturduğumuz seçenek kutularının işaret durumları da kontrollere
BM_GETCHECK mesajı gönderilerek öğreniliyor. Eğer fonksiyondan 1 değeri dönerse
yapı nesnemizin ilgili veri elemanına 1 değerini, aksi takdirde 0 değerini atıyoruz.
Tüm bilgileri yapı nesnemize aktardıktan sonra şimdi dosyaya yazma işlemine
geçebiliriz. Bu amaçla (FILE *) türünden fpisimli nesnemize fopen fonksiyonu
ile vir tutamaç değeri atıyoruz ve dosyamızı sona ekleme modunda açıyoruz. fopen
çağrısından snra fp nesnemizin değeri NULL olursa dosya açma işlemi başarısız
olmuş demektir. Eğer bu durum gerçeklenirse fonksiyondan FALSE değeri ile dönüyoruz.
Dosya başarıyla açılmışsa nesnedeki değerleri formatlı bir şekilde dosyaya yazıyoruz.
Yazma işlemi tamamlandıktan sonra kullanıcıya MessageBox API fonksiyonu ile
bilgi veriyoruz. Sonra formu temizlemek için ClearForm fonksiyonunu çağırıyoruz
ve TRUE değeri ile fonksiyondan dönüyoruz.
Son olarak ControlForm
ve ClearForm isimli fonksiyonlarımızı da inceleyelim :
BOOL ControlForm()
{
    char name [20], surname [20];
    GetWindowText(hEditBox1,name,20);
    GetWindowText(hEditBox2,surname,20);
   
if (strcmp(name,"") == 0 || strcmp(surname,"") ==
0)
        return FALSE;
    return TRUE;
}
BOOL ClearForm()
{
    SetWindowText(hEditBox1,"");
    SetWindowText(hEditBox2,"");
    SendMessage(hRadioButton1,BM_SETCHECK,TRUE,0);
    SendMessage(hRadioButton2,BM_SETCHECK,FALSE,0);
    SendMessage(hCheckBox1,BM_SETCHECK,FALSE,0);
    SendMessage(hCheckBox2,BM_SETCHECK,FALSE,0);
    SendMessage(hCheckBox3,BM_SETCHECK,FALSE,0);
}
|
ControlForm fonksiyonunda,
isim ve soyisim alanlarına girilen değerleri kontrol ederek, bu değerleri standart
strcmp fonksiyonunu kullanarak boş bir karakter katarı ile karşılaştırıyoruz.
Eğer isim veya soyisim alanlarından birisi boş bırakılmışsa fonksiyon FALSE
değeri ile, her iki alan da doldurulmuşsa TRUE değeri ile fonksiyondan dönüyoruz.
ClearForm fonksiyonunda ise, isim ve soyisim alanlarını SetWindowText API fonksiyonunu
boş bir karakter katarı parametresiyle çağırarak temizliyoruz. Seçenek düğmelerini
ilk haline getirmek için, kontrollere SendMessage API fonksiyonu ile BM_SETCHECK
mesajı gönderiyoruz. wParam parametresi olarak, ilk seçenek düğmesi için kontrolün
işaretli olmasını sağlamak amacıyla TRUE değerini; ikinci seçenek düğmesi için
kontrolün seçili olmamasını sağlamak amacıyla FALSE değerini kullanıyoruz. Seçenek
kutularının başlangıçta işaretli olmamalarını sağlamak için üç kontrole de SendMessage
API fonksiyonu ile BM_SETCHECK mesajı iletiyoruz ve wParam parametresi olarak
FALSE değerini geçiyoruz. Şimdi ana penceremiz yeni bir kayda hazır durumdadır.
Uygulamamızın çalışır
haldeki görünümü şu şekilde olacaktır :
İsim veya soyisim
alanlarından herhangi birisinin boş bırakılması durumunda karşılaşacağımız mesaj
:
Kaydın başarıyla
tamamlanması durumunda karşılaşacağımız mesaj ise :
şeklinde olacaktır.
Bu uygulamamızda düğme kontrollerinin nasıl oluşturulduğunu, nasıl kullanıldığını,
düğme kontrollerine gönderilen mesajları ve kontrolden gelen mesajların işlenmesini
inceledik. Oluşturduğumuz uygulamada daha önce incelemiş olduğumuz standart
kontrollerden de oluşturarak bu kontroller hakkındaki bilgilerimizi tazeledik.
Uygulaya ait kaynak kod dosyalarını buradan
indirebilirsiniz. (Uygulama Microsoft .NET 2003’te hazırlanmıştır.) Yeni bir
yazımızda daha görüşmek üzere herkese mutlu günler dilerim.
Makale:
Windows API - Düğme Kontrolleri Uygulaması C ve Sistem Programlama Çiğdem Çavdaroğlu
|