C++ / Windows API ve C - (4)
Windows API ve C - (4)
|
 |
Yazar: by_Coder
Eklenme:
25/01/08
Okunma:
224 |
|
|
| |
| |
|
|
Ortak Diyalog Kütüphanesi
Windows isletim sistemi altinda programcilarin isini kolaylastirmak amaciyla belirli kurallar çerçevesinde pek çok sablon olusturulmustur. Bu sablonlar, çogu kez ilgili oldugu konunun ismine "common" (ortak) kelimesinin getirilmesiyle yapilir (örnegin "common controls" ve bu bölümde inceleyecegimiz "common dialog box library" yani "ortak diyalog kutusu kütüphanesi) ve Windows altinda farkli programlarda çalisirken benzer islemler yaparsaniz benzer arabirimlerle karsilasirsiniz (yani Not Defteri ya da Paint farketmez, Aç veya Ctrl+O dediginiz zaman Dosya Aç diyaloguyla karsilasirsiniz). Bu arabirimler birbirine benzer çünkü hemen hepsi ayni sablondan yaratilirlar. Bu makalemizde, Windows'un programcilara sundugu Ortak Diyalog Kütüphanesi'ni inceleyecegiz.
Diyalog? Ortak Diyalog
Diyalog kelimesi, karsilikli konusma anlaminda kullanilir ve programlamada kullanacagimiz diyaloglar da bu tanima uyarlar. Belirli bir islemi yerine getirirken ortaya çikan ve islemin gerçeklestirilmesi için kullanicidan bilgi girisi almaya yarayan geçici pencerelere diyalog ya da diyalog kutusu denir. Sonraki bölümlerde örneklerle görecegimiz gibi kendi diyaloglarinizi tasarlamak mümkündür, ama adindan da anlasilabilecegi gibi ekstra bir islem ister: tasarim. Bir de sunu düsünün: harddiskten dosya açma yetenegine sahip olmasi gereken her program için ayri bir "dosya aç" diyalogu yazacaksiniz...kulaga pek hos gelmiyor. Bu yüzden, Windows'un merhametli ve düsünceli (!) yaraticilari bizim için dosya açma/kaydetme gibi sik yapilan islemlere tekrar tekrar diyalog kutusu yazmamiza gerek kalmamasi için bazi sablonlar yaratmislar ve bu sablonlari ortak diyalog kütüphanesi altinda toplamislar.
Kullanabileceginiz ortak diyaloglar (olmazsa olmaz MessageBox'u saymazsak) sekiz tane: Renk Seç, Bul, Font Seç, Dosya Aç, Yazdir, Sayfa Yapisi, Degistir ve Kaydet. Daha önce de söyledigimiz gibi, her biri için sablonlar hazirlanmis ve sablonlarin kullanimi da su sekilde: kullanmak istediginiz ortak diyalog çesidine özgü bir yapi hazirlayip içini istediginiz sekilde dolduruyorsunuz ve bir fonksiyon çagiriip bu yapinin adresini parametre olarak geçiyorsunuz. Fonksiyon da sablonu istediniz biçimde dolduruyor ve ekranda gösteriyor. Dikkatli okuyucular hemen farkina varmistir, "istediginiz bilgiyi döndürüyor" demedim çünkü bu islemin bu kismi diyalog kutularinin ikisi için farkli gerçeklestiriliyor.
Simdi bahsedecegimiz iki kavram, modal ve non-modal, diyalog kutulari için geçerli ve diyalog kutusuyla kullanicidan istedigimiz bilginin ne zaman programimiza dönecegiyle ilgili. Modal diyalog kutulari, ekranda gösterildigi zaman o programin kontrolünü eline geçiriyor, yani kullanici istenen bilgiyi verene veya diyalog kutusunu kapatana kadar programin akisi duruyor. Modal diyalog kapandiktan sonra program akisina kaldigi yerden devam ediyor. Non-modal diyalog kutulari ise programin pencerelerinden biri gibi hareket ediyor ve programin akisini kesmiyor. Ortak diyalog kutularinin ikisi hariç hepsi modal diyalog kutulari kullanirlar, kullanmayanlar Bul ve Degistir diyaloglaridir. Diger fonksiyonlar diyalog kutusunun istenen bilgiyi almasina veya alamadan kapanmasina göre dogru veya yanlis gibi degerler döndürürken, Bul ve Degistir fonksiyonlari, yaratilan diyalog penceresine bir HWND döndürüyor, böylece diyalog kutusuyla bizzat iletisim kurabiliyorsunuz. Aslinda bütün ortak diyalog kutularinin kontrolünü ele geçirmek mümkün (hook/subclassing) ama makalede bu konulara yer vermeyecegiz (kafa karistirici, bazen zor bile olabilien islemler gerektiriyor).
Basvuru Formlari - Ortak Diyalog Kutusu Yapilari
Ögrenciler bilirler, bir sinava gireceginizde veya geziye katilacaginizda bir yerden basvuru formu ya da dilekçe benzeri bir belge alir, üzerindeki bosluklara kendi bilgilerinizle doldurur ve teslim edersiniz. Ortak diyalog kutulari da benzer bir sekilde yaratiliyor, her ortak diyalog kutusu çesidi için bir yapi olusturuyor ve dolduruyorsunuz. Simdi en çok kulanilan ortak diyalog kutulari olan Aç ve Kaydet için kullanilan yapiyi inceleyelim ve bir örnekle devam edelim:
typedef struct tagOFN { // ofn
DWORD lStructSize;
HWND hwndOwner;
HINSTANCE hInstance;
LPCTSTR lpstrFilter;
LPTSTR lpstrCustomFilter;
DWORD nMaxCustFilter;
DWORD nFilterIndex;
LPTSTR lpstrFile;
DWORD nMaxFile;
LPTSTR lpstrFileTitle;
DWORD nMaxFileTitle;
LPCTSTR lpstrInitialDir;
LPCTSTR lpstrTitle;
DWORD Flags;
WORD nFileOffset;
WORD nFileExtension;
LPCTSTR lpstrDefExt;
DWORD lCustData;
LPOFNHOOKPROC lpfnHook;
LPCTSTR lpTemplateName;
} OPENFILENAME;
GetOpenFileName ve GetSaveFileName fonksiyonlari için kullanacagimiz basvuru formu OPENFILENAME yapisi. Yapiyi olusturan elemanlari incelersek:
lStructSize - OPENFILENAME yapisinin bayt cinsinde uzunlugu. Yani her zaman sizeof(OPENFILENAME)
hwndOwnder - Diyalog hangi ana pencereye aitse o pencerenin hWnd degeri
hInstance - Diyalog hangi uygulamaya aitse o uygulamanin hInstance degeri
lpstrFilter - Dosya listesinde hangi uzantili dosyalarin gösterilecegi. Uzantilari bir dizi degiskeni içinde vermeniz gerekiyor, yazim sekli ise "uzanti adi ve açiklamasi\0*.uzanti\0" seklinde. Yani birbirinden \0 (null) karakteriyle ayrilmis uzanti açiklamasi ve uzantilardan olusuyor. Sonuna ekstra bir \0 eklemeniz gerekiyor.
lpstrCustomFilter - Eger kullanici uzanti listesinden farkli bir uzanti seçerse bir önceki seçili uzantiyi saklamak için opsiyonel bir tampona isaretçi. Kullanimi için WinAPI dökümantasyonunuzu ziyaret edebilirsiniz.
nMaxCustFilter - lpstrCustomFilter ile isaret edilen tamponun büyüklügü. Yine opsiyonel.
nFilterIndex - Eger diyalog kutusu ilk açildiginda lpstrFilter degiskeninde belirtilen uzantilarin ilkinin degil de baska birisinin seçili olmasini istiyorsaniz, burada belirtiyorsunuz.
lpstrFile - En can alici nokta. Kullanici bir dosya seçip diyalog kapandigi zaman seçilen dosyanin tam adresini barindiracak olan tampon bölgeye bir isaretçi. Eger "default" bir dosya isminiz varsa diyalog fonksiyonunu çagirmadan önce bu tampon bölgeye yerlestirebilirsiniz.
nMaxFile - lpstrFile ile belirtilen tamponun büyüklügü (yani dosya adresinin en fazla kaç karakterden olusabilecegi)
lpstrFileTitle - Eger dosya adresinin tamamini degil de sadece dosya adini istiyorsaniz (yani C:\yazi\yazi.txt yerine sadece yazi.txt) buraya bir tampona isaretçi atayabilirsiniz. Diyalog kapandigi zaman tampon dosya adini barindiracaktir.
nMaxFileTitle - lpstrFileTitle ile belirtilen tamponun büyüklügü.
lpstrInitialDir - Diyalogun ilk açildigi zaman belirli bir klasörden baslamasini istiyorsaniz burada belirtebilirsiniz. Eger belirtilmezse diyalog geçerli klasörde baslar.
lpstrTitle - Diyalogun basligi. "Dosya Aç" veya "Farkli Kaydet" gibi.
Flags - Diyalog sablonuna has özelliklerin hangilerinin kullanilacagini belirtmeye yarar (klasik "flags" yapisi birbirinden | isaretiyle [binary OR] ayrilmis sabitlerden olusur). Buraya gelebilecek pek çok deger var, örnegimizde kullanacagimiz degerler OFN_EXPLORER (diyalog kutularinin WinXP ve Win2000'de bulunan "Masaüstü, Bilgisayarim, Belgelerim" çabuk erisim butonlari gibi ek özelliklerden faydalanmasini sagliyor), OFN_FILEMUSTEXIST (sonuç olarak döndürülen dosya ismi var olmak zorunda, yani kullanici olmayan bir dosya adi yazip açmaya çalisirsa hata mesaji gösteriliyor) ve OFN_OVERWRITEPROMPT (kaydet diyaloglari için, eger var olan bir dosya adi seçilirse "üzerine yazilsin mi?" mesaji çikmasi için).
nFileOffset - Dosya adinin lpstrFile içindeki baslangici (0 ilk karakter olmak üzere tabii)
nFileExtension - Dosya uzantisinin lpstrFile içindeki baslangici
lpstrDefExt - Kaydetme diyaloglarinda eger kullanici dosya adina uzantiyi bizzat eklemezse (günümüz kullanicisi genelde eklemiyor :)) dosya adina otomatik olarak eklenecek uzanti.
lCustData - Hooking için kullanilan opsiyonel alanlardan biri.
LPOFNHOOKPROC - Eger Hooking kullanacaksiniz hook fonksiyonunuzun adresi.
lpTemplateName - Biz kullanmayacagiz, eger farkli bir ortak diyalog sablonu kullanmak istiyorsaniz o sablonun tanimlayicisi.
Gerçekten de çok elemani var bu yapilarin :). Ama merak etmeyin, hepsine ihtiyaciniz olmayacak. 9 tanesini kullanarak son derece islevsel aç/kaydet diyaloglari hazirlayabilirsiniz.
Göster Diyalogunu!
Simdi eskiden attigimiz temellerin üzerinde az önce ögrendiklerimizle birseyler insa etme zamani geldi. Pencere olusturma fonksiyonlari ikinci makaleden tanidik gelebilir (ileride sablon olarak kullanacagiz dememis miydim? :)).
#include
char szPencCins[]="OrtakDiyalog";
char szMsg[]="Sag veya sol tiklamayi deneyin...";
char szDosyaAdi[MAX_PATH]; //dosya adlari buraya gelecek
HINSTANCE hProgInst; //diger fonksiyonlarla paylasmak için
LRESULT CALLBACK PenPros(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
//pencere prosedürü
void DosyaAcDlg(HWND hwndKaynak);
void DosyaKaydetDlg(HWND hwndKaynak);
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmd,int nShowCmd)
{
hProgInst=hInst;
WNDCLASS x; //pencere tanim bilgileri
x.style=CS_HREDRAW|CS_VREDRAW; //yatay ve dikey boyut degisirse 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 isaretçisi
x.hbrBackground=(HBRUSH)COLOR_WINDOW; //pencere rengi kullan
x.lpszMenuName=NULL; //menü yok
x.lpszClassName=szPencCins; //pencere cinsimiz
if(!RegisterClass(&x))
{
MessageBox(NULL,"Pencere sinifi yaratilamadi!","Hata",MB_ICONSTOP);
return 0;
};
//pencereyi yarat
HWND hWnd=CreateWindow(szPencCins,"Ortak
Diyaloglar",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,
CW_USEDEFAULT,200,200,NULL,NULL,hInst,NULL);
ShowWindow(hWnd,nShowCmd); //pencereyi ekranda göster
//kullanim mesaji
MessageBox(hWnd,szMsg,"Ipucu!",MB_OK);
MSG t; //mesaj verisi için degisken
while(GetMessage(&t,hWnd,0,0)>0) //mesaj kuyrugu doluysa mesaj al
{
TranslateMessage(&t); //klavye mesajlarini çevir
DispatchMessage(&t); //pencere prosedürüne gönder
};
return 0;
};
void DosyaAcDlg(HWND hwndKaynak)
{
//eger geçerli (default) bir dosya adi istiyorsak
strcpy(szDosyaAdi,"dosyaac.txt");
OPENFILENAME ofnAc; //basvuru formumuz, sablon bilgileri
ofnAc.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST; //diyalog stili
ofnAc.hInstance=hProgInst;
ofnAc.hwndOwner=hwndKaynak;
ofnAc.lpstrTitle="Dosya Aç..."; //diyalog basligi
ofnAc.lpstrFile=szDosyaAdi;//sonuç dosya adi tampon degiskenimize yazilacak
ofnAc.nMaxFile=MAX_PATH; //dosya adi en fazla ne kadar uzunlukta olabilir?
ofnAc.lpstrFilter="Metin Belgesi (*.txt)\0*.txt\0Tüm Dosyalar\0*.*\0";
//kabul edilen uzantilar
ofnAc.lpstrInitialDir="C:\\"; //diyalog hangi klasörde baslayacak
ofnAc.lStructSize=sizeof(OPENFILENAME); //yapi uzunlugu
if(GetOpenFileName(&ofnAc))
{
MessageBox(hwndKaynak,szDosyaAdi,"Açilacak Dosya:",MB_OK);
}
else
{
MessageBox(hwndKaynak,"Islem iptal edildi","Mesaj",MB_OK);
};
};
void DosyaKaydetDlg(HWND hwndKaynak)
{
//eger geçerli (default) bir dosya adi istiyorsak
strcpy(szDosyaAdi,"dosyakayit.txt");
OPENFILENAME ofnKay; //basvuru formumuz, sablon bilgileri
ofnKay.Flags=OFN_EXPLORER|OFN_OVERWRITEPROMPT; //diyalog stili
ofnKay.hInstance=hProgInst;
ofnKay.hwndOwner=hwndKaynak;
ofnKay.lpstrTitle="Farkli Kaydet.."; //diyalog basligi
ofnKay.lpstrFile=szDosyaAdi;//sonuç dosya adi tampon degiskenimize yazilacak
ofnKay.nMaxFile=MAX_PATH; //dosya adi en fazla ne kadar uzunlukta olabilir?
ofnKay.lpstrFilter="Metin Belgesi (*.txt)\0*.txt\0"; //kabul edilen uzantilar
ofnKay.lpstrInitialDir="C:\\"; //diyalog hangi klasörde baslayacak
ofnKay.lStructSize=sizeof(OPENFILENAME); //yapi uzunlugu
ofnKay.lpstrDefExt="*.txt"; //kullanici uzanti eklemezse eklenecek
if(GetSaveFileName(&ofnKay))
{
MessageBox(hwndKaynak,szDosyaAdi,"Kaydedilecek Dosya:",MB_OK);
}
else
{
MessageBox(hwndKaynak,"Islem iptal edildi","Mesaj",MB_OK);
};
};
LRESULT CALLBACK PenPros(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg) //mesaj cinsine göre
{
case WM_LBUTTONDOWN:
DosyaAcDlg(hWnd);
break;
case WM_RBUTTONDOWN:
DosyaKaydetDlg(hWnd);
break;
case WM_CLOSE:
PostQuitMessage(0); //programdan çik (GetMessage'a 0 gönder)
break;
default:
return DefWindowProc(hWnd,uMsg,wParam,lParam);
};
return 0;
};
Her zamanki gibi size kopyala-yapistir yerine kendi kodunuzu yazmanizi tavsiye edecegim. Bir de farkettiginiz gibi, örnegimiz sadece Aç ve Kaydet diyaloglarini kapsiyor. Peki kalan alti diyalog ne olacak? Hepsinin yapilarini buraya ayri ayri yazip inceleyebilmek isterdim ama bu durumda makale gerçekten uzun olurdu ve içinde çok sayida tekrar geçerdi, çünkü bütün diyalog yapilarinda kullanilan ortak elemanlar var. Aç ve Kaydet diyaloglarinin kullanimini anladiysaniz diger diyaloglari da bir WinAPI dökümantasyonu ile çalisarak kullanmaniz isten bile degil.
|
| |
|