C++ / Windows API ve C - (2)
Windows API ve C - (2)
|
 |
Yazar: by_Coder
Eklenme:
25/01/08
Okunma:
307 |
|
|
| |
| |
|
|
Pencereler!
Windows işletim sistemine adını veren "pencereler", aslında ekran üzerinde görülen dikdörtgen şekilli (dikdörtgen olmak zorunda değil tabii) ve üzerinde butonlar, menüler, yazılar olan, sağa sola kaydırılabilir objelerden çok daha fazlasını ifade ederler. Eğer grafik arabirimli bir program yazmak istiyorsanız (ki Windows altında çalışıyorsanız, muhtemelen istersiniz) pencereler kullanmak zorundasınız. Durun, daha bitmedi; pencerelerin üzerinde duran o butonlar, liste kutuları (listbox) ve rengarenk ağaç hiyeraşileri (tree view) de aslında birer pencere sayılıyor. Madem pencereler bu kadar önemli, gelin onları daha yakından tanıyalım.
Mesaj Kuyrukları ve Pencere Prosedürleri
Bildiğiniz gibi, canlı ve cansız varlıklara uyguladığınız etkiler sonucu size cevap olarak bazı tepkiler verirler. Pencereler de üzerine uyguladığınız sanal etkiler sonucu bazı sanal tepkiler verirler, örneğin "kapat" düğmesine tıklarsanız, o pencere kapanır. Bir pencere yarattığınız zaman, o pencerenin kullanıcıya karşı vereceği cevapları da hazırlamanız gerekir. İşte, pencerenin kullanıcıya vereceği cevapları hazırlayan bu fonksiyonlara "pencere prosedürleri" (window procedure) denir. Standart pencere prosedürünün alacağı parametreler, önceden şu şekilde tanımlanmıştır:
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
Burada görüyoruz ki pencere prosedürleri "geri çağrılan" (CALLBACK) fonksiyonlar olarak tanımlanıyor, CALLBACK anahtar kelimesi __stdcall fonksiyon çağırma usülünü devreye sokmaya yarıyor (fonksiyon çağırma usüllerine ileride, DLL yazarken değineceğiz). Pencere prosedürünün işleyişi şu şekilde oluyor; pencereye bir eylem uygulandığı zaman (tıklama, çift tıklama, dosya sürükleme...) Windows, o pencerenin mesaj kuyruğuna (pencereye gelen mesajların tümü) "şu şu oldu" diye bir mesaj bırakır, programınızın mesaj kuyruğu işleyeci de pencere prosedürünü kullanarak bu mesajı işler. Prosedüre geçilen parametreler:
HWND hWnd - Pencerenin tutamacı (window handle), UINT uMsg - Mesajın türü, standart pencere mesajlarının çoğu WM_ ile öneklenmiştir (örneğin WM_CLOSE), listesi için API dökümantasyonunuza başvurabilirsiniz, WPARAM wParam ve LPARAM lParam - Mesajın işlenmesi için gerekecek ek parametreler (mesela mouse tıklaması için X ve Y koordinatları)
Döndürülen değer ise LRESULT cinsinden, mesajın işlenip işlenmediğini belirtiyor (bütün mesajlar için işleyici yazmak imkansız gibidir çünkü binlerce var). İşlenmeyen mesajları Windows, DefWindowProc adlı kendi prosedüründe hallediyor, sizin tek yapmanız gereken o prosedürü size gelen parametrelerle çağırmak.
Örnek bir pencere prosedürü şöyle olabilir:
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg) //mesajın cinsine göre
{
case WM_LBUTTONDOWN: //sol mouse tuşu basıldı
//...sol mouse tıklanınca yapılacaklar
break;
case WM_CLOSE: //pencereyi kapat
PostQuitMessage(0); //mesaj kuyruğundan çık
break;
default: //bilinmeyen mesaj
return DefWindowProc(hWnd,uMsg,wParam,lParam); //Windows mesaj işleyeci
};
return 0; //mesaj işlenmiştir
};
Mesaj Kuyruğu İşleyeçleri
Programınızın ana fonksiyonunda (WinMain), pencereye mesajlar geldikçe onları prosedüre gönderip işleyecek bir döngü bulunması gerekir, buna da mesaj kuyruğu işleyeci denir. Basit bir işleyeç örneği:
HWND mWnd; //pencere tutamacı, pencereyi yarattığımızı varsayalım
MSG xMsg;
while(GetMessage(&xMsg,mWnd,0,0))
{
TranslateMessage(&xMsg);
DispatchMessage(&xMsg);
};
GetMessage fonksiyonu (ilk parametre mesaj bilgisini alacak MSG yapısının adresi, ikincisi pencere tutamacı, üç ve dört bazı mesajları filtrelemek için kullanılıyor), mesaj kuyruğundan sıradaki mesajı çekiyor ve xMsg yapısının içinde saklıyor. TranslateMessage, klavye mesajlarındaki sanal tuşları karakterlere çeviriyor. DispatchMessage ise mesajı işlenmesi için pencere prosedürüne gönderiyor.
Pencereyi Yaratmak
Artık pencereyi destekleyecek altyapıyı hazırlamayı öğrendik, penceremizi yaratmaya hazırız demektir. Pencere yaratmak için kullanacağımız iki fonksiyon var: *Önce RegisterClass fonksiyonu ile penceremizin "cinsini" tanımlayacağız *Sonra CreateWindow ile tanımladığımız cinsten bir pencere oluşturacağız Bu fonksiyonlara şöyle bir bakalım:
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
Belirtilen WNDCLASS yapısındaki özelliklere göre pencere cinsini tanımlar ve bu cinse özgü bir ATOM numarası döndürür. WNDCLASS yapısının tanımı şöyledir:
typedef struct _WNDCLASS {
UINT style; //pencere stili, ekranı kapla tuşu, simge durumuna
küçült tuşu...
WNDPROC lpfnWndProc; //pencere prosedürü adresi
int cbClsExtra; //cins için ayrılacak ekstra bayt, genellikle 0
int cbWndExtra; //pencere için ayrılacak ekstra bayt, genellike 0
HANDLE hInstance; //pencereyi yaratan programın tutamacı (instance handle)
HICON hIcon; //pencere ikonu
HCURSOR hCursor; //pencere fare işaretçisi
HBRUSH hbrBackground; //arkaplan rengi
LPCTSTR lpszMenuName; //menü kaynağı
LPCTSTR lpszClassName; //bu pencere cinsini tanımlayan özel bir isim
} WNDCLASS;
HWND CreateWindow(
LPCTSTR lpClassName, //pencere cinsinin özel ismi
LPCTSTR lpWindowName, // pencere başlığı
DWORD dwStyle, //pencere başlangıç stili
int x, //yatay konum
int y, //dikey konum
int nWidth, //genişlik
int nHeight, //yükseklik
HWND hWndParent, //ebeveyn pencerenin tutamacı (eğer varsa)
HMENU hMenu, //menü tutamacı
HANDLE hInstance, //pencereyi yaratan programın tutamacı
LPVOID lpParam //ekstra pencere yaratım bilgisi
);
CreateWindow da belirttiğiniz parametrelere göre bir pencere oluşturur ve tutamacını döndürür (veya bir hata oluşursa, NULL döndürür).
Hokus, Pokus, Pencere!
Artık basit bir pencere oluşturmak ve ekranda göstermek için gerekli bütün bilgilere sahibiz. Kod yazma zamanıdır :).
#include <windows.h>
char szPencCins[]="BenimPencerem";
LRESULT CALLBACK PenPros(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
//pencere prosedürü
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmd,int nShowCmd)
{
WNDCLASS x; //pencere tanım bilgileri
x.style=CS_HREDRAW|CS_VREDRAW; //yatay ve dikey boyut değişirse tekrar çiz
x.lpfnWndProc=PenPros; //pencere prosedürü
x.cbClsExtra=0;
x.cbWndExtra=0;
x.hInstance=hInst;
x.hIcon=LoadIcon(NULL,IDI_APPLICATION); //standart windows ikonu
x.hCursor=LoadCursor(NULL,IDC_ARROW); //standart fare işaretçisi
x.hbrBackground=(HBRUSH)COLOR_WINDOW; //pencere rengi kullan
x.lpszMenuName=NULL; //menü yok
x.lpszClassName=szPencCins; //pencere cins
if(!RegisterClass(&x))
{
MessageBox(NULL,"Pencere sınıfı yaratılamadı!","Hata",MB_ICONSTOP);
return 0;
};
//pencereyi yarat
HWND hWnd=CreateWindow(szPencCins,"İlk Pencerem",WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,300,
300,NULL,NULL,hInst,NULL);
if(!hWnd)
{
MessageBox(NULL,"Pencere yaratılamadı","Hata",MB_ICONSTOP);
return 0;
};
ShowWindow(hWnd,nShowCmd); //pencereyi ekranda göster
MSG t; //mesaj verisi için değişken
while(GetMessage(&t,hWnd,0,0)) //mesaj kuyruğu doluysa mesaj al
{
TranslateMessage(&t); //klavye mesajlarını çevir
DispatchMessage(&t); //pencere prosedürüne gönder
};
return 0;
};
LRESULT CALLBACK PenPros(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg) //mesaj cinsine göre
{
case WM_LBUTTONDOWN:
MessageBox(hWnd,"Sol tuşu tıkladınız!","Mesaj",MB_OK);
break;
case WM_RBUTTONDOWN:
MessageBox(hWnd,"Sağ tuşu tıkladınız!","Mesaj",MB_OK);
break;
case WM_CLOSE:
PostQuitMessage(0); //programdan çık
(GetMessage'a 0 gönder)
break;
default:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
};
return 0;
};
Kodu düzgünce yazıp (kopyala-yapıştır ile öğrenmezsiniz, kendiniz yazmaya çalışın) çalıştırdığınız zaman ekranda ilk pencereniz görünecektir. Üstelik sağ ve sol tuşu tıkladığınızda hoş bir mesajla size cevap verecektir. Bu yazdığımız kod, hemen hemen bütün Windows programlarında kullanılan cinsten, o yüzden bir yerlere kaydedip ilerideki programlarınızda şablon olarak kullanabilirsiniz. Bir sonraki makalemizde, penceremizin üzerine diğer pencereler yerleştireceğiz, butonlar ve liste kutuları gibi daha "kullanışlı" pencereler. O zamana kadar pencere şablonuyla biraz oynmayı deneyin, mesela WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK gibi mesajlara karşılık yazın, veya fonksiyonlar yazıp bunları mesajlara cevap olarak çağırın.
|
| |
|