mfceng.harran.edu.tr/~nbesli/sp/mfc.doc  · web viewcrect sınıfı dikdörtgensel koordinat...

284
MFC Microsoft Foundation Class 2001-10-09 Ekim-Salı günü başladı, 2002-06-11 Haziranda Salı bitti. Kaan Aslan tarafından kurs verildi.C ve Sistem Programcıları Derneği, Mecidiyeköy / İstanbul 0212-274 99 89 0212-288 35 20 Hazırlayan Taner Üstüntaş 1

Upload: trantruc

Post on 21-Apr-2019

231 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

MFCMicrosoft Foundation Class

2001-10-09 Ekim-Salı günü başladı, 2002-06-11 Haziranda Salı bitti.

Kaan Aslan tarafından kurs verildi.C ve Sistem Programcıları Derneği, Mecidiyeköy / İstanbul

0212-274 99 89 0212-288 35 20Hazırlayan Taner Üstüntaş

1

Page 2: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

2

Page 3: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3

Page 4: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

1 API PROGRAMLAMA MODELİNİN PROBLEMLERİBir Windows programının organizasyonu en iyi API programlama modeliyle yansıtılabilir. Çünkü API programlama Windows’ta en aşağı seviyeli çalışma biçimidir. Yani Windows sistemi iskelet API programındaki düzenlemeye uygun olarak çalışmaktadır. API programlama modeli aşağı seviyeli ve Windows’un çalışmasını iyi açıklamasına karşın uygulama geliştirmede pek çok zorluklar içerir.

1) API programlamada pek çok temel işlemin her defasında programcı tarafından yeniden aynı biçimde yapılması gerekir.

2) API programlama nesne yönelimli bir model değildir. Dolayısıyla büyük projelerde çok karmaşık bir yapı oluşturmaktadır.

3) Mesajların ele alınıp işlenmesi, global değişkenlerin çok bol kullanılması proje geliştirmede problemli bir konudur. Aşağı seviyeli olduğu için her türlü ayrıntının programcı tarafından ele alınıp işlenmesi gerekir.

1.1 Windows Programlamada Bir Sınıf Kütüphanesinden BeklenenlerGenel olarak bir sınıf kütüphanesinden işlemleri kolaylaştırması beklenir.

1) Hep aynı biçimde yapılması gereken rutin işlemleri ortadan kaldırmalı, yani kütüphanenin bunu bir biçimde arka planda kendisinin yapması.

2) Birtakım ayrıntıların gizlenmesiyle bir soyutlamanın sağlanması. Örneğin WinMain fonksiyonunun ve pencere fonksiyonlarının gizlenmesi mesajlar oluştuğunda belirli fonksiyonların çağrılması istenen tipik soyutlamalardır.

3) Kullanılan kütüphanenin bir sınıf kütüphanesi olması istenir. Çeşitli olayların sınıflarla temsil edilmesi karmaşıklığı azaltmakta ve uygulama geliştirmeyi kolaylaştırmaktadır.

4) Kütüphanenin çeşitli yararlı programları içeren bir IDE (Integrated Development Environment) ile birleşik olması istenir. Tipik bir IDE çeşitli wizard’lara, görsel editörlere, rutin işlemleri kaldıran kolaylıklara sahip olmalıdır.

Windows için yazılmış bir kütüphanenin seviyesi ne olmalıdır? Seviyenin çok yükseltilmesi soyutlamanın çok aşırıya varması genel olarak C / C++ felsefesine uygun değildir. Seviyenin çok düşük olması da beklenen kolaylıkları azaltmaktadır. O halde C / C++ felsefesine en uygun olan seviye API programlama modelinden aşırı derecede uzaklaşılmadığı, kısmi soyutlamaların yapıldığı ancak önemli kolaylıkların sağlandığı bir seviyedir. Bu seviyeye en uygun sınıf kütüphanesi MFC’dir.

1.2 MFC Sınıf SistemiMFC sınıf sistemi içerisinde yüzden fazla sınıf ve binlerce üye fonksiyon vardır. Sınıf sisteminin en tepesinde CObject denilen bir sınıf bulunur. Bu CObject sınıfı polymorphic uygulamalar için diğer sınıflara taban sınıflık yapmaktadır. MFC sınıflarının çok büyük çoğunluğu CObject sınıfından türetilmiştir. MFC sınıf isimleri geleneksel olarak C harfi ile başlatılarak isimlendirilmiştir. MFC sınıfları kullanım alanlarına göre çeşitli gruplara ayrılabilir. Temel pencere işlemlerinin yapılmasını sağlayan sınıf topluluğu şunlardır:

Bazı MFC sınıfları doğrudan Windows programlamayla ilgisi olmayan sınıflardır. Örneğin CString ve CFile gibi sınıfların doğrudan Windows programlamayla bir ilgisi yoktur. MFC STL sınıflarına gereksinim duymadan bir çalışmayı sağlamak amacıyla düşünülmüştür. Bu yüzden kütüphane sistemi içerisinde çeşitli nesne tutan sınıflar (container class) vardır.

Ayrıca MFC’de az miktarda küçük template sınıflar da bulunmaktadır. MFC çoklu türetmenin tercih edilmediği bir sınıf sistemidir. Çünkü çoklu türetmenin hızı azaltacağı ve karmaşıklığı artıracağı düşünülmüştür. MFC’de polymorphism yani sanal fonksiyon mekanizması orta düzeyde kullanılmıştır. Çünkü sanal fonksiyon mekanizmasının aşırı derecede kullanılmasının hızı yavaşlatacağı düşünülmüştür.

4

Page 5: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CObject

CCmdTarget

CWinThread CWnd

CWinApp CFrameWndMFC sınıflarının büyük çoğunluğu AFXWIN.H dosyasında bildirilmiştir (Tabii AFXWIN.H dosyası pek çok dosyası include etmektedir). AFXWIN.H dosyası ayrıca kendi içerisinde WINDOWS.H dosyasını da include etmektedir. MFC sınıflarına ilişkin fonksiyon kodları hem statik kütüphanelere hem de dinamik kütüphanelere yerleştirilmiştir. Yani programcı isteğine göre statik ya da dinamik link işlemi yapabilir. Statik kütüphane kullanımı .EXE dosyaları büyütmektedir. Ancak dinamik link tercih edilirse ilgili DLL dosyalarının program çalıştırılırken bulundurulması gerekir (MFC sınıflarının hemen hepsi MFC42.DLL denilen bir DLL dosyası içindedir). Normal koşullarda dinamik link tercih edilmelidir.

1.3 MFC Uygulamasında Winmain FonksiyonuBilindiği gibi her Windows programının giriş noktası WinMain fonksiyonudur. MFC uygulamasında da program gene WinMain fonksiyonundan çalışmaya başlar. Ancak WinMain programcı tarafından yazılmaz, kütüphane içerisine yerleştirilmiştir. Bu durumda MFC programı kütüphanede bulunan WinMain fonksiyonundan çalışmaya başlamaktadır. WinMain fonksiyonunun gizlenmesinin iki amacı vardır:

1) Rutin işlemlerin ortadan kaldırılması ve soyutlama yapılması.

2) MFC kütüphane sistemi için WinMain içerisinde yapılması gereken birtakım ek işlemler de vardır. Eğer WinMain programcı tarafından yazılsaydı bu işlemlerin de programcı tarafından yapılması gerekirdi.

Programın mesaj döngüsü de WinMain içerisinde yani kütüphanededir. MFC uygulamasında akış programcıya ana pencerenin yaratılması gerektiği noktasında verilmektedir. Programcı ana pencereyi yarattıktan sonra akış yeniden WinMain’e döner ve WinMain içerisindeki mesaj döngüsüne girer.

2001-10-11 perşembe

1.4 Program Akışının Ele GeçirilmesiMFC sınıflarının çoğu genellikle doğrudan değil türetme uygulanarak kullanılır. Zaten türetme (public türetmesi) taban sınıfı tam olarak kullanabilmemize olanak sağlar. Gereken birtakım ilave işlemler türemiş sınıf içerisine eklenebilir.

Bilindiği gibi global sınıf nesneleri için başlangıç fonksiyonları main ya da WinMain fonksiyonlarından önce çağrılmaktadır.

Bir MFC uygulamasında akışı ele geçirmek için yapılması gereken işlemler şunlardır:

1) CWinApp sınıfından bir sınıf türetilir ve o sınıf için InitInstance sanal fonksiyonu yazılır (InitInstance ilk kez CWinThread sınıfında sanal olarak tanımlanmış bir fonksiyondur).

2) CWinApp sınıfından türettiğimiz sınıf türünden global bir sınıf nesnesi tanımlamak gerekir. Örneğin:

class CMyApp : public CWinApp {public:

virtual BOOL InitInstance(void);};BOOL CMyApp::InitInstance(void){

// .....}CMyApp theApp;

5

Page 6: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

InitInstance fonksiyonunun prototipi şöyledir:BOOL InitInstance(void);Akışın nasıl programcıya geçtiği aşağıdaki kodlarla anlaşılabilir:CWinThread *g_pApp;CWinApp::CWinApp(void){

g_pApp = this;// .....

}WinMain(.....){

if (!g_pApp->InitInstance())return;

g_pApp->Run();}

Yukarıdaki kodlar MFC kütüphanesinin içerisindedir ve soyutlama sağlansın diye basitleştirilmiştir. CWinApp sınıfından türettiğimiz sınıfa ilişkin global sınıf nesnesi yoluyla programın akışı WinMain fonksiyonuna girmeden bir dizi başlangıç fonksiyonu çağrılacaktır. Görüldüğü gibi bu global sınıf nesnesinin adresi kütüphane içerisindeki global bir göstericiye atanmıştır. Programın akışı WinMain fonksiyonuna girdiğinde bu gösterici yoluyla InitInstance sanal fonksiyonu çağrıldığında sanallık mekanizmasından dolayı türettiğimiz sınıfın sanal fonksiyonu çağrılır. MFC kütüphanesinde klasik GetMessage, TranslateMessage, DispatchMessage fonksiyonlarından oluşan mesaj döngüsü CWinThread sınıfının Run üye fonksiyonu içerisinde kurulmuştur. Görüldüğü gibi akış InitInstance fonksiyonundan döndüğünde Run üye fonksiyonu çağrılarak mesaj döngüsüne girilmektedir. Ayrıca InitInstance fonksiyonunun geri dönüş değeri FALSE ise programın sonlandırıldığını yani mesaj döngüsüne girilmediğini de görmekteyiz.

Normal olarak bir GUI uygulaması için InitInstance fonksiyonu içerisinde programın ana penceresi yaratılmalı ve TRUE ile geri dönülmelidir.

Anahtar Notlar : MFC sınıflarının pek çok üye fonksiyonu API fonksiyonlarıyla aynı isimlidir. Bu nedenle bir sınıfın üye fonksiyonu içerisinde bir API fonksiyonu çağrılacaksa gerekiyor olsa da olmasa da okunabilirliği arttırmak amacıyla unary çözünürlük operatörü kullanılmalıdır.

::MoveWindow(.....);

1.5 Programın Ana Penceresinin YaratılmasıMFC sisteminde tüm pencere işlemleri de sınıflarla yapılır. Temel pencere işlemleri CWnd sınıfı tarafından gerçekleştirilmektedir.

Anımsatma : Bir pencere CreateWindow ya da CreateWindowEx API fonksiyonlarıyla yaratılır. CreateWindow fonksiyonunun önemli parametreleri WNDCLASS ismi, pencere biçimi ve HMENU parametreleridir. Hiçbir pencerenin alt penceresi olmayan masa üstünde görüntülenen pencerelere ana pencereler (top level windows) denir. Ana pencere yaratmak için CreateWindow fonksiyonunun hWndParent parametresi NULL olarak girilmelidir. Alt pencereler ayrıca ID değeri denilen WORD bir değere daha sahiptir. Alt pencere yaratmak için CreateWindow fonksiyonunun hWndParent parametresi üst pencerenin handle değeri olarak girilmelidir. Ayrıca pencere biçimi olarak WS_CHILD eklenmelidir. WS_CHILD eklenmezse pencere owned pencere olur. Owned pencere üst penceresinin sınırları dışına çıkabilir ve her zaman üst pencerenin üzerinde görüntülenir. Üst pencere minimize edildiğinde owned pencereler de gözden kaybolur. Alt – üst pencere ilişkisi üzerinde işlem yapan önemli fonksiyonlar şunlardır: GetParent, GetDlgItem, GetDlgCtrlID. Pencere yaratıldıktan sonra alınan handle değeri pencere ile işlem yapan bütün fonksiyonlara birinci parametre olarak geçirilmektedir. Pencere DestroyWindow API fonksiyonuyla istenildiği zaman yok edilebilir.

CWnd sınıfı şu biçimde türetilmiştir:6

Page 7: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CObject

CCmdTarget

CWinThread

CWinApp

CWnd sınıfının yaratılan pencerenin handle değerini tutan HWND m_hWnd isimli bir veri elemanı vardır. Sınıfın Create üye fonksiyonu CreateWindow API fonksiyonunu çağırarak pencereyi yaratır ve handle değerini sınıfın m_hWnd veri elemanına yazar. Sınıfın bütün üye fonksiyonları parametre olarak handle değerini istemezler. Çünkü zaten bu değeri sınıfın veri elemanından alırlar. Tabii bu üye fonksiyonlar aslında API fonksiyonlarını çağırarak işlemlerini yapmaktadır. Örneğin CWnd::UpdateWindow fonksiyonu şöyle yazılmıştır:void CWnd::UpdateWindow(void){

::UpdateWindow(m_hWnd);}CWnd sınıfının bitiş fonksiyonu kendi içerisinde DestroyWindow API fonksiyonunu çağırarak pencereyi yok etmektedir. Bu nedenle örneğin aşağıdaki gibi bir kodda pencere yaratıldığı gibi yok edilir.

{CWnd wnd;

wnd.Create(.....);} // Blok bitince bitiş fonksiyonu çağrılır ve bitiş fonksiyonu da // pencereyi yok eder.

CWnd sınıfı handle değeri bilinen her türlü pencere için API fonksiyonlarını çağırarak işlemler yapan üye fonksiyonlara sahiptir. Ancak programın ana penceresi ya da dialog pencereleri ekstra özelliklere sahip olan özelliklerdir. Bu nedenle programın ana penceresi ve dialog pencereleri CWnd sınıfından türetilmiş olan ayrı sınıflarla temsil edilmiştir.

CObject

CCmdTarget

CWnd

CFrameWnd CDialog

Programın ana penceresini temsil eden sınıf CFrameWnd sınıfıdır (yüksek seviyeli programlama terminolojisinde programın ana penceresi Microsoft tarafından "frame window" terimiyle de belirtilir).

2001-10-16 Salı

Programın ana penceresini yaratabilmek için CFrameWnd sınıfını doğrudan kullanmak yerine bu sınıftan türetme yapmak daha uygun bir yöntemdir. Programın ana penceresi CWnd::Create ile değil CFrameWnd::Create ile yaratılmalıdır. CWnd ve CFrameWnd sınıflarının her ikisinin de Create fonksiyonları vardır. Zaten CFrameWnd::Create birtakım işlemlerden sonra CWnd::Create fonksiyonunu çağırmaktadır.

BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle = WS_OVERLAPPEDWINDOW, const RECT &rect = rectDefault, CWnd *pParentWnd = NULL, LPCTSTR lpszMenuName = NULL, DWORD dwExStyle = 0, CCreateContext *pContext = NULL);

7

Page 8: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Görüldüğü gibi fonksiyonun ilk iki parametresinin dışındaki parametreleri default değer almaktadır. Fonksiyonun birinci parametresi register ettirilmiş bir sınıf ismini alır. Bu parametre NULL olarak girilirse MFC kütüphanesinin içerisinde register ettirilmiş olan bir sınıf kullanılır. Fonksiyonun çağırma akışı şöyledir:

CFrameWnd::Create ----> CWnd::Create ----> ::CreateWindowEx

Programın ana penceresinin yaratılacağı CFrameWnd sınıfından türetilmiş olan sınıfın adresi CWinApp sınıfının m_pMainWnd gösterici elemanında saklanmak zorundadır. Programın ana penceresi yaratıldıktan sonra iskelet API programında olduğu gibi UpdateWindow ve ShowWindow fonksiyonlarının çağrılması gerekir. Tabii bu API fonksiyonlarının doğrudan çağrılması yerine CWnd sınıfının aynı isimli üye fonksiyonlarının çağrılması aynı şeydir.

Bu durumda bir MFC uygulamasında ana pencerenin yaratılması iki biçimde yapılabilir:

1)BOOL CGenericApp::InitInstance(void)

{m_pMainWnd = new CMainWnd();m_pMainWnd->Create(NULL, "Sample Window");m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

m_pMainWnd, MFC'nin sonraki versiyonlarında (thread kavramı eklendikten sonra) CWinApp sınıfından alınarak CWinThread sınıfına yerleştirilmiştir. m_pMainWnd CFrameWnd sınıfı türünden bir göstericidir. class CWinThread : public CCmdTarget {public:

CFrameWnd *m_pMainWnd;// .....

};m_pMainWnd thread'lerle çalışırken her thread'in kendi ana penceresini tutar.

2) CFrameWnd::Create fonksiyonu InitInstance içerisinde değil de CFrameWnd sınıfından türettiğimiz sınıfın başlangıç fonksiyonu içerisinde de çağrılabilir. Her iki durumda da m_pMainWnd elemanında adresi tutulacak sınıf nesnesinin dinamik olarak yaratılması gerekir.

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(){Create(NULL, "Sample Window");}

m_nCmdShow CWinApp sınıfının veri elemanıdır.

CObject

CCmdTarget

8

Page 9: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CWinThread CWnd

CWinApp CFrameWnd

CGenericApp Bizim türettiğimiz sınıflar

CMainApp

1.6 İskelet MFC Programının YazımıYapılacak işlemler şunlardır:

1) CWinApp sınıfından bir sınıf türetilir ve o sınıf için InitInstance sanal fonksiyonu yeniden yazılır.

2) CWinApp'den türetilen sınıf türünden global bir sınıf nesnesi yaratılır.

3) CFrameWnd sınıfından bir sınıf türetilir.

4) InitInstance fonksiyonu içerisinde CFrameWnd sınıfından türetilen sınıf türünden dinamik bir nesne yaratılır ve bu nesnenin adresi CWinThread::m_pMainWnd elemanında saklanır.

5) Yaratılan sınıf nesnesi ile CFrameWnd::Create fonksiyonu çağrılarak programın ana penceresi yaratılır.

//GENMFC.H#ifndef _GENMFC_H_#define _GENMFC_H_

// Uygulamayı temsil eden sınıf CWinApp sınıfından türetilir

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void); // Akışın ele geçirildiği ilk fonksiyon};

// Uygulamanın ana penceresine ilişkin sınıf CFrameWnd sınıfından türetilir

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);};

#endifGENMFC.CPP

#include <afxwin.h>#include "genmfc.h"

// Uygulamaya ilişkin global değişken

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd(); // CWinThread::m_pMainWnd programın ana // penceresine ilişkin sınıfı göstermelidir

m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE; // Mesaj döngüsüne girmek için TRUE ile geri dönülmelidir

}

CMainWnd::CMainWnd(void){

// Ana pencere CFrameWnd::Create fonksiyonu ile yaratılıyorCreate(NULL, "Generic MFC Application", WS_OVERLAPPEDWINDOW );

}

9

Page 10: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

1.7 İskelet MFC Programının Çalıştırılmasıİskelet MFC programının wizard kullanarak otomatik bir biçimde yazılması gereken bazı işlemlerin de otomatik olarak yapılmasını sağlar. Ancak wizard kullanmadan MFC programı yazmak için link aşamasında MFC kütüphanelerinin de işleme dahil edilmesi gerekir. Bunun için şunlar yapılmalıdır:

1) File/New/Win32 Application seçilir. API programı yazmak istemediğimizden Empty Project seçilir.

2) MFC programı yazılır ve projeye dahil edilir.

3) Project/Settings/General menüsünden MFC kütüphane sisteminin static ya da dinamik olarak link işlemine dahil edilmesi sağlanır.

1.8 Pencere Mesajlarının İşlenmesiBilindiği gibi her pencerenin API düzeyinde bir pencere fonksiyonu vardır. Mesajlar pencere fonksiyonu içerisinde işlenir. Pencere fonksiyonu WNDCLASS yapısı içerisinde belirlenmektedir. Win32'de her thread'in ayrı bir mesaj kuyruğu vardır. Bir thread'in yarattığı bütün pencerelere ilişkin mesajların hepsi o thread'in mesaj kuyruğuna gider. Mesaj döngüsü içerisinde GetMessage fonksiyonu her pencereye gelen mesajı alır, DispatchMessage fonksiyonu ise mesaj hangi pencereye ilişkinse o pencerenin pencere fonksiyonunu çağırır.

while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);

}

MFC'de CWnd sınıfı kullanılarak yaratılmış tüm pencerelerin pencere fonksiyonları aynı fonksiyondur ve bu fonksiyonun ismi AfxWndProc'tur. MFC'de tüm global fonksiyonlar Afx önekiyle başlatılmıştır.

Programcı register ettirmiş olduğu bir sınıf ismini kullansa bile CWnd::Create fonksiyonu içerisinde sınıf ile belirtilen pencere fonksiyonu bir yere saklanır ve pencere fonksiyonu olarak yine AfxWndProc yerleştirilir. Bu durumda örneğin aşağıdaki gibi bir push button kontrolü yaratılsa bile push button üzerinde işlem gerçekleştiğinde yine AfxWndProc çağrılacaktır.

CWnd button;button.Create("button", .....);

Eğer pencere Create üye fonksiyonunun birinci parametresine NULL geçirilerek yaratılmışsa bu durumda MFC içerisinde register ettirilmiş bir sınıf kullanılır ki zaten o sınıfın pencere fonksiyonu AfxWndProc fonksiyonudur.

2001-10-18 Perşembe

MFC'de pencere yaratan her türlü sınıf CWnd sınıfından türemiştir. Bütün pencereler en sonunda CWnd::Create fonksiyonu ile yaratılır ve CWnd::DestroyWindow fonksiyonu ile pencere yok edilir. MFC'de yaratılan pencerelerin handle değerlerini ve bu pencerelerin yaratılmasında kullanılan nesne adreslerini bir çift halinde tutan global bir tablo vardır (erişim hızlı olsun diye bu tablo hash tablosu olarak kurulmuştur). Böyle bir tablonun varlığı dökümante edilmemiştir. Bu global tablo aşağıdaki gibi bir görünüme sahiptir:

CWnd Nesnesinin Adresi Pencere Handle değeri&Wnd1 &hWnd1&Wnd2 &Wnd2..

.

.

Söz konusu global tabloya eleman ekleme işlemi CWnd::Create fonksiyonu tarafından yapılmaktadır. Eleman silme işlemi ise pencereyi yok eden CWnd::DestroyWindow tarafından gerçekleştirilir. Bu durumda herhangi bir zaman bu tablo incelense yaratılmış olan bütün

10

Page 11: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

pencerelerin handle değerleri ve bu pencerelerin yaratılması sırasında kullanılan nesne adresleri elde edilebilir.

Herhangi bir pencereye ilişkin bir olay gerçekleştiğinde AfxWndProc fonksiyonu pencere fonksiyonu olarak çağrılır. Şüphesiz bu fonksiyon sistem tarafından yani DispatchMessage tarafından doğrudan çağrılır. AfxWndProc aynı parametrelerle AfxCallWndProc isimli fonksiyonu çağırır. AfxCallWndProc içerisinde olayın gerçekleştiği handle değerinden hareketle global tabloda arama yapılarak o pencerenin yaratılmasında kullanılan CWnd nesne adresi bulunur ve bu adresle CWnd sınıfının sanal WindowProc fonksiyonu çağrılır.

AfxWndProc ----> AfxCallWndProc ----> virtual CWnd::WindowProc

CWnd::WindowProc fonksiyonunun parametrik yapısı şöyledir:

virtual LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

Görüldüğü gibi CWnd::WindowProc adeta yarattığımız pencerenin pencere fonksiyonu gibidir. Çünkü o pencereyle ilgili bir işlem yapıldığında API pencere fonksiyonunda olduğu gibi bu fonksiyon çağrılacaktır. Bu aşamada mesaj işleme işlemlerinde MFC bırakılarak API düzeyine dönülebilir. Eğer MFC mesaj işlemleri devam ettirilecekse CWnd sınıfının WindowProc fonksiyonu da çağrılmalıdır. Çünkü mesaj işlemlerinin geri kalan kısmını bu fonksiyon yapar. Yani bir pencerenin sanal WindowProc'unu yazmaktaki amacımız olayların akışını durdurmamak yalnızca araya girmekse CWnd sınıfının WindowProc fonksiyonu da çağrılmalıdır.

LRESULT CMyWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){

// .....

return CWnd::WindowProc(message, wparam, lparam);}

Örneğin WindowProc fonksiyonu yoluyla API düzeyine geçerek şöyle programlama yapılabilir: #include <afxwin.h>

class CMyApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMyWnd : public CFrameWnd {public:

CMyWnd(void);virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

};

BOOL CMyApp::InitInstance(void){

m_pMainWnd = new CMyWnd();m_pMainWnd->ShowWindow(SW_RESTORE);m_pMainWnd->UpdateWindow();

return TRUE;}

LRESULT CMyWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){

switch (message) {case WM_LBUTTONDOWN:

MessageBox("Left button pressed!..");break;

case WM_DESTROY:PostQuitMessage(0);

11

Page 12: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

break;default:

return ::DefWindowProc(m_hWnd, message, wPaarm, lParam);}return 0;}

CMyWnd::CMyWnd(void){

Create(NULL, "Sample Window");}

CMyApp theApp;

Görüldüğü gibi burada CWnd::WindowProc çağrılmamıştır. Dolayısıyla MFC mesaj işlemleri kesilerek API düzeyine dönülmüştür.

CWnd::WindowProc CWnd::OnWndMsg fonksiyonunu çağırır. CWnd::OnWndMsg önce mesajın ne mesajı olduğuna bakar. CWnd::OnWndMsg eğer mesaj WM_COMMAND veya WM_NOTIFY ise CWnd::OnCommand ve CWnd::OnNotify sanal fonksiyonlarını çağırır. Eğer mesaj WM_COMMAND ya da WM_NOTIFY değilse sınıfın mesaj haritasına (mesaj map) bakılır. Mesaj haritasında bu mesaj için belirlenen fonksiyon çağrılır.

AfxWndProc ----> AfxCallWndProc ----> virtual CWnd::WindowProc ----> CWnd::OnWndMsg ---->{ WM_COMMAND ise virtual CWnd::OnCommand, WM_NOTIFY ise virtual CWnd::OnNotify,

değilse mesaj haritasında belirtilen fonksiyonu çağırır}

Görüldüğü gibi WM_COMMAND ve WM_NOTIFY mesajları OnCommand ve OnNotify sanal fonksiyonlarını yazarak işlenebilir. Ancak bunların dışındaki hemen her mesaj, mesaj haritası denilen yöntemle işlenmektedir. Mesaj haritası bir mesaj oluştuğunda bir sınıfın istediğimiz üye fonksiyonunun çağrılmasını sağlayan bir yöntemdir.

1.9 MFC Mesaj İşlemlerinden Çıkan Sonuçlar1) Bir mesaj oluştuğunda yukarıda anlatılan işlemlerin gerçekleşmesi bir dizi işlemden sonra otomatik olarak yapılmaktadır. Bu işlemlerin kesilmesi ancak WindowProc sanal fonksiyonu yazılıp, CWnd::WindowProc fonksiyonunu çağırmayarak mümkün olur.

2) WM_COMMAND ve WM_NOTIFY mesajlarını işlemek için en pratik yöntem pencereyi yarattığımız sınıfta OnCommand ve OnNotify sanal fonksiyonlarını yazmaktır.

3) Diğer mesajlarda istediğimiz bir üye fonksiyonun çağrılmasını sağlamak için mesaj haritası kullanılmalıdır.

2001-10-23 Salı

1.10 MFC Mesaj DöngüsüAPI düzeyinde klasik mesaj döngüsü şu biçimdedir:

while (GetMessage(&msg, 0, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);

}

MFC'de mesaj döngüsü CWinThread::Run üye fonksiyonu içerisinde kurulmuştur. Ancak CWinThread::Run üye fonksiyonu içerisinde mesaj döngüsü GetMessage ile değil PeekMessage fonksiyonuyla kurulmuştur. Bilindiği gibi PeekMessage eğer mesaj kuyruğunda mesaj varsa alır, fakat mesaj yoksa thread'i bloke etmez. Böylelikle mesaj döngüsü içerisinde

12

Page 13: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

bir fonksiyonun sürekli çağrılabilmesi sağlanmıştır. CWinThread::Run üye fonksiyonu kütüphanede aşağıdakine benzer bir biçimde yazılmıştır:

int CWinThread::Run(void){

int bIdle = TRUE;int idleCount = 0;

for (;;) {while (!::PeekMessage(.....)) {

if (bIdle && !OnIdle(idleCount++))bIdle = FALSE;

}if (!PreTranslateMessage(.....)) {

::TranslateMessage(.....);::DispatchMessage(.....);

}}}

Görüldüğü gibi mesaj döngüsüne bakılırken CWinThread::OnIdle sanal fonksiyonu çağrılmaktadır:

virtual BOOL OnIdle(LONG lCount);

Bu durumda programcı mesaj kuyruğunda mesaj yokken arka plan işler yapmak isterse CWinApp sınıfından türetmiş olduğu sınıf için OnIdle sanal fonksiyonunu yazmalıdır. OnIdle fonksiyonu FALSE ile geri döndürülürse bu fonksiyonun çağrılmasına devam edilmez. TRUE ile geri döndürülürse fonksiyonun çağrılmasına devam edilir. Bu fonksiyon programcı tarafından yazılmazsa duruma göre CWinApp ya da CWinThread'in OnIdle sanal fonksiyonu çağrılır. Kütüphanedeki OnIdle fonksiyonları thread'i belirli bir süre bloke edecek biçimde yazılmışlardır. OnIdle fonksiyonu programcı tarafından yazılacaksa arka plan işlem yapıldıktan sonra thread'in hiç olmazsa bir quanta süresi kadar bloke edilmesi faydalı olur. Aksi halde thread meşgul döngü içerisinde kalacaktır ve OnIdle fonksiyonu çok hızlı ve fazla bir biçimde çağrılacaktır. Ya da OnIdle fonksiyonunu yazan programcı fonksiyonun başında bilinçli olarak CWinThread::OnIdle'ı çağırarak problemi çözebilir. Kuyrukta mesaj varsa mesaj alınır, dispatch edilmeden önce alınan mesaj ile CWinThread'in PreTranslateMessage sanal fonksiyonu çağrılır.

virtual BOOL CWinThread::PreTranslateMessage(MSG *pMsg);

Görüldüğü gibi CWinApp sınıfından türettiğimiz sınıf için PreTranslateMessage fonksiyonunu yazarsak daha mesaj dispatch edilmeden yakalayabiliriz. Bu fonksiyon belirli mesajları devre dışı bırakmak için ya da değiştirmek için yazılabilir. Ya da yalnızca bir araya girme işlemi de yapılabilir. Bu fonksiyonu FALSE ile geri döndürürsek mesaj dispatch edilir, TRUE ile geri döndürürsek dispatch edilmez. Oluşan bir mesaj en erken bu biçimde ele geçirilebilir. Çünkü WindowProc fonksiyonu ile ele geçirilmesi için mesajın dispatch edilmesi gerekir. Örnek bir kullanım şöyle olabilir:BOOL CMyApp::PreTranslateMessage(MSG *pMsg){

if (pMsg->message == WM_RBUTTONDOWN)pMsg->message = WM_LBUTTONDOWN;

return FALSE;}

CWinThread::PreTranslateMessage önemli bir işlem yapmamaktadır.

Anımsatma : Bir sınıfın bir üye fonksiyonunun başlangıç adresini tutan göstericilere üye fonksiyon göstericileri denir. Üye fonksiyon göstericileri sınıfın veri elemanı olmak zorunda değildir ve aşağıdaki gibi tanımlanır:

13

Page 14: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

class Sample {public:

void Func(void);// .....

};

void (Sample::*pF)(void);pF = Sample::Func;

Üye fonksiyon göstericisi ile üye fonksiyonu çağırabilmek için bir sınıf nesnesi ya da göstericisine gereksinim duyulur. Ancak çağırma aşağıdaki gibi yapılamaz:

Sample X;

X.pF();

Çünkü nokta operatörünün sağındaki operandın sınıf faaliyet alanında tanımlanmış bir isim olması gerekir. Bu tür çağırmalar için özel iki operatör vardır:

.* ve ->*

Ancak bu operatörler parantez operatöründen daha düşük öncelikli olduğu için aşağıdaki gibi kullanılmalıdır:

Sample X;Sample *p = new Sample();void (Sample::*pF)(void);

pF = Sample::Func;(X.*pF)();(p->*pF)();

Türetme durumunda türemiş sınıf üye fonksiyon göstericisine taban sınıf üye fonksiyonunun adresini atamak güvenli ve geçerli bir işlemdir. Bunun tersi olan durum güvensiz bir atamadır ve error ile sonuçlanır. Örneğin:

void (A::*pFA)(void);pFA = B::FuncB; // error

void (B::*pFB)(void);pFB = A::FuncA; // ok

Tabii türemiş sınıf üye fonksiyonunun adresini taban sınıf üye fonksiyon göstericisine tür dönüştürme operatörüyle atayabiliriz. Örneğin:

void (A::*pFA)(void);pFA = (void (A::*)(void)) B::FuncB;

14

Page 15: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

2 MESAJ HARİTALARIBir mesaj oluştuğunda bir sınıfın bir üye fonksiyonunun çağrılması iki biçimde gerçekleşebilir:

1) Sanal fonksiyon mekanizmasıyla. Örneğin WM_COMMAND mesajı için CWnd::OnCommand sanal fonksiyonunun çağrılmasında olduğu gibi.

2) Mesaj haritaları yoluyla.

MFC sisteminde sanal fonksiyon yöntemi yoğun olarak kullanılmamıştır. Sanal fonksiyonlar yerine mesaj haritaları daha baskın olarak tercih edilmiştir.

2001-10-25 Perşembe

Mesaj haritası sınıfın statik bir yapı dizisidir. Bu yapı dizisinde kabaca hangi mesajlar için hangi üye fonksiyonların çağrılacağı bilgileri vardır. Mesaj haritası WindowProc sanal fonksiyonunun çağırdığı OnWndMsg fonksiyonu tarafından aranır. Yani OnWndMsg mesajı WM_COMMAND ya da WM_NOTIFY değilse sınıfın mesaj haritasına bakmaktadır. Mesaj haritasının kurulabilmesi için sınıf bildiriminde ve tanımlamasında çeşitli eklentilerin yapılması gerekir. Mesaj haritası kurmak için gereken düzenlemeler birkaç makro tarafından kolaylıkla yapılabilir. Mesaj haritasını oluşturan AFX_MSGMAP_ENTRY yapısı şöyledir:

struct AFX_MSGMAP_ENTRY {UINT nMessage;// mesajın numarasını içerirUINT nCode; // UINT nID; // UINT nLastID; //UINT nSig; // çağrılacak üye fonksiyonun parametrik yapısını belirlerAFX_PMSG pfn; // çağrılacak üye fonksiyonun adresini tutmaktadır

};

Yapının nMessage elemanı mesaj oluştuğunda mesajın numarasını içerir. nSig elemanı çağrılacak üye fonksiyonun parametrik yapısını belirlemek için kullanılır. pfn elemanı ise mesaj oluştuğunda çağrılacak üye fonksiyonun adresini tutmaktadır. pfn üye fonksiyon göstericisi genel bir göstericidir. Bu üye fonksiyon çağrılacağı zaman orijinal biçimine dönüştürülecektir. Üye fonksiyon göstericisi AFX_PMSG tür ismiyle temsil edilmiştir. Bu tür aşağıdaki gibi typedef edilmiştir:

typedef void (CCmdTarget::*AFX_PMSG)(void);

Bir sınıfa mesaj haritası yerleştirebilmek için ilk yapılacak işlem DECLARE_MESSAGE_MAP( ) isimli makronun sınıf bildirimi içerisine yerleştirilmesidir. Bu makro içerisinde bölüm belirleme işlemi yapıldığından makronun sınıf bildiriminin sonuna yerleştirilmesi daha uygundur. Örneğin:

class CMainWnd : public CFrameWnd {// .....DECLARE_MESSAGE_MAP()

};

DECLARE_MESSAGE_MAP( ) makrosu şöyle yazılmıştır:

#define DECLARE_MESSAGE_MAP() \private: \

static const AFX_MSGMAP_ENTRY _messageEntries[ ]; \protected: \

static AFX_DATA const AFX_MSGMAP messageMap; \virtual const AFX_MSGMAP *GetMessageMap() const;

Burada messageEntries isimli dizi söz konusu mesaj haritasıdır. Tabii CWnd::OnWndMsg adresiyle belirlediği nesnenin hangi sınıfa ilişkin olduğunu bilemez. Bilemediği için de bu mesaj dizisini tespit edemez. Bu nedenle makro sınıfa bu dizinin başlangıç adresini veren

15

Page 16: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

GetMessageMap isimli bir üye fonksiyon da eklemiştir. GetMessageMap sanal fonksiyonu aslında doğrudan messageEntries dizisinin başlangıç adresiyle geri dönmez. Sınıfa eklenen messageMap yapısının adresiyle geri döner. Bu yapının içerisinde dizinin başlangıç adresi tutulmaktadır. Burada söz konusu olan AFX_MSGMAP yapısı şöyledir:

struct AFX_MSGMAP {const AFX_MSGMAP *pBaseMap;const AFX_MSGMAP_ENTRY *lpEntries;

};

Bu yapının içerisinde hem mesaj haritasına ilişkin dizinin başlangıç adresi hem de taban sınıfın mesaj haritasının başlangıç adresi bulunmaktadır.

Özetle DECLARE_MESSAGE_MAP makrosu ile şunlar yapılmaktadır:

1) Mesaj haritasına ilişkin AFX_MSGMAP_ENTRY türünden statik bir dizinin bildirimi sınıfa eklenir.

2) Bu statik dizinin başlangıç adresinin elde edilmesi için GetMessageMap isimli sanal bir fonksiyonun prototipi sınıfa eklenir.

3) GetMessageMap sanal fonksiyonu doğrudan statik dizinin başlangıç adresiyle geri dönmez. Sınıfa yerleştirilen statik bir yapının başlangıç adresiyle geri döner. Dizinin adresi bu yapıda yazmaktadır. Yani dizinin adresine dolaylı bir biçimde erişilmektedir.

Sonuç olarak türetme ağacının herhangi bir yerinde sınıfa yerleştirilen GetMessageMap sanal fonksiyonunu çağırarak mesaj haritasına ilişkin diziyi inceleyebiliriz. Zaten OnWndMsg fonksiyonu da mesaj hartasını böyle ele geçirmektedir.

DECLARE_MESSAGE_MAP makrosu ile yapılan bildirimlerin tanımlamaları BEGIN_MESSAGE_MAP ve END_MESSAGE_MAP makrolarıyla yapılır. Bir sınıf .H ve .CPP dosyalarıyla yazıldığına göre bu makrolar .CPP dosyasının tepesine global düzeyde yerleştirilmelidir. BEGIN_MESSAGE_MAP makrosu iki parametreli bir makrodur. Birinci parametresi mesaj haritasının yerleştirildiği sınıfın ismi, ikinci parametresi ise bu sınıfın taban sınıf ismi olmak zorundadır. END_MESSAGE_MAP makrosunun parametresi yoktur. Bu durumda bu makrolar tipik olarak aşağıdaki gibi oluşturulabilir:

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)END_MESSAGE_MAP()

BEGIN_MESSAGE_MAP makrosu şöyle yazılmıştır:

#define BEGIN_MESSAGE_MAP(theClass, baseClass) \const AFX_MSGMAP *theClass::GetMessageMap() const; \

{ return &theClass::messageMap; } \AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \{ &baseClass::messageMap, &theClass::_messageEntries[0] }; \AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[ ] = \{ \

END_MESSAGE_MAP makrosu da şöyle yazılmıştır:

#define END_MESSAGE_MAP() \{0, 0, 0, 0 AfxSig_end, (AFX_PMSG)0} \}; \

BEGIN_MESSAGE_MAP makrosunda şunlar yapılmıştır:

1) Bildirimde belirtilen GetMessageMap sanal fonksiyonu yazılmıştır.

2) Mesaj harita dizisinin başlangıç adresi bildirimde belirtilen messageMap isimli statik veri elemanına yazılmıştır.

3) Mesaj harita dizisi global düzeyde ilk değer veriliyormuş gibi tanımlanmıştır. Makronun yerleştirdiği son şey bu mesaj harita dizisine ilk değer vermeyi başlatan küme parantezidir. Yani

16

Page 17: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

BEGIN_MESSAGE_MAP makrosundan sonra yazılan ifadeler bu diziye verilen ilk değerler gibi ele alınacaktır.

END_MESSAGE_MAP mesaj harita dizisinin sonunun tespit edilebilmesi için bir eleman yerleştirerek ilk değer verme küme parantezini kapatır.

2.1 Mesaj MakrolarıBir mesaj oluştuğunda istenilen bir üye fonksiyonun çağrılması için mesaj harita dizisine bu işleme ilişkin bir eleman eklenmesi gerekir. Yani BEGIN_MESSAGE_MAP ve END_MESSAGE_MAP makroları arasına mesaj numarası ve çağrılacak üye fonksiyonun belirtildiği AFX_MSGMAP_ENTRY türünden yapı elemanları girmek gerekir. Bu yapı elemanları kolaylık sağlamak amacıyla manual olarak değil, ismine mesaj makroları denilen makrolarla girilmektedir. Mesaj makroları parametresiz ya da parametreli makrolar olmak üzere ikiye ayrılır. Parametresiz makrolarda mesaj oluştuğunda çağrılacak fonksiyonun ismi makronun içerisinde belirlenmiştir. Programcı da çağrılacak bu üye fonksiyonu belirtilen bu isimde yazmak zorundadır. Parametreli mesaj makrolarında çağrılacak üye fonksiyonların isimleri makro parametresi olarak belirtilir. Yani programcı çağrılacak fonksiyonun ismini kendisi belirleyebilir. Parametresiz makrolar genel pencere mesajlarına ilişkindir. Parametreli makrolar ise kontrollerin gönderdiği mesajlar işlenir.

Sınıfın üye fonksiyonları CWnd::OnWndMsg tarafından çağrılacağına göre parametrik yapıları da önceden belirlenmiştir. Yani makro ister parametreli ister parametresiz olsun çağrılacak üye fonksiyonun parametrik yapısı önceden belirlenmiştir ve programcı bu belirlemeye uymak zorundadır. Örneğin farenin sol tuşuna basıldığında çağrılacak üye fonksiyonu yazmak isteyelim. Bunun için kullanılacak mesaj makrosu ON_WM_LBUTTONDOWN() biçimindedir ve biz üye fonksiyonu aşağıdaki prototipe uygun olarak yazmak zorundayız.

void OnLButtonDown(UINT CPoint);

Bir sınıfın bir mesaj oluştuğunda çağrılacak üye fonksiyonu bildirilirken prototipin önüne geleneksel olarak afx_msg sembolik sabiti yerleştirilir. Bu sembolik sabit önişlemci tarafından silinmektedir. Böylelikle bir sınıfın üye fonksiyonunun prototip önünde afx_msg görüldüğünde bu üye fonksiyonun mesaj oluştuğunda çağrılacak bir üye fonksiyon olduğu hemen tespit edilebilir. Bu sembolik sabit yalnızca prototipin önünde kullanılmaktadır.

2001-10-30 Perşembe

2.2 Mesaj Haritalarına İlişkin Anahtar Notlar1) Mesaj haritası kurmak için CWnd sınıfından türetilmiş sınıfın bildirimi içerisine DECLARE_MESSAGE_MAP() makrosunu yerleştirmek ve global düzeyde bu sınıf için BEGIN_MESSAGE_MAP ve END_MESSAGE_MAP makrolarını yerleştirmek gerekir.

2) Mesaj makroları aslında mesaj harita dizisine ilk değer verme işlemi yapmaktadır.

3) Mesaj makroları parametreli ya da parametresiz olabilir. Parametresiz olanlar genel pencere mesajlarına ilişkindir. ON_WM_XXX biçiminde isimlendirilmiştir. Parametresiz mesaj makrolarında mesaj oluştuğunda çağrılacak üye fonksiyonun ismi makronun içerisinde kodlandığı için bu üye fonksiyonları belirlenen isimlerle yazmak zorundayız. Parametreli mesaj makroları genellikle kontrollere ilişkindir. Burada çağrılacak üye fonksiyonun ismi programcı tarafından belirlenir.

4) Mesaj oluştuğunda çağrılacak fonksiyonlar kolay bir biçimde tespit edilebilsin diye prototiplerinin başına afx_msg makrosu yerleştirilir. Bu boş bir makrodur.

5) Mesaj makrolarına ilişkin fonksiyonların parametrik yapıları önceden belirlenmiştir.

17

Page 18: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

2.3 CWnd::MessageBox FonksiyonuCWnd sınıfının MessageBox üye fonksiyonu default argümanlara sahip olduğu için kullanılması kolay bir fonksiyondur.

int MessageBox(LPCTSTR lpszText, LPCTSTR lpszCaption = NULL, UINT nType = MB_OK);Sınıf Çalışması

İskelet MFC programını kullanarak ana pencerede farenin sol tuşuna basıldığında MessageBox fonksiyonu ile bir mesaj yazdırınız.

MESSAGEBOX.H

#ifndef _MESSAGEBOX_H_#define _MESSAGEBOX_H_

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

DECLARE_MESSAGE_MAP()};

#endifMESSAGEBOX.CPP

#include <afxwin.h>#include "messagebox.h"

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_LBUTTONDOWN()END_MESSAGE_MAP()

CMainWnd::CMainWnd(void){

Create(NULL, "LbuttonDown Uygulaması", WS_OVERLAPPEDWINDOW);}

void CMainWnd::OnLButtonDown(UINT nFlags, CPoint point){

MessageBox("Mouse un Sol tuşuna basabildiniz");}

2.4 Point Yapısı ve CPoint SınıfıCPoint sınıfı MFC içerisinde kullanılan utility bir sınıftır. Pencere mekanizmasıyla bir ilgisi yoktur. Bir noktayı temsil eder. CPoint sınıfı POINT yapısından türetilmiştir. typedef struct tagPOINT { LONG x; LONG y;} POINT;

18

Page 19: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

class CPoint : public tagPoint {// .....

};

CPoint sınıfının veri elemanı yoktur. Zaten taban sınıfının x ve y elemanlarını kullanarak işlemlerini yapar. CPoint sınıfının noktasal işlem yapan faydalı operatör fonksiyonları vardır.

Sınıfın başlangıç fonksiyonları şunlardır:CPoint();

CPoint(int x, int y);

CPoint(POINT pt);

Sınıfın karşılaştırma operatör fonksiyonları şunlardır:

BOOL CPoint::operator ==(POINT pt) const;

BOOL CPoint::operator !=(POINT pt) const;

CPoint sınıfının aritmetik operatör fonksiyonları şunlardır:

CPoint::operator +(POINT pt) const;

CPoint::operator -(POINT pt) const;

CPoint::operator +=(POINT pt) const;

CPoint::operator -=(POINT pt) const;

CPoint sınıfının başka üye fonksiyonları da vardır.

2.5 RECT Yapısı ve CRect SınıfıCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan bir sınıftır. typedef struct tagRECT {LONG left;LONG top; LONG right; LONG bottom;} RECT;

class CRect : public tagRECT {// .....};

Görüldüğü gibi CRect sınıfı da RECT yapısından türetilmiştir.

Sınıfın başlangıç fonksiyonları şunlardır:

CRect();

CRect(int l, int t, int r, int b);

CRect(const RECT &rect);

CRect(POINT topLeft, POINT bottomRight)

CRect sınıfı özellikle CWnd::Create fonksiyonunda RECT & parametresini karşılamak amacıyla kullanılır. Örneğin:wnd.Create(....., CRect(10, 10, 20, 30), .....);CRect türünden nesne yoluyla sınıfın veri elemanlarına erişilebilir. CRect sınıfı yalnızca koordinatlar üzerinde aritmetik işlemler yapan bir sınıftır. Faydalı üye fonksiyonlarından bazıları şunlardır:

19

Page 20: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

int CRect::Height() const;

int CRect::Width() const;

Bu fonksiyonlar dikdörtgenin yüksekliğini ve genişliğini bulur.BOOL CRect::IsRectEmpty() const;

BOOL CRect::IsRectNull() const;

Bu fonksiyonlar bölgenin alansal olarak boş olduğunu ve tamamen 0 değerlerinden oluştuğunu bulmaya çalışır. BOOL CRect::PtInRect(POINT point) const;Bir noktanın dikdörtgenin içerisinde olup olmadığını bulur.

Sınıfın en fazla kullanılan üye fonksiyonlarından ikisi InflateRect ve DeflateRect fonksiyonlarıdır. Inflate işlemi bir dikdörtgeni sol üst ve sağ alt köşegenlerinden açmayı, deflate işlemi ise büzmeyi anlatır. Bu fonksiyonların pek çok biçimi vardır.

void CRect::InflateRect(int x, int y);

void CRect::DeflateRect(int x, int y);

Fonksiyonun x ve y parametreleri açım değerleridir. Genellikle x ve y değerleri birbirine eşit alınır. Bu parametreler negatif olabilir. O zaman büzmek anlamına gelir. Zaten InflateRect ile DeflateRect arasında yalnızca işaret farkı vardır. Dikdörtgenin sol üst ve sağ alt köşesinin koordinatları TopLeft ve BottomRight fonksiyonlarıyla elde edilebilir:CPoint &TopLeft();CPoint &BottomRight();

Sınıfın RECT türünden adrese dönüşüm yapan bir tür dönüştürme operatör fonksiyonu vardır. Bu fonksiyon sayesinde LPRECT parametresi isteyen API fonksiyonlarına kolay parametre verilebilir. Şüphesiz bu operatör fonksiyonu kendi veri elemanlarının başlangıç adresiyle geri dönmektedir.

CRect::operator LPRECT();

Bunların yanı sıra iki CRect nesnesi için ==, +=, -=, +, - gibi aritmetik operatör fonksiyonları da tanımlanmıştır. CRect sınıfının başka üye fonksiyonları da vardır.

2.6 CWnd::GetClientRect FonksiyonuBilindiği gibi GetClientRect API fonksiyonu RECT türünden bir yapının adresini alarak çalışma alanının koordinatlarını bu yapıya yerleştirir. Bu fonksiyonla alınan koordinatların sol üst köşesi her zaman (0, 0) biçimindedir. CWnd::GetClientRect fonksiyonu da bu API fonksiyonunu çağırarak işlemini yapar. void CWnd::GetClientRect(LPRECT lpRect) const;

Pencerenin çalışma alanının koordinatlarını CRect türünden bir sınıf içerisine çekip bu sınıfın üye fonksiyonlarıyla hızlı bir biçimde koordinat dönüşümü yapabiliriz. Örneğin:CRect rect;

GetClientRect(rect);rect.InflateRect(-100, -100);edit.Create(....., rect, .....);

//0,0,100,100 koordinatları içine mousla tıklandığında, mous koordinatlarını // mesajbox ile gösteren program//lbuttondown.h

20

Page 21: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

#ifndef _LBUTTON_H_#define _LBUTTON_H_

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

DECLARE_MESSAGE_MAP()};

#endif // Multiple include checker!

//lbuttondown.cpp#include <afxwin.h>#include "lbutton.h"

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "LButton Uygulamasi");}

void CMainWnd::OnLButtonDown(UINT nFlags, CPoint point){

CRect rect(0, 0, 100, 100);char buf[100];

if (rect.PtInRect(point)) {sprintf(buf, "x = %d\ty = %d", point.x, point.y);MessageBox(buf);

}}

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_LBUTTONDOWN()END_MESSAGE_MAP()

2001-11-01 Perşembe

21

Page 22: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3 KONTROL SINIFLARICFrameWnd, CButton, CListBox, CEdit, .......--> CWnd

MFC'de kontroller CWnd sınıfından türetilmiş sınıflarla temsil edilmektedir. Örneğin push button kontrolü CButton sınıfı ile, list box kontrolü CListBox sınıfı ile, edit box kontrolü ise CEdit sınıfı ile temsil edilmiştir.

Anımsatma : Kontroller aslında birer alt penceredir ve CreateWindow API fonksiyonuyla yaratılırlar. Kontrol yaratmakta kullanılan WNDCLASS isimleri Windows yüklenirken global düzeyde register ettirilmiştir. Kontrollere ilişkin pencere fonksiyonları Windows tarafından ilk elden yazılmış olup USER32.DLL içerisine yerleştirilmiştir. Yani bir kontrol üzerinden işlem yapıldığında mesajlar thread'in ana mesaj kuyruğuna bırakılır. Mesaj dispatch edildiğinde kontrole ilişkin pencere fonksiyonu tarafından işlenir. Bir kontrol yaratıldıktan sonra SendMessage fonksiyonu ile mesaj göndererek kontrole çeşitli işlemler yaptırılabilir. Kontrollerin pencere fonksiyonları işletim sistemine ilişkin olduğuna göre bir push button üzerine click yapıldığında click mesajı da kontrolün pencere fonksiyonu tarafından işlenecektir. Peki kontrolü yaratan kişi olaydan nasıl haberdar olacaktır? İşte kontroller bir olay gerçekleştiğinde üst pencereye WM_COMMAND mesajını SendMessage ile gönderirler. WM_COMMAND mesajının parametreleri şöyledir:

HIWORD(wParam)--> Mesajın nedeni (notification code)

LOWORD(wParam)--> Kontrolün ID değeri

LParam --> Kontrolün handle değeri

MFC'de bir kontrol yaratmak için önce kontrol sınıfı türünden bir nesne tanımlanır. Sonra kontrolün Create fonksiyonu ile pencere yaratılır. Her kontrol sınıfının Create fonksiyonu vardır. Aslında bu Create fonksiyonları CWnd::Create fonksiyonunu kontrole ilişkin sınıf ismiyle çağırır. Tabii CWnd::Create fonksiyonu da CreateWindow API fonksiyonuyla kontrolü yaratacaktır. Pencere yaratıldıktan sonra kontrolün handle değeri kontrol sınıfının CWnd kısmının m_hWnd elemanında saklanır.

Tıpkı CWnd sınıfında olduğu gibi yerel bir kontrol nesnesiyle pencere yaratılırsa faaliyet alanı bittiğinde çağrılan bitiş fonksiyonu pencereyi kapatacaktır. Bu nedenle nesneyi dinamik olarak yaratmak ya da nesneyi üst pencereye ilişkin sınıfın veri elemanı olarak yaratmak uygun olur.

Kontrol üzerinde işlemler yapmak için kontrol sınıflarının çeşitli üye fonksiyonları vardır. Aslında bu üye fonksiyonlar SendMessage ile kontrole uygun mesajı göndermekten başka bir şey yapmazlar. Bu durumda bir kontrole işlem yaptırmak için API programlamada olduğu gibi kontrole mesajlar göndermek yerine kontrolün uygun üye fonksiyonunu çağıracağız.

Anımsatma : API programlamada bir alt pencere ya üst pencere yaratıldıktan sonra herhangi bir zaman ya da üst pencerenin pencere fonksiyonu içerisinde WM_CREATE mesajında yaratılır.

3.1 MFC' de Kontrollerin Yaratılma İşlemiMFC' de tıpkı API programlamada olduğu gibi kontroller iki yerde yaratılabilir. Kontrol nesneleri kontrol nasıl yaratılmış olursa olsun sınıfın veri elemanı biçiminde tutulmalıdır. Böylelikle bütün üye fonksiyonlar içerisinden erişilebilir. O halde iki durum söz konusudur:

1- Kontrol nesnesini gösterici veri elemanı olarak almak.

2- Kontrol nesnesini normal bir veri elemanı olarak almak.

22

Page 23: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3.2 Statik KontrolStatik kontrol MFC'de CStatic sınıfıyla temsil edilir. Birkaç üye fonksiyonu vardır. Statik kontrolün Create fonksiyonu şöyledir:

BOOL Create(LPCTSTR lpszText, DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID = 0xffff);

Tipik bir statik kontrol iskelet MFC programına şöyle yaratılabilir:

1) CMainWnd sınıfı içerisinde bir veri elemanı alınır.

2) Ana pencere yaratıldıktan sonra ya da ana pencerenin WM_CREATE mesajında statik kontrol yaratılabilir.

Sınıf Çalışması

Ana pencerenin sol üst köşesinde bir statik kontrol yaratınız. Sonra farenin sol tuşuna basıldığında basılma koordinatlarını statik kontrol içerisinde gösteriniz. Sırasıyla statik kontrolü ana pencereden sonra ve WM_CREATE mesajı içerisinde yaratmayı deneyiniz. Ayrıca statik kontrol nesnesini normal bir nesne ya da gösterici biçiminde tanımlayarak denemeler yapınız.

STATIC.H

#ifndef _STATIC_H_#define _STATIC_H_

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);private:

CStatic m_text;public:

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnLButtonDown(UINT key, CPoint point);

DECLARE_MESSAGE_MAP()};

#endifSTATIC.CPP

#include <afxwin.h>#include "static_control.h"

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "static_control", WS_OVERLAPPEDWINDOW, CRect(100,100, 500,300));}

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

23

Page 24: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

m_text.Create("x=0 y=0", WS_CHILD | WS_VISIBLE, CRect(0, 0, 200, 30), this);return 0;

}

void CMainWnd::OnLButtonDown(UINT nFlags, CPoint point){

char buf[100];

wsprintf(buf, "x = %4ld y = %4ld ", point.x, point.y);m_text.SetWindowText(buf);

}BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_CREATE()ON_WM_LBUTTONDOWN()END_MESSAGE_MAP()------------------------------------------------nesne dinamik tahsisatla yapılsaydı, yukarıdaki örnek için;#ifndef _GENMFC_H_#define _GENMFC_H_

class CGenericApp: public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd{public:

CMainWnd(void);CStatic *m_text;//nesne adres olarak tanımlanıyor

private:DECLARE_MESSAGE_MAP()

public:afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

};

#endif

#include <afxwin.h>#include "static_control.h"

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "static_control", WS_OVERLAPPEDWINDOW, CRect(100,100, 500,300));}

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

m_text = new CStatic();//Cstatic nesnesi dinamik tahsis ediliyorm_text->Create("x=0 y=0", WS_CHILD | WS_VISIBLE, CRect(0, 0, 200, 30), this);return 0;

}

void CMainWnd::OnLButtonDown(UINT nFlags, CPoint point){

char buf[100];

wsprintf(buf, "x = %4ld y = %4ld ", point.x, point.y);m_text->SetWindowText(buf);

24

Page 25: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

}

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_CREATE()ON_WM_LBUTTONDOWN()END_MESSAGE_MAP()

3.3 WM_SIZE Mesajının İşlenmesiBilindiği gibi WM_SIZE mesajı pencerenin boyutu değiştirildiğinde ve pencere ilk kez yaratıldığında gönderilmektedir. MFC'de bu mesaj ON_WM_SIZE( ) makrosu ile işlenir ve aşağıdaki üye fonksiyon ile işlenir:

afx_msg void OnSize(UINT nType, int cx, int cy);

nType parametresi pencerenin maksimize, minimize gibi özel durumlarını bildirir. cx ve cy parametreleri pencerenin yeni genişlik ve uzunluğunu belirtir. WM_SIZE mesajı özellikle bir kontrolün dinamik büyütülüp küçültülmesini sağlamak amacıyla sağlanır. Örneğin aşağıdaki kodda bir statik kontrol bu biçimde büyütülüp küçültülmektedir.

Kontrolü genişletip daraltmak için CWnd::MoveWindow kullanılabilir. Bu fonksiyonun farklı parametreli iki versiyonu vardır.

void CMainWnd::OnSize(UINT nType, int cx, int cy){

CRect rect(0, 0, cx, cy);rect.InflateRect(-50, -50);MoveWindow(rect);

}

2001-11-06 Salı

3.4 Push Button KontrolüBilindiği gibi API düzeyinde push button kontrolü CreateWindow fonksiyonu ile "button" sınıf ismi kullanılarak BS_PUSHBUTTON pencere biçiminin de eklenmesiyle yaratılır. Oysa MFC'de CButton isimli sınıf bütün push button işlemlerini yapmaktadır. CButton sınıfının Create fonksiyonu push button kontrolünü yaratır. Ayrıca BS_PUSHBUTTON pencere biçiminin eklenmesine gerek yoktur. Örneğin tipik bir push button kontrolü şöyle yaratılabilir:

m_pButton = new CButton;m_pButton->Create("calculate", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(10, 10, 100, 100), this, ID_BUTTON);

CButton sınıfının yararlı bazı üye fonksiyonları vardır. Bu üye fonksiyonlar push button kontrolüne BM_XXX mesajlarını göndererek işlemlerinin yapar. Örneğin SetCheck fonksiyonu kontrole basılma hareketini yaptırır. SetIcon fonksiyonu ya da SetBitmap fonksiyonu kontrol üzerine istediğimiz icon ve bitmap görüntülerinin basılmasını sağlar. Push button kontrolü üzerine click yapılıp el çekildiğinde üst pencereye WM_COMMAND mesajı gönderir. Mesajın parametreleri şöyledir:

HIWORD(wParam) -->Mesajın nedeni. ( Click için BN_CLICKED )LOWORD(wParam)-->Alt pencere ID değeriLParam -->Alt pencere handle değeri

Ayrıca push button kontrolü üzerine double click yapıldığında da WM_COMMAND mesajını BN_DOUBLECLICK koduyla göndermektedir. Ancak push button kontrolüne double click yapılması rastlanan bir durum değildir. Push button kontrolü üst pencereye WM_COMMAND mesajını el fareden çekildiği zaman (WM_LBUTTONUP mesajı ile) gönderir. CButton sınıfı check box ve radio button kontrollerini yaratmak için de kullanılır. Eğer bu kontroller yaratılacaksa BS_CHECKBOX ya da BS_RADIOBUTTON pencere biçimleri eklenmelidir (push

25

Page 26: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

button kontrolü için BS_PUSHBUTTON default olarak alınmaktadır. Ancak bu default durumun dökümante edilmemişse BS_PUSHBUTTON pencere biçiminin eklenmesi tavsiye edilir).

Kontrollerin gönderdiği WM_COMMAND mesajını işleyebilmemiz için ne yapmamız gerekir?

3.5 WM_COMMAND Mesajının MFC' de İşlenmesiMFC mesaj işleme işlemleri anımsanacağı gibi aşağıdaki biçimde olmaktadır:

AfxWndProc AfxCallWndProc WindowProc OnWndMsg Mesaj Haritası

CWnd::OnCommandCWnd::OnNotify

WM_COMMAND mesajı için OnCommand sanal fonksiyonunun çağrıldığını biliyoruz. Biz OnCommand sanal fonksiyonunu yazmazsak CWnd::OnCommand çağrılacaktır (aslında biz yazsak da ileride anlatılacak olan olayların devam edebilmesi için CWnd sınıfının OnCommand fonksiyonunu da çağırmalıyız). Bu durumda kontrollerden gelen WM_COMMAND mesajlarının ilk işleneceği yer OnCommand fonksiyonudur. Tabii OnCommand içerisinde mesajın hangi kontrolden geldiği tıpkı API' de olduğu gibi wParam parametresi ile tespit edilmelidir. O halde bir push button kontrolüne click yapıldığı OnCommand fonksiyonu içerisinde şöyle tespit edilebilir:

BOOL CMainWnd::OnCommand(WPARAM wParam, LPARAM lParam){

if (LOWORD(wParam) == ID_BUTTON && HIWORD(wParam) == BN_CLICKED) {// .....

}return CWnd::OnCommand(wParam, lParam);}

CWnd::OnCommand fonksiyonu kendi içerisinde CCmdTarget::OnCmdMsg sanal fonksiyonunu çağırır. OnCmdMsg fonksiyonu document/view uygulamalarında "message routing" işlemlerini yapmaktadır. CWnd sınıfının default OnCmdMsg fonksiyonu ise mesaj haritasına WM_COMMAND mesajları için bakar.

Özetle CWnd::OnCommand fonksiyonu CCmdTarget::OnCmdMsg sanal fonksiyonunu çağırır. Bu fonksiyon da CWnd sınıfı için yazılmıştır ve mesaj haritasındaki WM_COMMAND mesajlarını işler. Bu durumda MFC mesaj işleme işlemleri tam olarak aşağıdaki gibi yapılmaktadır:

AfxWndProc AfxCallWndProc WindowProc OnWndMsg Mesaj Haritası

CWnd::OnCommand

CcmdTarget::OnCmdMsg

Mesaj haritasına WM_COMMAND

Mesajları

3.6 ON_COMMAND Mesaj MakrosuWM_COMMAND mesajını mesaj haritası ile işlemek için kullanılan en genel mesaj makrosu ON_COMMAND makrosudur. ON_COMMAND makrosu iki parametreli bir makrodur. Birinci parametre LOWORD(wParam) ile belirtilen ID değeri, ikinci parametre çağrılacak fonksiyondur. Çağrılacak üye fonksiyonun geri dönüş değeri void ve parametresi void olmak zorundadır. CWnd::OnCmdMsg mesaj haritasında bütün ON_COMMAND makrolarını inceler. Mesajın LOWORD(wParam) parametresi makrodaki ID değeriyle uyuşuyorsa fonksiyonu çağırır. Bu makro kontrolden gelen mesajlar için değil de menüden gelen mesajlar için kullanılmalıdır. Çünkü makroda belirtilen fonksiyon çağrıldığında HIWORD(wParam) değeri herhangi bir biçimde olabilir. Yani biz kontrolde ne yapıldığını bilemeyebiliriz.

26

Page 27: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3.7 Kontrollere Özgü WM_COMMAND MakrolarıKontrollerde oluşan mesajları işlemek için kontrollere özgü mesaj makroları vardır. Bu mesaj makrolarının hepsi iki parametrelidir. Birinci parametreleri kontrolün ID değeri, ikinci parametreleri çağrılacak fonksiyondur. Çağrılacak fonksiyonun geri dönüş değeri ve parametresi void olmak zorundadır. Örneğin ID_BUTTON ID değerine sahip bir push button kontrolüne click yapıldığında OnButtonClick isimli üye fonksiyonun çağrılmasını isteyelim. Mesaj makrosu şöyle yazılacaktır:

ON_BN_CLICKED(ID_BUTTON, OnButtonClick)

Burada olduğu gibi her türlü kontrol için ve her türlü işlem için özel bir WM_COMMAND mesaj makrosu vardır.

ON_COMMAND ve bütün kontrol makroları mesaj harita dizisine aslında WM_COMMAND mesajını yerleştirmektedir. Ancak ON_COMMAND makrosunda HIWORD(wParam) koşulu aranmaz. Halbuki kontrollere özgü makrolarda HIWORD(wParam) kontrolü de yapılmaktadır.

Sınıf Çalışması

İskelet MFC programını kullanarak pencerenin sol üst köşesine "Ok" yazılı bir push button yerleştiriniz. Bu push button'a click yapıldığında MessageBox fonksiyonu ile durumu bildiriniz. Bu işlemi önce ON_BN_CLICKED mesaj makrosu ile, sonra OnCommand sanal fonksiyonu ile, sonra da her ikisiyle işleyiniz.

PUSHBUTTON1.H

#ifndef _PUSHBUTTON_H_#define _PUSHBUTTON_H_

#define ID_BUTTON 100

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);private:

CButton m_button;public:

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnButtonClick();

DECLARE_MESSAGE_MAP()};

#endifPUSHBUTTON1.CPP

#include <afxwin.h>#include "pushbutton1.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_CREATE()ON_BN_CLICKED(ID_BUTTON, OnButtonClick)

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

27

Page 28: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

}

CMainWnd::CMainWnd(void){

Create(NULL, "Generic MFC Application", WS_OVERLAPPEDWINDOW);}

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

m_button.Create("Ok", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(10, 10, 100, 40), this, ID_BUTTON);

return 0;

}

void CMainWnd::OnButtonClick(){

MessageBox("Push button'a click yapıldı");}2001-11-08 perşembe

3.8 ON_CONTROL MakrosuWM_COMMAND mesajına ilişkin bir makro da ON_CONTROL makrosudur. Bu makro üç parametrelidir.

ON_CONTROL(nNotificationCode, nID, Func)

Bu makroyla belirtilen fonksiyon

HIWORD(wParam) = nNotificationCode

LOWORD(wParam) = nID

olduğunda çağrılır. Bu durumda toplam üç çeşit WM_COMMAND makrosu vardır.

1) ON_COMMAND: ID uyuşumu gerçekleştiğinde belirtilen fonksiyon çağrılır.

2) ON_CONTROL: Hem ID hem de notification code uyuştuğunda belirtilen fonksiyon çağrılır.

3) Kontrole özgü mesaj makroları: Bu makrolarda zaten makronun ismi hangi notification code gerçekleştiğinde fonksiyonun çağrılacağını anlatır. Notification code zaten makro ismiyle belirlendiğine göre bu makrolar iki parametre alırlar. Aslında kontrollere özgü mesaj makroları ON_CONTROL makrosu kullanarak oluşturulmuş birer makrodur. Örneğin:

#define ON_BN_CLICKED(id, Func) ON_CONTROL(BN_CLICKED, (id), (Func))

Burada sözü edilen üç tür mesaj makrosu da CWnd::OnCommand fonksiyonunun çağırdığı CCmdTarget::OnCmdMsg fonksiyonu tarafından ele alınır. Yani biz OnCommand sanal fonksiyonunu yazıp CWnd::OnCommand fonksiyonunu çağırmazsak bu mesaj makrolarının hiçbir tanesi işlem görmeyecektir.

3.9 EDIT BOX KontrolüBilindiği gibi edit box kontrolü CreateWindow fonksiyonu ile "edit" sınıf ismi kullanılarak yaratılır. Pencere başlığı olarak belirtilen yazı başlangıçta edit kontrolünün içerisine yerleştirilir. Edit box kontrolünün ES_XXX ile isimlendirilen bir grup özel pencere biçimi vardır. Bu pencere biçimlerinin bazıları şunlardır:

ES_LOWERCASE, ES_UPPERCASE: Sürekli büyük harf ya da küçük harf yazımı sağlar.

ES_LEFT, ES_RIGHT , ES_CENTER: Hizalama işlemini sağlar.

ES_MULTILINE : Edit box default tek satırlıdır, çok satırlı yapmak için kullanılır.

28

Page 29: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

ES_AUTOHSCROLL, ES_AUTOVSCROLL: Sağa ve aşağı scroll işlemlerinin gerçekleştirirler.

ES_PASSWORD : Yazı yazıldıkça * karakterini basarak yazılan yazıyı göstermez.

Standart edit box kontrolü en fazla 64K'lık bir bilgi üzerinde işlem yapabilmektedir.

MFC'de edit box kontrolü CEdit sınıfıyla temsil edilmiştir. Dolayısıyla kontrol de CEdit::Create fonksiyonuyla yaratılır.

BOOL CEdit::Create(DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID);

Edit box işlemleri için API programlamada olduğu gibi kontrole mesaj göndermeye gerek yoktur. Zaten CEdit kontrolü bu mesajları göndererek işlem yapan çeşitli üye fonksiyonlara sahiptir.

3.10 CEdit Sınıfının Üye FonksiyonlarıCEdit sınıfının üye fonksiyonları edit box kontrolüne EM_XXX mesajları göndererek işlemlerini yapar.

3.10.1 CEdit::GetLine FonksiyonuBu fonksiyon EM_GETLINE mesajını edit kontrolüne göndererek belirli bir satırdaki yazıyı elde eder. GetLine fonksiyonunun iki biçimi vardır:

int CEdit::GetLine(int nIndex, LPTSTR lpszBuffer) const;int CEdit::GetLine(int nIndex, LPTSTR lpszBuffer, int nMaxLength) const;

Her iki fonksiyon da NULL karakteri dizinin sonuna eklemez. Her iki fonksiyonun da geri dönüş değeri buffer'a yerleştirilen karakter sayısıdır. Fonksiyonların ilk parametresi hangi satırdaki yazının alınacağını belirtir. Tek satırlı edit kontrolü için bu parametre ihmal edilebilir. API programlamada bu işlem tipik olarak şöyle yapılmaktadır:

*(WORD *)buf = n;count = SendMessage(hEdit, EM_GETLINE, line, (LONG)buf);buf[count] = '\0';

Görüldüğü gibi yazının çekileceği dizinin ilk WORD elemanı dizi uzunluğunu içermektedir. CEdit::GetLine fonksiyonunun ikinci biçiminde bu otomatik olarak yapılır. Bu durumda örneğin edit box içerisindeki satır şöyle elde edilebilir:

char buf[SIZE];int n;

n = pEdit->GetLine(0, buf, SIZE - 1);buf[n] = '\0';

Edit kontrolü içerisindeki yazının tümü GetWindowText API fonksiyonuyla alınabilir. Bu API fonksiyonunun CWnd::GetWindowText biçimi de vardır. Anımsanacağı gibi GetWindowText API fonksiyonu şöyledir:

int CWnd::GetWindowText(HWND hWnd, LPTSTR lpstring, int nMaxCount);

CWnd::GetWindowText ise şöyledir:

int CWnd::GetWindowText(LPTSTR lpszStringBuf, int nMaxCount) const;

Bu durumda edit box içerisindeki tüm yazı şöyle alınabilir:

char buf[SIZE];pEdit->GetWindowText(buf, SIZE - 1);

29

Page 30: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3.10.2 CEdit::GetLineCount FonksiyonuBu fonksiyon edit kontrolüne EM_GETLINECOUNT mesajını göndererek toplam satır sayısını alır.

int CEdit::GetLineCount() const;

3.10.3 CEdit::LineIndex ve CEdit::LineLength FonksiyonlarıBilindiği gibi edit box kontrolünde her karakterin ilk karakter 0 olmak üzere bir pozisyon numarası vardır. Bir satırın ilk karakterinin pozisyon numarası API düzeyinde EM_LINEINDEX mesajı gönderilerek elde edilir. Bir satırdaki karakter sayısı da bu pozisyon numarası kullanılarak EM_LINELENGTH mesajıyla elde edilir. Her iki mesajda da satır numarası –1 biçiminde girilirse cursor'ın bulunduğu satır üzerinde işlem yapılır. Benzer biçimde bu işlemler CEdit sınıfından iki üye fonksiyon ile yapılır.

int CEdit::LineIndex(int nLine = -1) const;

int CEdit::LineLength(int nLine = -1) const;

Bu işlem şöyle yapılabilir:

char buf[SIZE];int pos, nCount;

pos = pEdit->LineIndex(n);nCount = pEdit->LineLength(pos);

3.10.4 Edit Box Kontrolünde Seçme ve Insert İşlemleriBelirli bir bölgeyi seçmek seçilmiş bölgenin pozisyon numaralarını almak, seçilmiş bölgedeki yazıyı başka bir yazıyla değiştirmek gibi işlemler mesajlar gönderilerek yapılır. CEdit sınıfında bu mesajları gönderen SetSel, GetSel, ReplaceSel gibi üye fonksiyonlar vardır.

void CEdit::SetSel(DWORD dwSelection, BOOL bNoScroll = FALSE);

void CEdit::SetSel(int nStartChar, int nEndChar, BOOL bNoScroll = FALSE);

DWORD GetSel( ) const;

void GetSel(int& nStartChar, int& nEndChar) const;

void ReplaceSel(LPCTSTR lpszNewText, BOOL bCanUndo = FALSE);

Edit box kontrolünün sonuna yazı eklemek için iki yöntem uygulanabilir:

1) GetWindowText ile tüm yazı alınır, ekleme yapılır. Sonra SetWindowText ile tekrar kontrole yerleştirilir. Ancak bu yöntemde scroll çubuğu yazının başında olur. Bu durum genellikle istenmez.

2) Yazının tamamı alınır, eklemeler yapılır, sonra yazının tamamı SetSel fonksiyonuyla seçilir (yazının tamamını seçmek için start = 0, end = -1 özel değerleri kullanılmalıdır). ReplaceSel ile eklenmiş yazı insert edilir. Bu durumda scroll çubuğu yine edit kontrolünün sonunda kalır.

3.10.5 CEdit Sınıfının Diğer Üye FonksiyonlarıSetModify ve GetModify fonksiyonları kontrol içerisindeki yazının güncellenmesiyle ilgili bilgi verir. SetLimitText edit kontrolü içerisindeki yazının uzunluğunu sınırlar. GetLimitText bu uzunluğu alır. SetReadOnly edit box kontrolünü read-only yapar (kontrol ES_READONLY pencere biçimiyle de yaratılabilir).

void SetModify(BOOL bModified = TRUE);

30

Page 31: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

BOOL GetModify( ) const;

UINT GetLimitText( ) const;

void SetLimitText(UINT nMax);

Sınıf Çalışması

İskelet MFC programını kullanarak ana pencerenin içinde bir tane çok satırlı edit kontrolü, bir tane de push button kontrolü yaratınız. Push button üzerine click yapıldığında edit box içerisindeki yazıyı MessageBox ile yazdırınız.

2001-11-13 salı

31

Page 32: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3.11 CString SINIFIConstruction CString Class MembersCString Constructs CString objects in various ways.The String as an Array GetLength Returns the number of characters in a CString object. For multibyte characters, counts each 8-

bit character; that is, a lead and trail byte in one multibyte character are counted as two characters.

IsEmpty Tests whether a CString object contains no characters.Empty Forces a string to have 0 length.GetAt Returns the character at a given position.operator [] Returns the character at a given position — operator substitution for GetAt.SetAt Sets a character at a given position.operator LPCTSTR Directly accesses characters stored in a CString object as a C-style string.Assignment/Concatenation operator = Assigns a new value to a CString object.operator + Concatenates two strings and returns a new string.operator += Concatenates a new string to the end of an existing string.Comparison operator == <, etc. Comparison operators (case sensitive).Compare Compares two strings (case sensitive).CompareNoCase Compares two strings (case insensitive).Collate Compares two strings (case sensitive, uses locale-specific information).CollateNoCase Compares two strings (case insensitive, uses locale-specific information).Extraction Mid Extracts the middle part of a string (like the Basic MID$ function).Left Extracts the left part of a string (like the Basic LEFT$ function).Right Extracts the right part of a string (like the Basic RIGHT$ function).SpanIncluding Extracts a substring that contains only the characters in a set.SpanExcluding Extracts a substring that contains only the characters not in a set.Other Conversions MakeUpper Converts all the characters in this string to uppercase characters.MakeLower Converts all the characters in this string to lowercase characters.MakeReverse Reverses the characters in this string.Replace Replaces indicated characters with other characters.Remove Removes indicated characters from a string.Insert Inserts a single character or a substring at the given index within the string.Delete Deletes a character or characters from a string.Format Format the string as sprintf does.FormatV Formats the string as vsprintf does.TrimLeft Trim leading whitespace characters from the string.TrimRight Trim trailing whitespace characters from the string.FormatMessage Formats a message string.Searching Find Finds a character or substring inside a larger string.ReverseFind Finds a character inside a larger string; starts from the end.FindOneOf Finds the first matching character from a set.Archive/Dump operator << Inserts a CString object to an archive or dump context.operator >> Extracts a CString object from an archive.Buffer Access GetBuffer Returns a pointer to the characters in the CString.GetBufferSetLength Returns a pointer to the characters in the CString, truncating to the specified length.ReleaseBuffer Releases control of the buffer returned by GetBuffer.FreeExtra Removes any overhead of this string object by freeing any extra memory previously allocated

to the string.LockBuffer Disables reference counting and protects the string in the buffer.UnlockBuffer Enables reference counting and releases the string in the buffer.Windows-Specific AllocSysString Allocates a BSTR from CString data.SetSysString Sets an existing BSTR object with data from a CString object.LoadString Loads an existing CString object from a Windows resource.AnsiToOem Makes an in-place conversion from the ANSI character set to the OEM character set.OemToAnsi Makes an in-place conversion from the OEM character set to the ANSI character set.

CString sınıfı CObject sınıfından türememiş olan, yazılar üzerinde işlem yapmayı sağlayan yararlı bir sınıftır. CString sınıfı da başka kütüphanelerdeki string sınıfları gibi yazıları dinamik olarak tahsis edilmiş olan bir alanda saklar. Sınıfın yazının başlangıç adresini gösteren ve uzunluğunu tutan veri elemanları vardır. CString sınıfı MFC kütüphanesinde başka sınıfların arabirimlerinde (üye fonksiyonların prototiplerinde) ve tanımlamalarında kullanılmıştır. CString sınıfı bir string sınıfından beklenen bütün üye fonksiyonlara sahiptir.

32

Page 33: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3.11.1 Sınıfın Başlangıç Fonksiyonları

CString(void);

CString(const CString &r);

CString(char ch, int nRepeat = 1);

CString (const char *pStr);

CString(const char *pStr, int length);

3.11.2 Sınıfın Atama Operatör Fonksiyonları1) Sınıfın birkaç tane atama operatör fonksiyonu vardır:

const CString &CString::operator =(const CString &r);

const CString &CString::operator =(char ch);

const CString &CString::operator =(LPCSTR pStr);

2) + ve += operatör fonksiyonları CString, char, const char * parametreli olarak vardır. + operatör fonksiyonu sol ve sağ operand için ayrı ayrı yazılmıştır. + operatör fonksiyonu iki yazıyı birleştirir. += ise bir yazının sonuna başka bir yazıyı ekler.

3) Sınıfın const char * türüne dönüşüm yapan bir tür dönüştürme operatör fonksiyonu vardır. Bu operatör fonksiyonu yazının bulunduğu bölgenin adresine geri döner. Dolayısıyla CString nesnesi doğrudan const char * parametreli fonksiyonlara parametre olarak geçirilebilir.

3.11.3 Sınıfın Karşılaştırma Operatör FonksiyonlarıAltı tane karşılaştırma operatörünün hepsi operatör fonksiyonu olarak yazılmıştır. Bu operatör fonksiyonlarının CString ve const char * parametreli versiyonları vardır.

BOOL operator ==(const CString& s1, const CString& s2);

BOOL operator ==(const CString& s1, LPCTSTR s2);

BOOL operator ==(LPCTSTR s1, const CString& s2);

BOOL operator !=(const CString& s1, const CString& s2);

BOOL operator !=(const CString& s1, LPCTSTR s2);

BOOL operator !=(LPCTSTR s1, const CString& s2);

BOOL operator <(const CString& s1, const CString& s2);

BOOL operator <(const CString& s1, LPCTSTR s2);

BOOL operator <(LPCTSTR s1, const CString& s2);

BOOL operator >(const CString& s1, const CString& s2);

BOOL operator >(const CString& s1, LPCTSTR s2);

BOOL operator >(LPCTSTR s1, const CString& s2);

BOOL operator <=(const CString& s1, const CString& s2);

BOOL operator <=(const CString& s1, LPCTSTR s2);

BOOL operator <=(LPCTSTR s1, const CString& s2);

BOOL operator >=(const CString& s1, const CString& s2);

33

Page 34: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

BOOL operator >=(const CString& s1, LPCTSTR s2);

BOOL operator >=(LPCTSTR s1, const CString& s2);

3.11.4 Sınıfın Faydalı Üye Fonksiyonları

3.11.4.1 Format FonksiyonuFormat üye fonksiyonu sprintf fonksiyonu gibidir. Oluşturulan yazıyı sınıf içerisinde saklar.

void Format(LPCTSTR lpszFormat, ...);

void Format(UINT nFormatID, ...);

Örneğin:

CString str;int i = 123;

str.Format("i = %d", i);puts(str);

3.11.4.2 MakeLower, MakeUpper, MakeReverse FonksiyonlarıMakeLower yazıyı küçük harfe dönüştürür. MakeUpper yazıyı büyük harfe dönüştürür. MakeReverse ise yazıyı ters düz eder.

void MakeUpper();

void MakeLower();

void MakeReverse();

3.11.4.3 Right ve Left FonksiyonlarıYazının soldaki ve sağdaki n karakterini alarak bir cstring nesnesi biçiminde geri verir.

CString Right( int nCount ) const;

CString Left( int nCount ) const;

3.11.4.4 GetLength FonksiyonuYazının uzunluğunu bulur.

int GetLength() const;

3.11.4.4 IsEmpty FonksiyonuYazının boş olup olmadığını tespit eder.

BOOL IsEmpty() const;

3.11.4.5 Empty FonksiyonuBu fonksiyon yazıyı boş yazı haline getirir.

void Empty();

34

Page 35: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3.11.4.6 TrimLeft ve TrimRight FonksiyonlarıBu fonksiyonlar yazının sağındaki ve solundaki boşlukları atarlar.

void TrimLeft();

void CString::TrimLeft(TCHAR chTarget);

void CString::TrimLeft(LPCTSTR lpszTargets);

void TrimRight();

void CString::TrimRight(TCHAR chTarget);

void CString::TrimRight(LPCTSTR lpszTargets);

3.11.4.7 Compare FonksiyonuBu fonksiyon strcmp fonksiyonu gibi pozitif, negatif ya da sıfıra geri döner.

int Compare(LPCTSTR lpsz) const;

3.11.4.8 Find FonksiyonlarıSınıfın iki Find fonksiyonu vardır. Bunlar tek bir karakteri ve bir yazıyı aramakta kullanılır. Her ikisi de bulunan yerin index numarasına geri döner.

int Find(TCHAR ch) const;

int Find(LPCTSTR lpszSub) const;

int Find(TCHAR ch, int nStart) const;

int Find(LPCTSTR pstr, int nStart) const;

3.11.4.9 GetAt ve [ ] Operatör FonksiyonlarıSınıfın GetAt ve [ ] üye fonksiyonları belirli bir indeksteki karakteri elde etmekte kullanılır. [ ] operatör fonksiyonu referansa geri dönmediği için sol taraf değeri olarak kullanılamaz.

TCHAR GetAt(int nIndex) const

TCHAR operator [ ](int nIndex) const;

Sınıfın bunlar dışında birkaç faydalı fonksiyonu daha vardır.

3.12 CHECK BOX ve RADIO BUTTON KontrolleriCheck box ve radio button kontrolleri de API düzeyinde "button" sınıf ismi kullanılarak yaratılmaktadır. Bilindiği gibi check box ve radio button kontrolleri otomatik olanlar ve olmayanlar biçiminde iki çeşittir. MFC'de check box ve radio button kontrolleri de CButton sınıfıyla temsil edilir. Bu kontroller yaratılırken BS_CHECKBOX, BS_AUTOCHECKBOX, BS_RADIOBUTTON, BS_AUTORADIOBUTTON pencere biçimlerinden biri kullanılır:

API düzeyinde radio button ya da check box kontrollerinin işaretli olup olmadığını anlamak için kontrole BM_GETCHECK mesajı gönderilir. Programlama yoluyla işaretlemek içinse BM_SETCHECK mesajı gönderilir. Bu işlemler MFC'de CButton sınıfının GetCheck ve SetCheck üye fonksiyonlarıyla yapılabilir (BM_GETSTATE ve BM_SETSTATE push button için kullanılmaktadır).

int GetCheck() const;

35

Page 36: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void SetCheck(int nCheck);

Radio button grubunun hangisinin işaretli olduğunu anlamak için iç içe if denenebilir ya da her bir radio button'ın ID değerleri ardışıl verilerek işlem döngü içerisinde yapılabilir.

#define ID_RADIOBUTTON1 100#define ID_RADIOBUTTON2 101#define ID_RADIOBUTTON3 102#define ID_RADIOBUTTON4 103#define ID_RADIOBUTTON5 104

// .....for (i = 100; i <= 104; ++i) {

hButtonWnd = GetDlgItem(hWnd, i);if (SendMessage(hButtonWnd, BM_GETCHECK, 0, 0)) {

flag = i;break;

}}

3.13 CSize SINIFIBu sınıf tıpkı CPoint sınıfı gibi tasarlanmıştır. SIZE isimli bir yapıdan türetilmiştir.

typedef struct tagSIZE {int cx; int cy;} SIZE;

Bu sınıf genişlik ve yükseklik kavramı oluşturmak için tasarlanmıştır. Sınıfın başlangıç fonksiyonları şunlardır:

CSize(void);

CSize(int x, int y);

CSize(POINT pt);

CSize(DWORD dwSize);

Sınıfın == ve != operatör fonksiyonları karşılaştırma yapar. +, -, +=, -= operatör fonksiyonları ise genişlik ve yükseklik işlemlerini yapar.

CRect sınıfının CSize içeren başlangıç fonksiyonu alt pencere yaratmakta çok kullanışlıdır:

CRect::CRect(POINT pt, SIZE size);

Örneğin:

m_check1.Create(....., CRect(CPoint(100, 100), CSize(50, 30), .....);m_check2.Create(....., CRect(CPoint(100, 150), CSize(50, 30), .....);

// Kontrollerin kullanımı 2 uygulaması// KONTROL UYGULAMASI ctrl.h ve ctrl.cpp dosyalarindan oluşmaktadır.#ifndef _CTRL_H_#define _CTRL_H_

#define ID_EDIT_NAME 100#define ID_BUTTON_CONFIRM 101#define ID_BUTTON_MALE 102#define ID_BUTTON_FEMALE 103#define ID_BUTTON_ENGLISH 104#define ID_BUTTON_GERMAN 105#define ID_BUTTON_FRENCH 106#define ID_LIST 107

36

Page 37: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

//Application classclass CGenericApp : public CWinApp{public:

virtual BOOL InitInstance(void);};//ana pencere uygulamalariclass CMainWnd: public CFrameWnd{public:

CMainWnd(void);~CMainWnd(void);afx_msg int OnCreate(LPCREATESTRUCT lpCreate);afx_msg void OnButtonClick(void);afx_msg void OnListDblClk(void);

private:static BOOL IsAllSpace(LPCSTR pszName);

private:CStatic *m_pStaticName;CEdit *m_pEditName;CButton *m_pConfirm;CButton *m_pMale;CButton *m_pFemale;CButton *m_pEnglish;CButton *m_pGerman;CButton *m_pFrench;CListBox *m_pList;

DECLARE_MESSAGE_MAP()};#endif//CPP DOSYASI#include <afxwin.h>#include "ctrl.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_CREATE()ON_BN_CLICKED(ID_BUTTON_CONFIRM, OnButtonClick)ON_LBN_DBLCLK(ID_LIST, OnListDblClk)

END_MESSAGE_MAP()

//Global degiskenlerCGenericApp theApp;

//Class ları oluşturmaBOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd -> ShowWindow(m_nCmdShow);m_pMainWnd -> UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(){

//sınıflar icin memory tahsis ediliorm_pStaticName = new CStatic();m_pEditName = new CEdit();m_pConfirm = new CButton();m_pMale = new CButton();m_pFemale = new CButton();m_pEnglish = new CButton();m_pGerman = new CButton();m_pFrench = new CButton();m_pList = new CListBox();

//ana pencere yaratiliyorCreate(NULL, "Kontrol Uygulaması");

}

CMainWnd::~CMainWnd(void)

37

Page 38: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

{//tahsis edilen alanlar basaltiliyordelete m_pStaticName;delete m_pEditName;delete m_pConfirm;delete m_pMale;delete m_pFemale;delete m_pEnglish;delete m_pGerman;delete m_pFrench;delete m_pList;

}

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreate){

//static kontrol ve edit box yaratiliyorm_pStaticName -> Create("Adı Soyadı", WS_CHILD|WS_VISIBLE|SS_CENTER,

CRect(CPoint(150,30), CSize(175,20)), this);m_pEditName -> Create(WS_CHILD|WS_VISIBLE|WS_BORDER,

CRect(CPoint(150,50), CSize(175,20)), this, ID_EDIT_NAME);

//OK PUSH BUTTON yaratiliyorm_pConfirm->Create("Ok", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,

CRect(CPoint(300, 100), CSize(80, 80)), this, ID_BUTTON_CONFIRM);

//male/female check box yaratiliyorm_pMale->Create("E", WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON,

CRect(CPoint(50, 100), CSize(50, 30)), this, ID_BUTTON_MALE);m_pFemale->Create("K", WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON,

CRect(CPoint(100, 100), CSize(50, 30)), this, ID_BUTTON_FEMALE);

//yabanci diller icin check box yaratiliyor

m_pEnglish-> Create("İngilizce", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, CRect(CPoint(175, 100), CSize(100,30)), this, ID_BUTTON_ENGLISH);

m_pGerman-> Create("Almanca", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, CRect(CPoint(175, 130), CSize(100,30)), this, ID_BUTTON_GERMAN);

m_pFrench-> Create("Fransızca", WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, CRect(CPoint(175, 160), CSize(100,30)), this, ID_BUTTON_FRENCH);

//list box yaratiliyorm_pList->Create(WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|LBS_NOTIFY,

CRect(CPoint(50, 200), CSize(325, 200)), this, ID_LIST);

//radio button a ilk deger vermem_pMale->SetCheck(TRUE);return 0;

}

void CMainWnd::OnButtonClick(void){

//isim girmechar name[30];int count;count = m_pEditName->GetLine(0, name, sizeof(name)-1);name[count] = '\0';m_pEditName->SetWindowText("");if(IsAllSpace(name)){

MessageBox("Adı Soyadı alanı boş...!", "Error");return;

}//erkek/bayan bilgisi almaBOOL bMale;bMale = m_pMale->GetCheck();

//yabanci dil bilgisi almaCString language;if(m_pEnglish->GetCheck())

language += "İngilizce";if(m_pGerman->GetCheck())

38

Page 39: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

language += "Almanca";if(m_pFrench->GetCheck())

language += "Fransızca";if(!language.GetLength())

language= "Yabancı dil bilmiyor";

//secilenleri list box a eklemeCString item;item.Format("%s(%c)(%s)", name, bMale?'E':'K', (LPCTSTR) language);m_pList->AddString(item);

//dinamik alan temizleniyorm_pEnglish->SetCheck(FALSE);m_pGerman->SetCheck(FALSE);m_pFrench->SetCheck(FALSE);m_pMale->SetCheck(TRUE);m_pFemale->SetCheck(FALSE);

}

void CMainWnd::OnListDblClk(void){

int index;index = m_pList->GetCurSel();CString text;m_pList->GetText(index, text);CString lineInfo;lineInfo.Format("\nTotal Record:%d", m_pList->GetCount());MessageBox(text+lineInfo, "Message");

}

BOOL CMainWnd::IsAllSpace(LPCSTR pszName){

for(int i=0; pszName[i] != '\0'; ++i)if(!isspace(pszName[i]))

return FALSE;return TRUE;

}

2001-11-15 Perşembe

3.14 LIST BOX KontrolüBilindiği gibi list box kontrolü birtakım bilgileri listelemek amacıyla kullanılır. API programlamada list box kontrolü "listbox" sınıf ismiyle yaratılır. Bu kontrolün özel pencere biçimleri şunlardır:

LBS_SORT : List box'a yapılan eklemeler sıralı gözükür.

39

Page 40: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

LBS_EXTENDEDSEL : Uzatmalı seçime izin verir.

LBS_MULTIPLESEL : Birden fazla seçim yapmak için kullanılır.

LBS_NOTIFY : Default olarak list box kontrolü belirlenen işlemler gerçekleştiğinde üst pencereye WM_COMMAND mesajını göndermez. Bu mesajları göndermesi için bu pencere biçiminin eklenmiş olması gerekir.

LBS_STANDARD : Bu aslında bir sembolik sabittir. LBS_SORT | LBS_NOTIFY | WS_BORDER özelliklerinin birleşimidir.

Bu mesajların hepsi MFC'de CListBox sınıfının üye fonksiyonları biçiminde mevcuttur. List box kontrolü MFC'de CListBox sınıfıyla temsil edilir. Burada mesajlar CListBox sınıfının üye fonksiyonlarıyla açıklanacaktır. List box kontrolüne gönderilen önemli mesajlar şunlardır:

3.14.1 CListBox::AddString FonksiyonuFonksiyon yazıyı ekler ve eklediği yerin index numarasına geri döner.

Bütün fonksiyonlar başarısızlık durumunda LIST BOX_ERR ya da LIST BOX_ERRSPACE değerine geri döner. Geri dönüş değerinin kontrol edilmesine gerek yoktur.

Anahtar Notlar (Fonksiyon başarısının kontrolü) : Fonksiyon başarısının test edilme gerekliliğine göre fonksiyonları üç bölüme ayırabiliriz:

1) Başarı kontrolünün kesinlikle gerektiği fonksiyonlar. Bu tür fonksiyonların başarısı kesinlikle her çağrıldığında test edilmelidir. Bu tür fonksiyonların başarısız olma olasılıkları hem fazladır hem de programcının dışındaki faktörlere bağlı olabilir. Örneğin fopen ve malloc fonksiyonlarında olduğu gibi.

2) Başarısının testine gerek olmayan ancak problemli bir durumla karşılaşıldığında şüphe üzerine test edilmesi gereken fonksiyonlar. Bu tür fonksiyonlarda başarısızlık olasılığı çok düşüktür. Programcı normal bir kodlama yapmışsa neredeyse imkansızdır. Ya da fonksiyon başarısız olduğunda programcının yapabileceği bir şey yoktur. Örneğin fclose fonksiyonunun SetWindowText API fonksiyonunun geri dönüş değerlerini kontrol etmeye gerek yoktur.

3) Programın debug ve release versiyonları oluşturulacak bir biçimde kodlama yapılıyorsa bazı fonksiyonların başarıları yalnızca debug versiyonunda kontrol edilebilir. Bu tür fonksiyonlar özellikle birinci be ikinci grup arasında kalan fonksiyonlar olabilir. Örneğin CreateWindow fonksiyonu gibi.

3.14.2 CListBox::DeleteString Fonksiyonuint DeleteString( UINT nIndex );

Elemanın index numarasını alarak siler.

3.14.3 CListBox::GetCount Fonksiyonu

int GetCount(void) const;

List box'taki toplam eleman sayısını elde etmekte kullanılır.

3.14.4 CListBox::GetText Fonksiyonuİstenilen bir index'teki yazıyı geri almakta kullanılır. İki versiyonu vardır.

int GetText(int nIndex, LPTSTR lpszBuffer) const;void GetText(int nIndex, CString &rString) const;

Fonksiyonun ikinci biçimi daha kullanışlıdır.

3.14.5 CListBox::GetCurSel Fonksiyonu

int GetCurSel(void) const;

40

Page 41: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Bu fonksiyon o anda aktif elemanın index numarasını almakta kullanılır. Double click yapıldığında ilgili yazıyı elde etmek için önce GetCurSel sonra da GetText fonksiyonlarını kullanmak gerekir.

3.14.6 CListBox Sınıfının Faydalı Diğer Üye FonksiyonlarıFindString bir elemanı bulmakta, InsertString eleman insert etmekte, RessetContent tamamen bir list box'ı boşaltmakta kullanılır.

3.15 List Box Kontrolünün Gönderdiği MesajlarList box kontrolünün gönderdiği iki önemli mesaj LBN_SELCHANGE ve LBN_DBLCLK notification code'una sahip mesajlardır. MFC'de bu mesajlar genel olarak ON_CONTROL makrosuyla ya da aşağıdaki özel makrolarla işlenebilir:

ON_LBN_DBLCLK(id, Func)ON_LBN_SELCHANGE(id, Func)

ON_CONTROL(LBN_DBLCLK, id, Func)ON_CONTROL(LBN_SELCHANGE, id, Func)

List box kontrolüne LB_DIR mesajı gönderilirse (MFC'de bu işlem CListBox::Dir fonksiyonuyla yapılabilir) list box belirtilen dizindeki tüm dosya isimlerini eleman olarak ekler. Dizin isimleri köşeli parantezler içerisinde belirtilir.

int Dir(UINT attr, LPCTSTR path);

3.16 CWnd SINIFININ PostMessage ve SendMessage FonksiyonlariAPI düzeyinde PostMessage ve SendMessage fonksiyonlarının parametrik yapıları aynıdır. PostMessage mesajı pencereyi hangi thread açmışsa o thread'in mesaj kuyruğuna bırakır. SendMessage ise pencerenin pencere fonksiyonunu bularak doğrudan onu çağırır. Genel olarak Windows klasik pencere mesajlarını PostMessage ile kuyruğa yerleştirir. Oysa kontroller WM_COMMAND mesajını SendMessage ile yollarlar. SendMessage fonksiyonundan çıkıldığında mesajın işlendiğine emin oluruz.

PostMessage ve SendMessage fonksiyonları CWnd sınıfının üye fonksiyonu olarak da yazılmıştır. Bu üye fonksiyonlarda hWnd parametresi yoktur. Çünkü bu parametreyi sınıfın m_hWnd elemanından elde etmektedir.

LRESULT CWnd::SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);

BOOL CWnd::PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);

Örneğin:

CWnd *pWnd;// .....::SendMessage(pWnd->m_hWnd, msg, wParam, lParam);

işleminin eşdeğeri

CWnd *pWnd;// .....pWnd->SendMessage(msg, wParam, lParam);

Ya da örneğin

CButton *pButton// .....

pButton->SendMessage(msg, wParam, lParam);

41

Page 42: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

işleminde pButton'a mesaj gönderilir. //Kontrollerin kullanımı 3 (Listbox uygulmasi)#ifndef _LDIR_H_#define _LDIR_H_

#define ID_COMBO 100#define ID_LIST 101

#define DIRATTR (DDL_READWRITE|DDL_DIRECTORY|DDL_ARCHIVE)//application class

class CGenericApp : public CWinApp{public:

virtual BOOL InitInstance(void);};

//aplication main window class

class CMainWnd : public CFrameWnd{public:

CMainWnd(void);afx_msg int OnCreate(LPCREATESTRUCT lpCreate);afx_msg void OnSelectItem(void);afx_msg void OnDblclkList(void);

private:CComboBox *m_pCombo;CListBox *m_pList;CString *m_pCurrentPath;int m_currentDrive;int m_numberOfDrives;

DECLARE_MESSAGE_MAP()};#endif//ldir.cpp dosyası#include <afxwin.h>#include "ldir.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_CREATE()ON_CBN_SELENDOK(ID_COMBO, OnSelectItem)ON_LBN_DBLCLK(ID_LIST, OnDblclkList)

END_MESSAGE_MAP()

//global variable for the aplicitionCGenericApp theApp;

//class implamentionBOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd ->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

m_pCombo = new CComboBox();m_pList = new CListBox();

Create(NULL, "Listbox Uygulamasi");}

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreate){

m_pCombo->Create(WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|CBS_DROPDOWN, CRect(CPoint(50, 50), CSize(200, 200)), this, ID_COMBO);

42

Page 43: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

m_pList->Create(WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|LBS_NOTIFY, CRect(CPoint(300, 50), CSize(200, 200)), this, ID_LIST);

DWORD dwLen = ::GetLogicalDriveStrings(0, NULL);LPSTR pDriveStrings = new char[dwLen];::GetLogicalDriveStrings(dwLen, pDriveStrings);DWORD dw = ::GetLogicalDrives();for(m_numberOfDrives=0; dw!=0; dw >>= 1)

if(dw & 1)++m_numberOfDrives;

m_pCurrentPath = new CString[m_numberOfDrives];

LPTSTR pStr = pDriveStrings;for(int n=0;; ++n){

m_pCurrentPath[n] = toupper(pStr[0]);m_pCombo->AddString(m_pCurrentPath[n]);m_pCurrentPath[n] += ':';pStr = strchr(pStr, '\0') + 1;if(*pStr=='\0')

break;}delete [ ] pDriveStrings;return 0;

}

void CMainWnd::OnSelectItem(void){

CString drive;int index;

index=m_pCombo->GetCurSel();m_currentDrive = index;m_pList->ResetContent();m_pList->SendMessage(LB_DIR, DIRATTR, (LPARAM)(LPCTSTR)(m_pCurrentPath[index]

+"/*.*"));}

void CMainWnd::OnDblclkList(){

CString str;int index;

index = m_pList->GetCurSel();m_pList->GetText(index, str);

if(str[0]=='['){if(str=="[..]"){

index = m_pCurrentPath[m_currentDrive].ReverseFind('/');m_pCurrentPath[m_currentDrive] =

m_pCurrentPath[m_currentDrive].Left(index);}else{

int length=str.GetLength();str=str.Mid(1, length-2);m_pCurrentPath[m_currentDrive] += '/';m_pCurrentPath[m_currentDrive] += str;

}m_pList->ResetContent();m_pList->SendMessage(LB_DIR, DIRATTR,

(LPARAM)(LPCTSTR)(m_pCurrentPath[m_currentDrive]+"/*.*"));return;

}}

43

Page 44: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

2001-11-20 salı

3.17 MFC HANDLE Tablosu İle İlgili İşlemlerBilindiği gibi her CWnd nesnesi için eğer bu nesneyle bir pencere yaratılmışsa MFC'nin global handle tablosunda bir giriş vardır. Ancak bazen özellikle API düzeyinde yapılan işlemler sırasında bir pencerenin hWnd handle değeri bilindiğinde buna karşı gelen CWnd nesne adresi elde edilmek istenir. MFC handle tablosu hash tablosu biçiminde düzenlenmiştir. Global handle tabloları kalıcı ve geçici olmak üzere iki tanedir. Normal olarak pencere yaratıldığında kalıcı handle tablosu kullanılır. Geçici handle tablosu birkaç durumda kullanılmaktadır. Bu durumdan ileride bahsedilecektir. Geçici handle tablosuna ilişkin bir CWnd adresi saklanarak uzun süre kullanılmamaktadır. Çünkü MFC idle process işleminde geçici tablodaki gereksiz girişleri silmektedir.

Bir hWnd handle değeri biliniyorsa buna ilişkin CWnd nesnesinin adresi CWnd::FromHandle ve CWnd::FromHandlePermanent statik üye fonksiyonları ile elde edilebilir. Bu fonksiyonlar kalıcı ve geçici handle tablolarına bakarak hWnd ile ilişkili CWnd nesne adresini verirler.

static CWnd *CWnd::FromHandle(HWND hWnd);

static CWnd *CWnd::FromHandlePermanent(HWND hWnd);

FromHandle fonksiyonu parametresiyle belirtilen handle'a ilişkin CWnd nesne adresini tabloda arar. Eğer bulamazsa bir CWnd alanını dinamik olarak tahsis eder, geçici tabloda bir giriş oluşturur ve bu CWnd adresiyle geri döner. Tabii bu biçimde elde edilen CWnd adresinin uzun süre saklanmaması gerekir. Çünkü idle process işleminde tahsis edilen alan boşaltılarak geçici tablodan silinmektedir. Örneğin:

1)CWnd *pWnd;pWnd->Create(.....);ASSERT(pWnd == CWnd::FromHandle(pWnd->m_hWnd)); // OK

2)CWnd wnd;wnd.Create(.....);ASSERT(&wnd == CWnd::FromHandle(wnd.m_hWnd)); // OK

FromHandlePermanent fonksiyonu geçici nesne yaratmaz. Eğer hWnd değerine karşı bir CWnd nesnesi bulamazsa NULL ile geri döner.

44

Page 45: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3.18 CWnd::Attach ve CWnd::Detach FonksiyonlarıAttach ve Detach fonksiyonları statik fonksiyonlar değildir. Attach başka bir biçimde elde edilmiş olan bir hWnd handle değerini sınıfın m_hWnd veri elemanına yazar ve fonksiyonun çağrıldığı nesnenin adresiyle de kalıcı handle tablosunda bir giriş oluşturur. Attach fonksiyonundan sonra artık handle bir pencereyle ilişkilendirilmiş olur ve MFC mesaj mekanizmasına katılır. Tipik olarak Attach fonksiyonu şu durumda kullanılmaktadır: "Elimizde CreateWindow API fonksiyonuyla elde edilmiş olan bir hWnd handle değeri olsun. Biz bu handle değerini CWnd'den türetilmiş bir sınıf ile ilişkilendirmek isteyelim. Yani sanki bu sınıf ile Create fonksiyonu çağrılarak pencere fonksiyonu yaratılmış olsun.

CWnd

CMyWnd

hWnd = ::CreateWindow(.....);CMyWnd *pWnd = new CMyWnd();pWnd->Attach(hWnd);

Aslında CWnd::Create fonksiyonu CreateWindow API fonksiyonuyla handle'ı elde ettikten sonra burada olduğu gibi Attach fonksiyonuyla tabloya yazmaktadır.

Benzer biçimde CWnd::Detach CWnd sınıf nesnesine ilişkin girişi handle tablosundan siler. Normal olarak bir pencere CWnd::DestroyWindow fonksiyonuyla yok edilir (CWnd sınıfının bitiş fonksiyonu bu fonksiyonu çağırmaktadır). CWnd::DestroyWindow API fonksiyonunu çağırdıktan sonra Detach fonksiyonuyla tablodan girişi silmektedir. Programcı istediği zaman Detach fonksiyonuyla bir CWnd nesnesini mesaj mekanizmasından çıkarabilir (Detach fonksiyonu ilgili girişi tablodan sildikten sonra sınıfın m_hWnd elemanına NULL yerleştirmektedir). Böylece iki kere Detach yapılamaz.

BOOL CWnd::Attach(HWND hWnd);

HWND CWnd::Detach(void);

45

Page 46: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

4 KAYNAK İŞLEMLERİBir Windows programında kullanılan her türlü kaynak PE dosyasının kaynak bölümüne linker tarafından yerleştirilmektedir. PE formatının kaynak bölümünün nereden başladığı PE formatının başlık kısmında yazmaktadır. PE formatının bellekteki başlangıç adresi ise hInstance değeriyle temsil edilir. Kaynaklar .RC dosyası içerisine text olarak kaynak dilinin kurallarıyla yazılır. Kaynak derleyicisiyle derlenerek .RES biçimine dönüştürülür ve linker tarafından PE formatının kaynak bölümüne yerleştirilir (resource binding). Her türlü kaynağın bir ismi vardır. İsim sayısal ya da alfabetik düzeyde verilebilir (sayısal isimlendirme daha hızlı işlem yapılmasına yol açar). Bir kaynak kaynağa özgür LoadXXX fonksiyonlarıyla ya da genel LoadResource fonksiyonuyla yüklenerek bir handle elde edildikten sonra bu handle yoluyla kullanılır.

MFC'de kaynak işlemleri API düzeyinden farklı değildir. Kaynaklar elle yazılmaz, kaynak editörüyle oluşturulur. Kaynak editörü X.RC ve RESOURCE.H isimli iki dosya üretir. .RC dosyası projeye dahil edilir, RESOURCE.H dosyasıysa kaynak koddan include edilir. RESOURCE.H içerisinde kaynak tanımlamalarına ilişkin sembolik sabitler bulunmaktadır.

4.1 Menü Kaynağının KullanılmasıMenü kaynağında her menü elemanının WORD uzunlukta bir ID değeri vardır (popup menülerin ID değerleri yoktur yalnızca menü elemanlarının ID değerleri vardır). Bu ID değerleri PE formatının kaynak bölümüne yazılmaktadır. Windows menüden bir eleman seçildiğinde kuyruğa WM_COMMAND mesajını bırakır. Seçilen menü elemanının ID'sini LOWORD(wParam)'a yerleştirilir. Anımsanacağı gibi WM_COMMAND mesajı kontroller tarafından da gönderilmektedir. MFC'de mesajın kontrolden mi yoksa menüden mi geldiği zaten framework tarafından tespit edilmektedir. API düzeyinde bunun tespit edilebilmesi için lParam'a bakılması gerekir. Kontroller için lParam kontrolün handle değerini tutarken, menüler için 0 değerinde kalmaktadır.

4.2 MFC' de Menü Mesajlarının İşlenmesi MFC'de menü mesajları ON_COMMAND mesaj makrosuyla işlenmektedir. Çünkü framework WM_COMMAND mesajı için LOWORD(wParam) belirtilen ID değerine, lParam 0 değerine eşitse ON_COMMAND makrosunda belirlenen fonksiyonları çağırmaktadır. ON_COMMAND makrosu iki parametrelidir:

ON_COMMAND(id, Func)

Menüyü işleyecek üye fonksiyonun geri dönüş değeri ve parametresi void olmak zorundadır.

NOT : AFXWIN.H dosyasının içerisinde çok klasik menü elemanları için çeşitli sembolik sabitler define edilmiştir. Örneğin ID_FILE_OPEN gibi. Bu nedenle klasik File, Edit gibi bir menü oluşturulurken tesadüf aynı isimler verildiğinde aynı sembolik sabitler hem RESOURCE.H içerisinde hem de AFXWIN.H içerisinde bulunmuş olur. Böylece problemli bir durum oluşur. Bu problemi çözmek için bu özel sembolik sabitlerin isimleri bilinçli olarak değiştirilebilir ya da RESOURCE.H içerisinden bu sembolik sabitler silinir.

2001-11-22 Perşembe

4.3 MFC'de Menülerin GörüntülenmesiBilindiği gibi API düzeyinde bir menü üç biçimde görüntülenebilir:

1) WNDCLASS yapısının lpszMenuName elemanına menü ismi girilir. CreateWindow fonksiyonunda bu sınıf kullanıldığında menü otomatik olarak görüntülenir.

46

Page 47: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

2) LoadMenu fonksiyonu ile menü kaynağı yüklenir ve handle elde edilir. Sonra CreateWindow fonksiyonunun HMENU parametresine bu handle girilerek menü yaratılır.

3) Menü API fonksiyonlarıyla istenildiği zaman dinamik olarak yaratılır.

MFC'de bu üç yöntemle de menü oluşturulabilir. Ancak birinci yöntemde WNDCLASS yapısını biz oluşturmadığımız için işlemler zordur. Üçüncü yöntem de zahmetli bir yöntemdir. O halde en kolay yöntem ikinci yöntemdir.

CFrameWnd::Create fonksiyonunun altıncı elemanı LPCTSTR lpszMenuName biçimindedir. Bu parametreye doğrudan menü kaynağının ismi girilirse fonksiyon kendi içerisinde menü kaynağını yükleyerek ikinci yöntemi uygular.

Sınıf Çalışması

İskelet MFC programını kullanarak aşağıdaki menü sistemini oluşturunuz ve seçim yapıldığında seçilen elemanı message box ile yazdırınız.

//MENU.H

#ifndef _MENU_H_#define _MENU_H_

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);public:

afx_msg void OnFileOpen();afx_msg void OnFileSave();afx_msg void OnFileExit();afx_msg void OnFileCut();afx_msg void OnFilePaste();DECLARE_MESSAGE_MAP()

};#endif//MENU.CPP#include <afxwin.h>#include "menu.h"#include "resource.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_COMMAND(ID_FILE_OPENX, OnFileOpen)ON_COMMAND(ID_FILE_SAVEX, OnFileSave)ON_COMMAND(ID_FILE_EXITX, OnFileExit)ON_COMMAND(ID_EDIT_CUTX, OnFileCut)ON_COMMAND(ID_EDIT_PASTEX, OnFilePaste)

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "Sample", WS_OVERLAPPEDWINDOW, rectDefault, NULL,MAKEINTRESOURCE(IDR_MENU1));}

47

Page 48: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CMainWnd::OnFileOpen(){

MessageBox("Open seçildi");}

void CMainWnd::OnFileSave(){

MessageBox("Save seçildi");}

void CMainWnd::OnFileExit(){

MessageBox("Exit seçildi");}

void CMainWnd::OnFileCut(){

MessageBox("Cut seçildi");}

void CMainWnd::OnFilePaste(){

MessageBox("Paste seçildi");}

48

Page 49: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

5 CFILE SINIFICWnd

CMyWnd

Windows programlamada dosya işlemleri için CreateFile, ReadFile, WriteFile gibi API fonksiyonları kullanılır. C'nin standart dosya fonksiyonları zaten Windows'ta bu API'leri çağırarak işlemleri yapar. MFC'de diğer işlemlerde olduğu gibi dosya işlemleri de bir sınıfla temsil edilmiştir. CFile sınıfı CObject sınıfından türetilmiştir.

CFile sınıfının public bölümünde HANDLE türünden m_hFile veri elemanı vardır. Bu eleman API handle değeridir.

Dosya CFile sınıfının başlangıç fonksiyonuyla ya da Open üye fonksiyonuyla açılabilir. Dosya Close üye fonksiyonuyla kapatılabilir ya da sınıfın bitiş fonksiyonu da bu kapatma işlemini otomatik olarak yapmaktadır. Sınıfın Read ve Write fonksiyonları okuma ve yazma işlemlerini yapar. Seek fonksiyonu dosya göstericisini yerleştirir. Bunun dışında sınıfın çeşitli faydalı üye fonksiyonları da vardır.

Dosya açış modları CFile sınıfının public bölümündeki modeXXX biçimindeki enum sembolik sabitlerinin bit or işlemine sokulmasıyla oluşturulur.

CFile Class Members Data Membersm_hFile Usually contains the operating-system file handle.Construction

CFile Constructs a CFile object from a path or file handle.Abort Closes a file ignoring all warnings and errors.Duplicate Constructs a duplicate object based on this file.Open Safely opens a file with an error-testing option.Close Closes a file and deletes the object.Input/OutputRead Reads (unbuffered) data from a file at the current file position.ReadHuge Can read more than 64K of (unbuffered) data from a file at the current file position. Obsolete in 32-bit

programming. See Read.Write Writes (unbuffered) data in a file to the current file position.WriteHuge Can write more than 64K of (unbuffered) data in a file to the current file position. Obsolete in 32-bit

programming. See Write.Flush Flushes any data yet to be written.PositionSeek Positions the current file pointer.SeekToBegin Positions the current file pointer at the beginning of the file.SeekToEnd Positions the current file pointer at the end of the file.GetLength Retrieves the length of the file.SetLength Changes the length of the file.LockingLockRange Locks a range of bytes in a file.UnlockRange Unlocks a range of bytes in a file.Status

GetPosition Retrieves the current file pointer.GetStatus Retrieves the status of this open file.GetFileName Retrieves the filename of the selected file.GetFileTitle Retrieves the title of the selected file.GetFilePath Retrieves the full file path of the selected file.SetFilePath Sets the full file path of the selected file.StaticRename Renames the specified file (static function).Remove Deletes the specified file (static function).GetStatus Retrieves the status of the specified file (static, virtual function).SetStatus Sets the status of the specified file (static, virtual function).

49

Page 50: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

5.1 CFile Sınıfının Başlangıç Fonksiyonları1) Default başlangıç fonksiyonu bir şey yapmaz.

CFile();

2) CreateFile API fonksiyonundan alınan handle değeriyle nesne oluşturulabilir.

CFile(int hFile);

3) Belirtilen isimde ve açış modunda dosyayı açar. Fonksiyon başarısızlık durumunda CFileException sınıfıyla throw etmektedir.

CFile(LPCTSTR lpszFileName, UINT nOpenFlags);throw CFileException();

Örneğin:

try {CFile X("a.dat", CFile::modeCreate | CFile::modeWrite);// .....

}catch (CFileException *pException) {

// .....}

5.2 CFile:Open Fonksiyonu

virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException *pError = NULL);

Önemli dosya açış modları şunlardır: modeRead, modeReadWrite, typeBinary (default'tur), typeText, modeNoTruncate, modeCreate.

Örneğin bir dosya şöyle açılabilir:

if (x.Open("a.dat", CFile::modeCreate | CFile::modeReadWrite)) {MessageBox("Cannot open file!..")return;

}

5.3 CFile::Close FonksiyonuClose fonksiyonu dosyayı kapatır. Dosya kapatılmazsa bitiş fonksiyonu tarafından kapatılmaktadır.

virtual void CFile::Close(void);throw(CFileException);

5.4 CFile::Read ve CFile::Write FonksiyonlarıRead ve Write Fonksiyonları dosyayla bellek arasında n byte transfer yaparlar.

virtual UINT CFile::Read(void *lpBuf, UINT nCount);throw(CFileException);

virtual void CFile::Write(const void* lpBuf, UINT nCount);throw(CFileException);

50

Page 51: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Read fonksiyonu ikinci parametresiyle belirtilen sayıda byte transfer eder. Geri dönüş değeri okunan byte sayıdır.

5.5 CFile::Seek FonksiyonlarıBu fonksiyonlar dosya göstericisini konumlandırmakta kullanılır.

virtual LONG CFile::Seek(LONG lOff, UINT nFrom);throw( CFileException );

5.6 CFile::SeekToBegin ve CFile::SeekToEnd FonksiyonlarıDosya göstericisini başa ve sona yerleştirirler.

void SeekToBegin(void); throw(CFileException);

DWORD SeekToEnd(void); throw(CFileException);

5.7 CFile Sınıfının Diğer FonksiyonlarıGetPosition dosya göstericisinin konumunu verir. GetFileName açık olan dosya ismini verir. GetFileTitle uzantısız dosya isimi verir. GetFilePath dosyanın full path ismini verir. Ayrıca CFile sınıfının statik üye fonksiyonları olan Rename ve Remove sırasıyla herhangi bir dosya ismini değiştirir ve bir dosyayı siler. Sınıfın GetLength üye fonksiyonu dosya uzunluğu elde etmekte kullanılır.

5.8 CStdioFile SINIFICFile

CStdioFile

Bu sınıf CFile sınıfından türetilmiştir ve text mod dosya işlemlerini yapar.

Sınıfın başlangıç fonksiyonu şöyledir:

CStdioFile(void);

CStdioFile(FILE *pOpenStream);

CStdioFile(LPCTSTR lpszFileName, UINT nOpenFlags);throw(CFileException);

Sınıfın ReadString ve WriteString üye fonksiyonları tıpkı fgets ve fputs fonksiyonlarında olduğu gibi birer satır yazıp okumakta kullanılır.

virtual LPTSTR CStdioFile::ReadString(LPTSTR lpsz, UINT nMax);

throw(CFileException);

BOOL CStdioFile::ReadString(CString &rString);throw(CFileException);

virtual void CStdioFile::WriteString(LPCTSTR lpsz);throw(CFileException);

51

Page 52: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Sınıf Çalışması

İskelet MFC programını kullanarak aşağıda açıklanan editör uygulamasını yazınız:

1) Programın menüsü aşağıdaki gibi olacaktır.

File/ Open Save Exit

2) Open ve save işlemleri "file.dat" isimli bir dosyadan yapılacaktır. Close işlemi dosya save edilmediyse yes/no MessageBox fonksiyonu kullanılarak sorgulanacaktır. Close işleminden sonra edit box boşaltılacaktır.

3) Edit box WM_CREATE mesajında yaratılacak ve WM_SIZE mesajı işlenerek çalışma alanını kaplar duruma getirilecektir.

4) Close işleminde değişiklik yapılıp yapılmadığı edit box kontrolünden öğrenilmelidir.

5) Open ve save işlemleri CFile sınıfı kullanılarak yapılacaktır ve bu işlem tipik olarak aşağıdaki gibi yapılabilir://edit.rcIDR_MENU1 MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Open...", ID_FILE_OPENX MENUITEM "&Save...", ID_FILE_SAVEX MENUITEM "&Close", ID_FILE_CLOSEX MENUITEM "&Quit", ID_FILE_QUITX ENDEND

//resource.h#define IDR_MENU1 101#define ID_FILE_OPENX 40001#define ID_FILE_SAVEX 40002#define ID_FILE_CLOSEX 40003#define ID_FILE_QUITX 40004#define ID_EDIT

//edit.h#ifndef _GENMFC_H_#define _GENMFC_H_

class CGenericApp: public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd{public:

CMainWnd(void);~CMainWnd(void);afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnSize(UINT nType, int cx, int cy);afx_msg void OnFileOpen(void);afx_msg void OnFileSave(void);afx_msg void OnFileClose(void);afx_msg void OnFileQuit(void);

private:CEdit *m_pEdit;DECLARE_MESSAGE_MAP();

};

#endif

//edit.cpp#include <afxwin.h>#include "edit.h"

52

Page 53: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

#include "resource.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_CREATE()ON_WM_SIZE()ON_COMMAND(ID_FILE_OPENX, OnFileOpen)ON_COMMAND(ID_FILE_SAVEX, OnFileSave)ON_COMMAND(ID_FILE_CLOSEX, OnFileClose)ON_COMMAND(ID_FILE_QUITX, OnFileQuit)

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

m_pEdit = new CEdit();Create(NULL, "Editor", WS_OVERLAPPEDWINDOW,

CRect(100, 100, 350, 300), NULL, MAKEINTRESOURCE(IDR_MENU1));}

CMainWnd::~CMainWnd(void){

delete m_pEdit;}

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

m_pEdit->Create(WS_CHILD|WS_VISIBLE|ES_MULTILINE,CRect(0,0,0,0), this, ID_EDIT);

return 0;}

void CMainWnd::OnSize(UINT nType, int cx, int cy){

m_pEdit->MoveWindow(0, 0, cx, cy);}

void CMainWnd::OnFileOpen(void){

CFile file;if(!file.Open("x.dat", CFile::modeRead)){

MessageBox("Cannot open file!..");}DWORD dwLength = file.GetLength();

char *pBuf = new char[dwLength + 1];file.Read(pBuf, dwLength);pBuf[dwLength]='\0';

m_pEdit->SetWindowText(pBuf);delete [ ] pBuf;file.Close();

}

void CMainWnd::OnFileSave(void){

CFile file;CString str;

file.Open("x.dat", CFile::modeCreate|CFile::modeWrite);m_pEdit->GetWindowText(str);file.Write(str,str.GetLength());

53

Page 54: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

file.Close();

}

void CMainWnd::OnFileClose(void){

m_pEdit->SetWindowText(" ");

}

void CMainWnd::OnFileQuit(void){

DestroyWindow();

}

2001-11-27 Salı

Anımsatma : Çok satırlı edit box kontrolü text dosyalar gibi çalışır. Yani bir karakterin aşağı satırın başında gözükebilmesi için kontrole yalnızca LF değil CR/LF çiftinin gönderilmesi gerekir. GetWindowText fonksiyonu ile edit box'tan bilgi alınırken aşağı satırın başına geçme anlamında CR ve LF karakterlerinin her ikisi de elde edilmektedir. Bu yüzden yazı dosyasının text modda değil binary modda açılması uygundur. MFC'de edit box'taki bilgiyi aktarıp geri almak için CStdioFile değil CFile sınıfı kullanılmalıdır.

5.9 MFC'de Programın SonlandırılmasıAPI düzeyinde programın sonlandırılması için WinMain fonksiyonunun sonlanması gerekir. WinMain fonksiyonunun sonlanması için ise mesaj döngüsünden çıkılması gerekir. Mesaj döngüsünden, GetMessage fonksiyonunun WM_QUIT mesajını alıp 0 ile geri dönmesi ile çıkılır. Kullanıcı fare ile X ikonuna click yaptığında ya da Alt+F4 tuşlarına bastığında Windows kuyruğa WM_CLOSE mesajını bırakır. WM_CLOSE mesajında DestroyWindow çağrılmalıdır (WM_CLOSE işlenmezse DefWindowProc default olarak DestroyWindow fonksiyonunu çağırır). DestroyWindow fonksiyonu kendi içerisinde SendMessage ile WM_DESTROY mesajını yollamaktadır. WM_DESTROY için PostQuitMessage çağrılır. Bu fonksiyon da kuyruğa WM_QUIT mesajını bırakır.

WM_CLOSE-->DestroyWindow--> WM_DESTROY--> PostQuitMessage--> WM_QUIT

Bu durumda API düzeyinde bir programı üç biçimde sonlandırabiliriz:

1) Ana pencereye WM_CLOSE mesajını bırakmak.

2) Ana pencereye DestroyWindow mesajını uygulamak.

3) PostQuitMessage fonksiyonunu doğrudan çağırmak.

En uygun yöntem DestroyWindow fonksiyonunun uygulanmasıdır.

MFC'de de sistematik aynı oluğundan bu üç yöntemin hepsi uygulanabilir. CWnd sınıfının DestroyWindow fonksiyonu sanal bir fonksiyondur. CFrameWnd sınıfında PostQuitMessage yapar.

virtual BOOL DestroyWindow(void);

54

Page 55: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Sanallık pencerenin kapatılması sırasında etkin olan önemli bir durum değildir. CWnd::DestroyWindow fonksiyonu programın ana penceresine ilişkin bir sınıfın üye fonksiyonundan çağırıldığında programın ana penceresini kapatır.

Sınıf Çalışması

İskelet MFC programını kullanarak ana pencere içerisinde farenin sol tuşuna basıldığında yukarıda açıklanan üç yöntemi de kullanarak programı sonlandırınız. //DESTROYWINDOW.H

#ifndef _DESTROYWINDOW_H_#define _DESTROYWINDOW_H_

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

DECLARE_MESSAGE_MAP()};

#endif//DESTROYWINDOW.CPP

#include <afxwin.h>#include "destroywindow.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_LBUTTONDOWN()

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "Destroy Window", WS_OVERLAPPEDWINDOW);}

void CMainWnd::OnLButtonDown(UINT nFlags, CPoint point){

PostMessage(WM_CLOSE, 0, 0);// DestroyWindow();// ::PostQuitMessage(0);}

Kuşkusuz PostQuitMessage fonksiyonunun çağırılması CFrameWnd::DestroyWindow fonksiyonuyla mümkün olmaktadır.

5.10 Uygulamaya ve Ana Pencereye İlişkin Nesnelerin Elde EdilmesiAnımsanacağı gibi bir MFC programında CWinApp sınıfından bir sınıf türetip o sınıfa ilişkin global bir nesne tanımlamak gerekiyordu. Bu global nesne diğer modüllerden extern yapılarak kullanılabilir. Ancak istenirse AfxGetApp global fonksiyonuyla bu nesnenin adresinin elde edilmesi mümkündür.

55

Page 56: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CWinApp *AfxGetApp(void);

Fonksiyonun geri dönüş değeri CWinApp türünden olmasına karşın aslında adreste bulunan nesne CWinApp'den türettiğimiz sınıf türündendir. Yani bu adresin aşağıya doğru dönüştürme yapılmasında bir sakınca yoktur.

CMyApp *pMyApp = (CMyApp *) AfxGetApp();

Programcı neden bu nesnenin adresini elde etmek ister? En önemli neden WinMain fonksiyonuna geçirilen parametrelere erişmektir. Çünkü framework InitInstance sanal fonksiyonunu çağırmadan önce WinMain parametrelerini CWinApp sınıfının veri elemanlarına yazmaktadır.

Sınıf Çalışması

İskelet MFC programını kullanarak farenin sol tuşuna basıldığında programın komut satırı argümanlarını MessageBox ile ekrana yazdıran programı yazınız.

COMMANDLINE.H

#ifndef _COMMANDLINE_H_#define _COMMANDLINE_H_

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

DECLARE_MESSAGE_MAP()};

#endifCOMMANDLINE.CPP

#include <afxwin.h>#include "commandline.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_LBUTTONDOWN()

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "Command Line", WS_OVERLAPPEDWINDOW);}

void CMainWnd::OnLButtonDown(UINT nFlags, CPoint point){

MessageBox(AfxGetApp()->m_lpCmdLine);}

56

Page 57: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Programcı herhangi bir zaman programın ana penceresine ilişkin nesnenin adresini CWinThread sınıfının m_pMainWnd elemanından çekebilir. Aynı işlem AfxGetMainWnd global fonksiyonuyla da yapılabilir.

CWnd *AfxGetMainWnd(void);

Bu durumda karmaşık bir projede programı sonlandırabilmek için:

AfxGetApp()->m_pMainWnd->DestroyWindow();

ya da

AfxGetMainWnd()->DestroyWindow();

yapılabilir.

5.11 Normal Alt Pencereleri YaratmakStandart kontrollerin dışında istediğimiz gibi şekillendirebileceğimiz alt pencereler yaratabiliriz. Tabii yarattığımız pencereyi MFC mesaj işleme mekanizmasına dahil edebilmek için CWnd sınıf sistemini kullanmamız gerekir. Bunun için CWnd sınıfından doğrudan bir sınıf türetmek ve pencereyi o sınıf türünden nesneyle CWnd sınıfının Create üye fonksiyonunu kullanarak yaratmak gerekir. Böylelikle alt pencere üzerinde olaylar gerçekleştiğinde alt pencereye ilişkin sınıfın mesaj haritası işlem görecektir.

57

Page 58: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

6 VISUAL C++ DERLEYİCİ SİSTEMİNDE SINIFLARIN OLUŞTURULMASIİyi bir çalışma sistemi sağlamak için her bir sınıf X.H ve X.CPP dosyaları ile düzenlenir ve proje dosyasına eklenir. Bu işlm Visual C++ derleyici sisteminde Insert/New Class menüsüyle pratik olarak yapılabilir. Insert/New Class ile şunlar yapılmaktadır:

1) Dialog penceresi, yaratılacak sınıfın ismini ve varsa taban sınıfının ismini programcıdan ister. İsmin başındaki ilk harfi atarak default olarak geri kalan harflerden sınıfa ilişkin dosyaların ismini oluşturur.

2) X.H dosyası içerisinde sınıf bildirimini yerleştirir. Include korumasını oluşturur (#ifndef'ler v.b.). Sınıfın başlangıç ve bitiş fonksiyonlarının prototiplerini oluşturur. X.CPP dosyasında ise başlangıç ve bitiş fonksiyonlarını içi boş olarak yazar ve X.H dosyasını buradan include eder.

3) X.CPP dosyasını projeye dahil eder.

//Genel alt pencere uygulaması//mainwnd.h#ifndef _MAINWND_H_#define _MAINWND_H_

#define ID_CHILD 2000

class CGenericApp: public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd{public:

CMainWnd();~CMainWnd();afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

private:

CChildWnd *m_pChildWnd;DECLARE_MESSAGE_MAP()

};

#endif//mainwnd.cpp#include <afxwin.h>#include "ChildWnd.h"#include "MainWnd.h"BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)

ON_WM_CREATE()END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

58

Page 59: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CMainWnd::CMainWnd(void){

m_pChildWnd = new CChildWnd();Create(NULL, "Main Window", WS_OVERLAPPEDWINDOW,CRect(CPoint(100,100),

CSize(350,150)));}CMainWnd::~CMainWnd(void){

delete m_pChildWnd;}

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

m_pChildWnd->Create(NULL, "Child Window", WS_CHILD|WS_VISIBLE|WS_BORDER|WS_CAPTION,

CRect(CPoint(50,10), CSize(200,100)), this, ID_CHILD);

return 0;}//childwnd.h// ChildWnd.h: interface for the CChildWnd class.

#if !defined(AFX_CHILDWND_H__FA8B9B01_1B60_4A54_A24D_7B58BBF35287__INCLUDED_)#define AFX_CHILDWND_H__FA8B9B01_1B60_4A54_A24D_7B58BBF35287__INCLUDED_

#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#define ID_BUTTON 2000

class CChildWnd : public CWnd {public:

CChildWnd();virtual ~CChildWnd();afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnButtonClick();

private:CButton *m_pButton;DECLARE_MESSAGE_MAP()

};#endif //!defined(AFX_CHILDWND_H__FA8B9B01_1B60_4A54_A24D_7B58BBF35287__INCLUDED_)

//childwnd.cpp// ChildWnd.cpp: implementation of the CChildWnd class.#include <afxwin.h>#include "ChildWnd.h"

BEGIN_MESSAGE_MAP(CChildWnd, CWnd)ON_WM_CREATE()ON_BN_CLICKED(ID_BUTTON, OnButtonClick)

END_MESSAGE_MAP()CChildWnd::CChildWnd(){

m_pButton = new CButton();}

CChildWnd::~CChildWnd(){

delete m_pButton;}

int CChildWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

m_pButton->Create("Ok", WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, CRect(CPoint(0,0),CSize(50,30)), this, ID_BUTTON);

return 0;}

59

Page 60: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CChildWnd::OnButtonClick(){

MessageBox("Butona Bastınız...");}2001-11-29 Perşembe

60

Page 61: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

7 MFC'DE ÇİZİM İŞLEMLERİWindows her pencere için ismine güncelleme alanı (update region) denilen dikdörtgensel bir alan tutar. Bu dikdörtgensel alan pencere görüntüsünün bozulduğu bölgeyi temsil etmektedir. Windows pencere içerisindeki görüntüyü programcı için saklamaz. Bozulan görüntünün yeniden çizilmesi programcının sorumluluğundadır. Windows belirli periyodlarla tüm pencerelerin güncelleme alanlarını izler. Güncelleme alanı boş küme olmayan pencereler için WM_PAINT mesajını yollar. Programcı tüm çizim işlemlerini WM_PAINT mesajında yapmalıdır. Çizim başka bir yerde yapılırsa WM_PAINT mesajı geldiğinde o görüntü yeniden çizilemeyecektir, böylece görüntü kaybı oluşacaktır. Ancak çizimin WM_PAINT dışında yapılması gerektiği durumlarda vardır. Bu durumda aynı çizimlerin WM_PAINT mesajında yeniden oluşturulması gerekir. Bunun için iki strateji izlenebilir:

1) Dışarıda yapılan çizimlerin aynı zamanda bir veri yapısı içerisinde tutulması ve WM_PAINT mesajı içerisinde o veri yapısına bakılarak yeniden çizilmesi.

2) Çizimin hem pencereye hem de bellek DC'sine yapılması. WM_PAINT mesajında BitBlt API fonksiyonuyla bellek DC'sinden pencere DC'sine kopyalama yapılması.

Çizim karmaşık ve çok bileşenli bir olaydır. Çizim bileşenleri bir handle alanında tutulur. Bu handle alanına DC (Device Context) denir. DC elde etmek için BeginPaint, GetDC ve GetWindowDC fonksiyonları vardır. DC alanındaki çizim bileşenleri DC yaratıldığında default değerlerle doldurulur. Ancak daha sonra SelectObject API fonksiyonuyla değiştirilebilir. DC alan fonksiyonlar arasında önemli farklılıklar vardır.

7.1 BeginPaint FonksiyonuDC bu fonksiyonla alınmışsa çizim fonksiyonları yalnızca güncelleme alanını ekonomik bir biçimde çizerler. BeginPaint aynı zamanda güncelleme alanını yeniden boş küme yapar ve SendMessage ile WM_ERASEBKGND mesajını göndererek zeminin yeniden çizilmesini sağlar. BeginPaint ile alınan DC'nin orijin noktası çalışma alanının sol üst köşesidir.

7.2 GetDC FonksiyonuBu fonksiyon çalışma alanının her yerine çizim yapabilir. Orijin noktası çalışma alanının sol üst köşesidir. Zeminin yeniden boyanmasına yol açmaz.

7.3 GetWindowDC FonksiyonuTamamen GetDC gibidir. Ancak pencerenin her yerine çizim yapabilir. Orijin noktası pencerenin sol üst köşesidir.

7.4 MFC Çizim SınıflarıMFC'de çizim işlemleri için CDC, CPaintDC, CClientDC ve CWindowDC sınıfları kullanılır.

CObject

CDC

CpaintDC CclientDC CWindowDC

CDC sınıfı bütün çizim işlemlerini temsil eder. CDC sınıfının API fonksiyonlarını çağırarak çizim yapan pek çok üye fonksiyonu vardır. Bu sınıfın üye fonksiyonlarının isimleri öğrenmeyi kolaylaştırmak için API fonksiyonlarıyla aynı verilmiştir. Sınıfın HDC türünden m_hDC public veri elemanı API düzeyindeki gerçek çizim handle değerini tutmaktadır. CDC sınıfının üye fonksiyonları bu nedenle hDC parametre değerine gereksinim duymazlar.

61

Page 62: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CDC sınıfından türetilmiş olan sınıfların her biri çizim için handle değerini farklı API fonksiyonlarıyla elde eder.

7.5 CPaintDC SınıfıBu sınıf başlangıç fonksiyonu içerisinde BeginPaint API fonksiyonuyla DC'yi elde eder ve bu DC'yi CDC sınıfının m_hDC elemanında saklar. Sınıfın bitiş fonksiyonu otomatik olarak EndPaint API fonksiyonunu çağırarak DC'yi geri bırakır.

CPaintDC::CPaintDC(CWnd *pWnd);throw(CResourceException);

Görüldüğü gibi CPaintDC sınıfının başlangıç fonksiyonunun parametresi CWnd sınıfı türünden göstericidir. Yani bu parametre alınacak DC'nin hangi pencereye ilişkin olduğunu belirlemekte kullanılır. Bu durumda MFC'de WM_PAINT mesajı geldiğinde çizim yapabilmek için bu sınıf türünden nesne tanımlayıp CDC sınıfının üye fonksiyonlarını çağırmak gerekir. Örneğin:

OnPaint(){CPaintDC dc;

dc.xxx();// .....}

7.6 CClientDC SınıfıBu sınıfın başlangıç fonksiyonu GetDC API fonksiyonuyla DC'yi alır. Bitiş fonksiyonu da ReleaseDC fonksiyonuyla bırakır.

CClientDC::CClientDC(CWnd *pWnd);throw(CResourceException);

Bu sınıf WM_PAINT mesajının dışında çizim yapmak amacıyla kullanılır. Örneğin:

void CMainWnd::OnMouseMove(UINT key, CPoint pt){

CClientDC dc(this);

dc.xxx();// .....

}

7.7 CWindowDC SınıfıBu sınıf da GetWindowDC ile DC'yi alıp yine ReleaseDC fonksiyonuyla bırakmaktadır.

CWindowDC::CWindowDC(CWnd *pWnd);throw(CResourceException);

7.8 MFC'DE WM_PAINT Mesajının İşlenmesiMFC'de WM_PAINT mesajı diğer mesajlarda olduğu gibi mesaj haritası yoluyla çağrılır. Bunun için ON_WM_PAINT() parametresiz mesaj makrosu kullanılır. Çağrılacak fonksiyonun prototipi aşağıdaki gibidir:

void OnPaint(void);

Sınıf Çalışması

62

Page 63: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

İskelet MFC programını kullanarak ana pencerenin çalışma alanına doğrular çiziniz. //onpaint.h#ifndef _ONPAINT_H_#define _ONPAINT_H_

class CGenericApp: public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd{public:

CMainWnd(void);afx_msg void OnPaint(void);DECLARE_MESSAGE_MAP()

};#endif

//on_paint.cpp

#include <afxwin.h>#include "onpaint.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_PAINT()

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "OnPain Uygulaması", WS_OVERLAPPEDWINDOW, CRect(100, 100, 450, 250));

}

void CMainWnd::OnPaint(void){

CClientDC dc(this);

MoveToEx(dc, 10, 30, NULL);dc.LineTo(120, 50);LineTo(dc,200, 90);LineTo(dc, 230, 20);dc.LineTo(160, 30);

}

7.9 SCRATCHPAD UygulamasıFareyi pencere içerisinde tuşa basılı olarak sürüklediğimizde çizim yapan programlar şöyle tasarlanabilir:

1) WM_MOUSEMOVE mesajında CClientDC sınıfıyla her mesajda önceki noktayla sonraki nokta arasında doğru çizilir (önceki nokta pencere sınıfının private veri elemanı olarak tutulabilir).

2) Her doğru çizildiğinde doğrunun uç noktaları bir veri yapısında tutulmalıdır. Kullanılacak veri yapısı, dinamik büyütülen bir dizi ya da bir bağlı liste olabilir.

3) WM_PAINT mesajında noktalar veri yapısından alınarak doğrular yeniden çizilir.

63

Page 64: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

7.10 CWnd::GetDC FonksiyonuCWnd sınıfının GetDC fonksiyonu GetDC API fonksiyonunu kullanarak DC alır. Dışarıda yapılan çizimlerde CClientDC sınıfı yerine bu fonksiyon da tercih edilebilir.

CDC *CWnd::GetDC(void);

Fonksiyon CDC türünden bir alanı dinamik olarak tahsis eder. GetDC fonksiyonuyla DC'yi alır. Tahsis ettiği CDC nesnesinin adresiyle geri döner. Bu fonksiyonla tahsis edilen alan ve DC CWnd::ReleaseDC fonksiyonuyla bırakılmalıdır.

int CWnd::ReleaseDC(CDC *pCDC);

2001-12-04

7.11 GDI NESNELERİNİN KULLANILMASIBir DC alanı yaratılığında kalem, fırça, font gibi çizim bileşenleri default değerlerle doldurulmuştur. Kalem, fırça, font gibi çizim bileşenleri aslında pek çok parametreye sahiptir. Win32'de bu çizim bileşenleri ayrı handle alanlarına sahiptir.

Çizim işlemlerinde kullandığımız handle alanına sahip bu bileşenlere GDI nesneleri denir. GDI nesneleri nesneye özgü CreateXXX fonksiyonlarıyla yaratılır ve DeleteObject fonksiyonuyla boşaltılır.

GDI nesnelerinin silinmesi unutulursa process'in sonlanmasıyla problemsiz bir biçimde silinir. Bir GDI nesnesi yaratıldıktan sonra kullanılabilmesi için DC handle alanına bağlanması gerekir. Bu bağlantı SelectObject API fonksiyonuyla yapılır.

SelectObject API fonksiyonu her türlü GDI nesnesini seçebilir. Prototipi şöyledir:

HGDIOBJ SelectObject(HDC hDC, HGDIOBJ hgdiObj);

Aslında bütün GDI nesnelerinin handle alanlarının başlık kısmı aynıdır. Bu başlık kısmına bakılarak nesnenin hangi GDI nesnesi olduğu anlaşılır. GDI nesnelerinin yalnızca bir kez örneğin WM_CREATE mesajı içerisinde yaratılmaları normal bir uygulamadır. Ancak tabii WM_PAINT mesajı içerisinde her defasında SelectObject fonksiyonuyla bağlanmaları gerekir.

64

Page 65: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

8 MFC'DE GDI NESNELERİNİN KULLANIMICObject

CGdiObject

Cpen Cbrush . . . .

GDI nesneleri ayrı sınıflarla temsil edilmiştir. Örneğin CPen, CBrush, CFont gibi. Bu sınıfların hepsi CGdiObject taban sınıfından türetilmişlerdir.

Nesne seçmek için kullanılan SelectObject fonksiyonu aynı biçimde CDC sınıfının üye fonksiyonu olarak yazılmıştır:

CPen *SelectObject(CPen *pPen);

CBrush *SelectObject(CBrush *pBrush);

virtual CFont *SelectObject(CFont *pFont);

CBitmap *SelectObject(CBitmap *pBitmap);

int SelectObject(CRgn *pRgn);

Görüldüğü gibi her türden GDI nesne sınıfı parametreli SelectObject fonksiyonu vardır (fonksiyonların geri dönüş değerleri daha önce seçilmiş nesne olduğu için alışıldığı gibi fonksiyonun taban sınıf türünden parametre alıp genelleştirilmesi istenmemiştir. Eğer böyle olsaydı fonksiyonun geri dönüş değeri de CGdiObject türünden olurdu, bu da tür dönüştürmesi gerektirirdi).

8.1 GDI Nesnelerinin Global Handle TablolarıTıpkı pencerelerde olduğu gibi GDI nesneleri için de kalıcı ve geçici handle tabloları oluşturulmuştur. GDI sınıfları kullanılarak bir GDI nesnesi yaratılıp GDI handle değeri elde edildiğinde bu handle değeriyle bu handle'ın elde edilmesinde kullanılan nesnenin adresi bu işlem için oluşturulmuş olan global handle tablosunda bir çift olarak saklanmaktadır. Nesne yok edilip GDI nesnesi sistem genelinde serbest bırakıldıktan sonra tablodan ilgili giriş silinmektedir. GDI sisteminde de kalıcı ve geçici olmak üzere iki handle tablosu kullanılmıştır.

8.2 CGdiObject SINIFIBu sınıf GDI nesne sınıflarının taban sınıfıdır. Sınıfın m_hObject isimli public veri elemanı vardır. Bu eleman tüm GDI sınıflarının gerçek handle değerini tutar. Örneğin CPen sınıfı türünden bir nesne tanımlanıp bir kalem GDI nesnesi yaratılsa bunun API düzeyindeki handle değeri CGdiObject sınıfının m_hObject elemanında saklanacaktır. CGdiObject sınıfının önemli üye fonksiyonları şunlardır:

8.2.1 CGdiObject::Attach ve CGdiObject::Detach Fonksiyonları

BOOL CGdiObject::Attach(HGDIOBJ hObject);

HGDIOBJ CGdiObject::Detach(void);

Attach fonksiyonu dışarıdan elde edilmiş GDI handle değeri ile bir nesnenin ilişkilendirilmesini sağlar. Yani artık ilgili nesne global handle tablosuna da yazılır. Detach global handle tablosundan silme yapar.

8.2.2 CGdiObject::DeleteObject FonksiyonuBu fonksiyon nesneyi API düzeyinde siler ve Detach işlemini gerçekleştirir.

65

Page 66: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

BOOL CGdiObject::DeleteObject(void);

8.2.3 CGdiObject::FromHandle FonksiyonuStatik bir fonksiyondur. API düzeyindeki handle değerinden global handle tablosuna bakarak CGdiObject nesne adresini elde eder.

static CGdiObject * CGdiObject::FromHandle(HGDIOBJ hObject);

8.3 CPen SINIFIBu sınıf kalem GDI nesnesi yaratmakta kullanılır. API GDI nesnesi sınıfın başlangıç fonksiyonuyla yaratılabilir. Eğer default başlangıç fonksiyonu kullanılırsa yaratma işi daha sonra sınıfın CreatePen üye fonksiyonuyla yapılır.

Sınıfın başlangıç fonksiyonları şunlardır:

CPen::CPen(void);

CPen::CPen(int nPenStyle, int nWidth, COLORREF crColor);throw(CResourceException);

CPen::CPen(int nPenStyle, int nWidth, const LOGBRUSH *pLogBrush, int nStyleCount = 0, const DWORD *lpStyle = NULL);throw(CResourceException);

Anımsatma : Win32 GDI alt sistemi renk bilgisini long bir değer olarak red, green, blue renklerinin toplam birleşimi biçiminde ele alır. COLORREF long türüne typedef edilmiştir. RGB byte'ları ayrıyken bunları long bir değer olarak birleştiren RGB isimli bir makro vardır. Özetle renk programcıdan COLORREF türüyle istenir. Programcı da rengi RGB makrosuyla verir. Renk çözünürlüğü azaltılırsa GDI alt sistemi otomatik olarak o andaki çözünürlüğün izin verdiği en yakın değerleri kullanmaktadır.

8.4 CPen::CreatePen FonksiyonuCPen türünden nesne default başlangıç fonksiyonu ile yaratılmışsa GDI kalem nesnesi daha sonra bu fonksiyon ile yaratılabilir.

BOOL CPen::CreatePen(int nPenStyle, int nWidth, COLORREF crColor);

BOOL CPen::CreatePen(int nPenStyle, int nWidth, const LOGBRUSH *pLogBrush, int nStyleCount = 0, const DWORD *lpStyle = NULL);

Aşağıdaki örnekte tipik olarak WM_PAINT mesajında bir kalem nesnesinin yaratılıp seçilerek kullanılması görülmektedir:

void CMainWnd::OnPaint(void){

CPaintDC dc(this);CPen pen(PS_SOLID, 1,RGB(255, 255, 0));

dc.SelectObject(&pen);dc.MoveTo(100, 100);dc.LineTo(200, 200);}

Bu örnekte her WM_PAINT mesajı geldiğinde CPen türünden yerel nesne yeniden yaratılıp handle alınacaktır. Küçük uygulamalar için bu yöntemin tasarımı basit olduğundan herhangi bir olumsuz durum oluşmaz. Ancak çizim işlemlerinin daha hızlı yapılması isteniyorsa ve çok fazla GDI nesnesi yaratılıyorsa GDI nesnelerinin WM_CREATE mesajı içerisinde bir kez yaratılması daha uygun bir çözüm olur. Bu durumda GDI sınıf nesneleri ilgili sınıfın veri elemanı olmalıdır.

66

Page 67: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Veri elemanının gösterici mi yoksa düz bir nesne mi olacağı programcının seçimine bağlıdır. Eğer düz nesne olarak alınacaksa nesnelerin default başlangıç fonksiyonu ile yaratılıp WM_CREATE mesajı içerisinde handle değerinin alınması görsel bakımdan daha uygundur.

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

m_pen.CreatePen(PS_SOLID, 1, RGB(255, 255, 0));// .....

}

void CMainWnd::OnPaint(void){

CPaintDC dc(this);

dc.SelectObject(&m_pen);dc.MoveTo(100, 100);dc.LineTo(200, 200);}2001-12-06 Perşembe

8.4.1 KALEMLE ÇİZİLEN ÇİZGİLERİN SİLİNMESİBir şeklin silinmesi zemine bağlı bir olaydır. Silmek demek şekli yeniden zemin rengiyle çizmek demektir. Stoktaki NULL_PEN kaleminin silmeyle bir ilişkisi yoktur. Bu kalem çizme eylemini hiç yapmaz. Ancak zemin saf bir renkte değilse örneğin bir bitmap'ten oluşuyorsa bir çizgiyi silmek mümkün olmayabilir. Çünkü silmek demek zemini çizme işleminden önceki duruma getirmek demektir. Bu nedenle Win32'de bir kalem yalnızca çizme yapmaz, aynı zamanda istenirse çizilen yerdeki pixel ile kalem arasında bit dönüşümleri yapılarak da çizim yapılabilir. Bu işlemlere "raster işlemleri" denir. DC yaratıldığında kalem için default raster durumu R2_COPYPEN biçimindedir. R2_COPYPEN kalem renginin doğrudan o andaki zeminin rengi dikkate alınmaksızın zemin üzerinde çizilmesidir. Default raster modu SetROP2 fonksiyonuyla değiştirilebilmektedir.

int SetROP2(HDC hDC, int fnDrawMode);

Fonksiyonun ikinci parametresi uygulanacak raster işlemini belirtir. Bu parametre R2_XXX biçiminde sembolik sabitlerle oluşturulur. SetROP2 fonksiyonu MFC'de CDC sınıfının üye fonksiyonu biçiminde bulunmaktadır.

BINARY RASTER İŞLEMLERİ

ROP2 FORMUL TanımlamaR2_BLACK D = 0 RGB modda 0R2_NOTMERGEPEN D = ~(D | P) R2_MERGEPEN in tersiR2_MASKNOTPEN D = D & ~P Kalemin tersi ile hedef bağlanmışR2_NOTCOPYPEN D = ~P Kalemin tersiR2_MASKPENNOT D = P & ~D Hedefin tersi kalemle bağlanmışR2_NOT D = ~D Hedefin tersiR2_XORPEN D = D ^ PR2_NOTMASKPEN D = ~(D & P)R2_MASKPEN D = D & PR2_NOTXORPEN D = ~(D ^ P)R2_NOP D = D Değişiklik yokR2_MERGENOTPEN D = D | ~DR2_COPYPEN D = PR2_MERGEPENNOT D = P | ~DR2_MERGEPEN D = P | DR2_WHITE D = 1 RGB modda 1

8.4.2 Stoktaki KalemlerNormal olarak bir kalemin API düzeyinde CreatePen fonksiyonuyla yaratılması gerekir. Ancak bazı temel kalemler Windows içerisinde zaten yaratılmış bir biçimde bulunmaktadır. GetStockObject API fonksiyonuyla stoktaki kalemlerin handle değerlerini elde edebiliriz ve doğrudan kullanabiliriz.

67

Page 68: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

HGDIOBJ GetStockObject(int fnObject);

MFC'de stoktaki çizim bileşenleri CGdiObject::CreateStockObject fonksiyonuyla alınabilir.

BOOL CGdiObject::CreateStockObject(int nIndex);

Bu fonksiyon kendi içerisinde GetStockObject API fonksiyonunu çağırarak stoktaki bileşeni alır ve sınıfın handle elemanına yazar. Bu durumda stoktaki WHITE_PEN kaleminin alınarak DC'ye bağlanması aşağıdaki gibi yapılabilir:

CPen pen;pen.CreateStockObject(WHITE_PEN);dc.SelectObject(pen);

8.4.3 Nesne Yönelimli Örnek Bir Çizim ProgramıÖrnek uygulamada uygulamaya ve ana pencereye ilişkin sınıflar PAINT.H ve PAINT.CPP dosyaları biçiminde oluşturulmuştur. Örnek uygulama elips, dikdörtgen ve çizgi çizilmesine olanak sağlamaktadır. Bütün şekiller fareyle çekilerek oluşturulur. Şekiller oluşturulduktan sonra WM_PAINT mesajında yeniden çizilebilmeleri için bir bağlı listede saklanır. WM_MOUSEMOVE içerisinde hangi şeklin çizileceğine karar vermek yerine sanal fonksiyon mekanizması ile işlem halledilmiştir. Çizim nesneleri aşağıdaki gibi ortak bir taban sınıftan türetilen sınıflarla temsil edilmiştir.

CShape

CEllipse CRectangle CLine

CShape sınıfı soyut bir sınıftır. DrawMouse ve DrawPaint isimli iki saf sanal fonksiyona sahiptir. DrawMouse sanal fonksiyonu her sınıf için yeniden yazılmıştır. Bu fonksiyon fareyi sürükledikçe sınıfla temsil edilen şeklin çizilmesini sağlar. DrawPaint fonksiyonu ise WM_PAINT mesajında çizimi sağlar. Uygulamanın polymorphic olmasının anlamı şudur: WM_MOUSEMOVE mesajında o anda çizilmekte olan şeklin türünü bilmek zorunda değiliz. Yalnızca CShape türünden bir gösterici ile DrawMouse sanal fonksiyonunu çağırırız. Şekil hangi şekilse o sınıfın DrawMouse fonksiyonu çağrılacağından ilgili şekil çizilecektir. Ayrıca şekillerin hepsi heap üzerinde tahsis edilirse ve adresleri bir veri yapısında saklanırsa WM_PAINT mesajında tek yapılacak şey bu veri yapısından nesne adresleri elde edilip DrawPaint sanal fonksiyonunun çağrılmasıdır. Böylece şeklin ne şekli olduğunu bilmeden WM_PAINT mesajı içerisinde bütün şekilleri yeniden çizebiliriz.

Menülerden seçim yaptığımızda seçim yapılmış eleman "checked" duruma geçirilir. Herhangi bir anda hangi şeklin ve rengin seçilmiş olduğu CMainWnd sınıfının m_shapeID ve m_colorID elemanlarında saklanmaktadır. Ayrıca bir renk seçildiğinde seçilen rengin RGB değeri m_color elemanında saklanmaktadır. Fareyle sol tuşa basıldığında menüden hangi şekil seçilmişse o şeklin temsil edildiği sınıf türünden bir nesne dinamik olarak yaratılır ve m_pCurrentShape veri elemanında saklanır. Yani m_pCurrentShape o anda işlem yapılmakta olan şekil türünden bir nesnenin adresini tutmaktadır. Daha önceden belirtildiği gibi fareyle sürükleme yapıldığında m_pCurrentShape kullanılarak DrawMouse sanal fonksiyonu çağrılmıştır. DrawMouse fonksiyonunun iki parametresi vardır. Birinci parametresi çizimde kullanılacak DC, ikinci parametresi farenin sürüklenmesi sırasında farenin o andaki koordinatıdır.

CEllipse ve CRect sınıfları yapı bakımından birbirine çok benzerdir. Line aslında noktalardan oluşan bir topluluktur. Bu nedenle CLine sınıfının içerisinde bir bağlı liste alınarak line'ı oluşturan noktalar bu listede saklanmıştır. Tabii kullanan kişi için CLine sınıfının CRectangle sınıfından hiçbir farkı yoktur. İkisi de dışarıdan bakıldığında aynı arabirime sahiptir. CLine bu karmaşıklığı kendi içerisinde halletmektedir.

68

Page 69: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

//paint.h#ifndef _PAINT_H_#define _PAINT_H_

#include<list>#include"Shape.h"

class CGenericApp : public CWinApp{public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd{public:

CMainWnd(void);~CMainWnd(void);afx_msg void OnMouseMove(UINT nKey, CPoint pt);afx_msg void OnLButtonDown(UINT nKey, CPoint pt);afx_msg void OnLButtonUp(UINT nKey, CPoint pt);afx_msg void OnFileExit(void);afx_msg void OnShapeEllipse(void);afx_msg void OnShapeRectangle(void);afx_msg void OnShapeLine(void);afx_msg void OnColorRed(void);afx_msg void OnColorGreen(void);afx_msg void OnColorBlue(void);afx_msg void OnColorBlack(void);afx_msg void OnPaint(void);

private:CMenu *m_pMenu;std::list<CShape *>m_list;CPoint m_prevPoint;COLORREF m_color;int m_shapeID;int m_colorID;CShape *m_pCurrentShape;DECLARE_MESSAGE_MAP()

};#endif

//paint.cpp#include<afxwin.h>#include"ellipse.h"#include"rectangle.h"#include"line.h"#include"paint.h"#include"resource.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_MOUSEMOVE()ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_PAINT()ON_COMMAND(ID_FILE_EXIT, OnFileExit)ON_COMMAND(ID_SHAPE_ELLIPSE, OnShapeEllipse)ON_COMMAND(ID_SHAPE_RECTANGLE, OnShapeRectangle)ON_COMMAND(ID_SHAPE_LINE, OnShapeLine)

69

Page 70: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

ON_COMMAND(ID_COLOR_RED, OnColorRed)ON_COMMAND(ID_COLOR_GREEN, OnColorGreen)ON_COMMAND(ID_COLOR_BLUE, OnColorBlue)ON_COMMAND(ID_COLOR_BLACK, OnColorBlack)

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd ->ShowWindow(m_nCmdShow);m_pMainWnd ->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "Paint Programı", WS_OVERLAPPEDWINDOW, rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU1));

m_pMenu = new CMenu();m_pMenu ->Attach(GetMenu()->m_hMenu);m_pMenu->CheckMenuItem(ID_SHAPE_ELLIPSE, MF_CHECKED|MF_BYCOMMAND);m_shapeID = ID_SHAPE_ELLIPSE;m_pMenu->CheckMenuItem(ID_COLOR_BLACK, MF_CHECKED|MF_BYCOMMAND);m_colorID = ID_COLOR_BLACK;

}CMainWnd::~CMainWnd(void){

delete m_pMenu;}void CMainWnd::OnMouseMove(UINT nKey, CPoint pt){

if(!(nKey&MK_LBUTTON))return;

CDC *pDC = GetDC();m_pCurrentShape->DrawMouse(pDC, pt);m_prevPoint = pt;ReleaseDC(pDC);

}

void CMainWnd::OnLButtonDown(UINT nKey, CPoint pt){

m_prevPoint = pt;switch(m_shapeID){case ID_SHAPE_ELLIPSE:

m_pCurrentShape = new CEllipse(pt, pt, m_color);break;

case ID_SHAPE_RECTANGLE:m_pCurrentShape = new CRectangle(pt, pt, m_color);break;

case ID_SHAPE_LINE:m_pCurrentShape = new CLine(pt, m_color);break;

}}

void CMainWnd::OnLButtonUp(UINT nKey, CPoint pt){

m_list.push_back(m_pCurrentShape);}

void CMainWnd::OnFileExit(void){

DestroyWindow();}

void CMainWnd::OnShapeEllipse(){

70

Page 71: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

m_pMenu->CheckMenuItem(m_shapeID, MF_UNCHECKED|MF_BYCOMMAND);m_pMenu->CheckMenuItem(ID_SHAPE_ELLIPSE, MF_CHECKED|MF_BYCOMMAND);m_shapeID = ID_SHAPE_ELLIPSE;

}

void CMainWnd::OnShapeRectangle(){

m_pMenu->CheckMenuItem(m_shapeID, MF_UNCHECKED|MF_BYCOMMAND);m_pMenu->CheckMenuItem(ID_SHAPE_RECTANGLE, MF_CHECKED|MF_BYCOMMAND);m_shapeID = ID_SHAPE_RECTANGLE;

}

void CMainWnd::OnShapeLine(){

m_pMenu->CheckMenuItem(m_shapeID, MF_UNCHECKED|MF_BYCOMMAND);m_pMenu->CheckMenuItem(ID_SHAPE_LINE, MF_CHECKED|MF_BYCOMMAND);m_shapeID = ID_SHAPE_LINE;

}

void CMainWnd::OnColorRed(){

m_pMenu->CheckMenuItem(m_colorID, MF_UNCHECKED|MF_BYCOMMAND);m_pMenu->CheckMenuItem(ID_COLOR_RED, MF_CHECKED|MF_BYCOMMAND);m_colorID = ID_COLOR_RED;m_color = RGB(255,0,0);

}

void CMainWnd::OnColorGreen(){

m_pMenu->CheckMenuItem(m_colorID, MF_UNCHECKED|MF_BYCOMMAND);m_pMenu->CheckMenuItem(ID_COLOR_GREEN, MF_CHECKED|MF_BYCOMMAND);m_colorID = ID_COLOR_GREEN;m_color = RGB(0,255,0);

}

void CMainWnd::OnColorBlue(){

m_pMenu->CheckMenuItem(m_colorID, MF_UNCHECKED|MF_BYCOMMAND);m_pMenu->CheckMenuItem(ID_COLOR_BLUE, MF_CHECKED|MF_BYCOMMAND);m_colorID = ID_COLOR_BLUE;m_color = RGB(0,0,255);

}

void CMainWnd::OnColorBlack(){

m_pMenu->CheckMenuItem(m_colorID, MF_UNCHECKED|MF_BYCOMMAND);m_pMenu->CheckMenuItem(ID_COLOR_BLACK, MF_CHECKED|MF_BYCOMMAND);m_colorID = ID_COLOR_BLACK;m_color = RGB(0,0,0);

}

void CMainWnd::OnPaint(){

CPaintDC dc(this);std::list<CShape *>::iterator iter;

for(iter=m_list.begin(); iter !=m_list.end(); ++iter)(*iter)->DrawPaint(&dc);

}// Shape.h: interface for the CShape class.#if !defined(AFX_SHAPE_H__3860F65D_8BC6_4651_8801_6F1D97E137C2__INCLUDED_)#define AFX_SHAPE_H__3860F65D_8BC6_4651_8801_6F1D97E137C2__INCLUDED_

#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000

class CShape {public:

71

Page 72: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CShape();virtual ~CShape();virtual void DrawPaint(CDC *pDC) = 0;virtual void DrawMouse(CDC *pDC, const CPoint &pt) = 0;

};#endif // !defined(AFX_SHAPE_H__3860F65D_8BC6_4651_8801_6F1D97E137C2__INCLUDED_)// Shape.cpp: implementation of the CShape class.#include<afxwin.h>#include "Shape.h"// Construction/Destruction

CShape::CShape(){

}

CShape::~CShape(){

}#if !defined(AFX_ELLIPSE_H__9DABFDBC_0F63_4260_9957_61821F7EB700__INCLUDED_)#define AFX_ELLIPSE_H__9DABFDBC_0F63_4260_9957_61821F7EB700__INCLUDED_

#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000

#include "Shape.h"

class CEllipse : public CShape {public:

CEllipse(const CPoint &leftTop, const CPoint &rightBottom, COLORREF color);virtual ~CEllipse();virtual void DrawPaint(CDC *pDC);virtual void DrawMouse(CDC *pDC, const CPoint &pt);

private:CPoint m_leftTop;CPoint m_rightBottom;COLORREF m_color;

};#endif // !defined(AFX_ELLIPSE_H__9DABFDBC_0F63_4260_9957_61821F7EB700__INCLUDED_)

// ellipse.cpp: implementation of the Cellipse class.#include<afxwin.h>#include "ellipse.h"

// Construction/DestructionCEllipse::CEllipse(const CPoint &leftTop, const CPoint &rightBottom, COLORREF color){

m_leftTop = leftTop;m_rightBottom;m_color = color;

}

CEllipse::~CEllipse(){

}

void CEllipse::DrawPaint(CDC *pDC){

CPen colorPen(PS_SOLID, 1, m_color);CPen *pOldPen = pDC->SelectObject(&colorPen);

pDC->Ellipse(CRect(m_leftTop, m_rightBottom));pDC->SelectObject(pOldPen);

}

void CEllipse::DrawMouse(CDC *pDC, const CPoint &pt)

72

Page 73: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

{CPen whitePen, colorPen(PS_SOLID, 1, m_color);CRect rect;

whitePen.CreateStockObject(WHITE_PEN);CPen *pOldPen = pDC->SelectObject(&whitePen);pDC->Ellipse(CRect(m_leftTop, m_rightBottom));

pDC->SelectObject(&colorPen);pDC->Ellipse(CRect(m_leftTop, pt));

pDC->SelectObject(pOldPen);m_rightBottom = pt;

}

// Rectangle.h: interface for the CRectangle class.#if !defined(AFX_RECTANGLE_H__737FAC30_32E2_4DF7_BAFD_131D62725736__INCLUDED_)#define AFX_RECTANGLE_H__737FAC30_32E2_4DF7_BAFD_131D62725736__INCLUDED_

#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000

#include "Shape.h"

class CRectangle : public CShape {public:

CRectangle(const CPoint &leftTop, const CPoint &rightBottom, COLORREF color);virtual ~CRectangle();virtual void DrawPaint(CDC *pDC);virtual void DrawMouse(CDC *pDC, const CPoint &pt);

private:CPoint m_leftTop;CPoint m_rightBottom;COLORREF m_color;

};#endif // !defined(AFX_RECTANGLE_H__737FAC30_32E2_4DF7_BAFD_131D62725736__INCLUDED_)

// Rectangle.cpp: implementation of the CRectangle class.#include<afxwin.h>#include "Rectangle.h"

// Construction/Destruction

CRectangle::CRectangle(const CPoint &leftTop, const CPoint &rightBottom, COLORREF color){

m_leftTop = leftTop;m_rightBottom = rightBottom;m_color = color;

}

CRectangle::~CRectangle(){

}

void CRectangle::DrawPaint(CDC *pDC){

CPen colorPen(PS_SOLID, 1, m_color);CPen *pOldPen = pDC->SelectObject(&colorPen);

pDC->Rectangle(CRect(m_leftTop, m_rightBottom));pDC->SelectObject(pOldPen);

}

void CRectangle::DrawMouse(CDC *pDC, const CPoint &pt)

73

Page 74: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

{CPen whitePen, colorPen(PS_SOLID, 1, m_color);CRect rect;

whitePen.CreateStockObject(WHITE_PEN);CPen *pOldPen = pDC->SelectObject(&whitePen);pDC->Rectangle(CRect(m_leftTop, m_rightBottom));

pDC->SelectObject(&colorPen);pDC->Rectangle(CRect(m_leftTop, pt));

pDC->SelectObject(pOldPen);m_rightBottom = pt;

}// line.h: interface for the Cline class.#if !defined(AFX_LINE_H__149A3BDF_AF0F_416C_A4FF_97B58F57159D__INCLUDED_)#define AFX_LINE_H__149A3BDF_AF0F_416C_A4FF_97B58F57159D__INCLUDED_

#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000

#include "Shape.h"#include<list>

class CLine : public CShape {public:

CLine(const CPoint &firstPoint, COLORREF color);virtual ~CLine();virtual void DrawPaint(CDC *pDC);virtual void DrawMouse(CDC *pDC, const CPoint &pt);

private:COLORREF m_color;std::list<CPoint>m_list;

};#endif // !defined(AFX_LINE_H__149A3BDF_AF0F_416C_A4FF_97B58F57159D__INCLUDED_)// line.cpp: implementation of the Cline class.#include<afxwin.h>#include "line.h"

// Construction/DestructionCLine::CLine(const CPoint &firstPoint, COLORREF color){

m_list.push_back(firstPoint);m_color = color;

}

CLine::~CLine(){

}

void CLine::DrawPaint(CDC *pDC){

CPen colorPen(PS_SOLID, 1, m_color);CPen *pOldPen = pDC->SelectObject(&colorPen);std::list<CPoint>::iterator iter;iter = m_list.begin();pDC->MoveTo(*iter);++iter;

for(;iter!= m_list.end(); ++iter)pDC->LineTo(*iter);

pDC->SelectObject(pOldPen);}

void CLine::DrawMouse(CDC *pDC, const CPoint &pt){

74

Page 75: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CPen colorPen(PS_SOLID, 1, m_color);CPen *pOldPen;

pOldPen = pDC->SelectObject(&colorPen);CPoint prev = m_list.back();pDC->MoveTo(prev);pDC->LineTo(pt);pDC->SelectObject(pOldPen);m_list.push_back(pt);

}2001-12-12 Salı

8.5 Şekillerin SürüklenmesiBir şeklin ya da bir pencerenin fareyle sürüklenip bırakılması gibi durumlarla çok sık karşılaşılır. Bunun için iki WM_MOUSEMOVE arasındaki x ve y ötelenme miktarı bulunur ve şekil bu miktar kadar ötelenir. Bunun için WM_LBUTTONDOWN mesajında önceki pozisyonu tutan POINT değişkeni set edilir. Sonra her WM_MOUSEMOVE mesajında mesaja geçirilen POINT değeriyle önceki POINT değeri arasındaki fark hesaplanır ve şekil bu fark kadar ötelenir.

// drag.h: interface for the drag class.#if !defined(AFX_DRAG_H__658593E5_FD58_11D5_83E7_0080AD85CCC7__INCLUDED_)#define AFX_DRAG_H__658593E5_FD58_11D5_83E7_0080AD85CCC7__INCLUDED_

#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000

#define ID_EDIT 100

class CMyGenericApp : public CWinApp {public:

virtual BOOL InitInstance();};

class drag : public CFrameWnd{public:

drag();virtual ~drag();afx_msg void OnLButtonDown(UINT, CPoint);afx_msg void OnLButtonUp(UINT, CPoint);afx_msg void OnMouseMove(UINT, CPoint);afx_msg void OnPaint();

private:CPoint m_prevPoint;CRect rect;bool m_bIsInRect;DECLARE_MESSAGE_MAP()

};

#endif // !defined(AFX_DRAG_H__658593E5_FD58_11D5_83E7_0080AD85CCC7__INCLUDED_)

// drag.cpp: implementation of the drag class.#include <afxwin.h>

75

Page 76: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

#include "drag.h"

BEGIN_MESSAGE_MAP(drag, CFrameWnd)ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_MOUSEMOVE()ON_WM_PAINT()END_MESSAGE_MAP()

CMyGenericApp x;

BOOL CMyGenericApp::InitInstance(){

m_pMainWnd = new drag();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();

return true;}

drag::drag() : rect(10, 20, 100, 100){

Create(NULL, "drag sample");m_bIsInRect = false;

}

drag::~drag(){

}

void drag::OnLButtonDown(UINT nFlags, CPoint pt){

if (rect.PtInRect(pt)) {m_bIsInRect = true;m_prevPoint = pt;

}}

void drag::OnLButtonUp(UINT nFlags, CPoint pt){

m_bIsInRect = false;}

void drag::OnMouseMove(UINT nFlags, CPoint pt){

if(!(nFlags & MK_LBUTTON))return;

if (!m_bIsInRect)return;

CDC *pDC = GetDC();CPen whitePen, *pOldPen;whitePen.CreateStockObject(WHITE_PEN);pOldPen = (CPen *)pDC->SelectObject(&whitePen);pDC->Rectangle(&rect);pDC->SelectObject(pOldPen);CPoint dif = pt - m_prevPoint;rect += dif;pDC->Rectangle(&rect);

m_prevPoint = pt;ReleaseDC(pDC);

}

void drag::OnPaint(){

CPaintDC dc(this);

dc.Rectangle(&rect);

76

Page 77: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

}

Şeklin üzerinde click yapılıp yapılmadığı CRect sınıfının PtInRect üye fonksiyonuyla anlaşılabilir. Ayrıca eğer yalnızca şekil üzerinde click yapıldığında sürükleme olsun isteniyorsa bir flag değişkeni kullanmak gerekir. Yani WM_LBUTTONDOWN mesajında click noktası bölgenin içerisindeyse flag TRUE yapılır, WM_MOUSEMOVE mesajında flag TRUE ise şekil sürüklenir. WM_LBUTTONUP mesajında flag yeniden FALSE yapılır.

8.6 FIRÇA İŞLEMLERİAPI düzeyinde bir fırça CreateSolidBrush ya da CreateBrushIndirect fonksiyonlarıyla kullanılır. Win32'de rectangle, ellipse gibi boyanabilir şekiller otomatik olarak DC'de seçilmiş olan fırçayla boyanmaktadır. Bir fırça yalnızca bir renkten oluşabilir ya da genel olarak fırça desenli olabilir. CreateSolidBrush düz renkli fırça yaratmak için, CreateBrushIndirect desenli fırça yaratmak için kullanılır. Default olarak DC yaratıldığında fırça stokta da bulunan WHITE_BRUSH ile belirtilen fırçadır. MFC'de fırça işlemleri CBrush sınıfıyla temsil edilir. CBrush sınıfı kullanılarak bir fırça iki biçimde yaratılabilir:

1) Default başlangıç fonksiyonuyla nesne yaratılır. Ondan sonra CreateSolidBrush ya da CreateBrushIndirect fonksiyonları çağrılarak handle elde edilir.

2) Doğrudan sınıfın parametreli başlangıç fonksiyonu ile fırça yaratılarak handle elde edilebilir.

Sınıfın başlangıç fonksiyonları şunlardır:CBrush::CBrush();

CBrush::CBrush(COLORREF crColor);throw(CResourceException);

CBrush::CBrush(int nIndex, COLORREF crColor);throw(CResourceException);

CBrush::CBrush(CBitmap *pBitmap);throw(CResourceException);

Sınıfın bitiş fonksiyonu DeleteObject API fonksiyonunu çağırarak fırça nesnesini geri bırakır.

Fırça default başlangıç fonksiyonuyla yaratılırsa handle aşağıdaki fonksiyonlarla alınabilir:

BOOL CBrush::CreateSolidBrush(COLORREF crColor);

BOOL CBrush::CreateHatchBrush(int nIndex, COLORREF crColor);

BOOL CBrush::CreateBrushIndirect(const LOGBRUSH *lpLogBrush);

BOOL CBrush::CreatePatternBrush(CBitmap *pBitmap);

8.7 Pencerenin Zemin Renginin DeğiştirilmesiAPI düzeyinde pencere zemin renginin oluşumu şöyledir:

1) WNDCLASS yapısının hbrBackground elemanına bir fırçanın handle değeri girilir ve pencere bu sınıfla yaratılır.

2) WM_PAINT mesajında BeginPaint API fonksiyonu çağrılır. BeginPaint kendi içerisinde WM_ERASEBKGND mesajını yollar.

3) DefWindowProc WM_ERASEBKGND mesajında GetClassLong fonksiyonuyla belirlenen fırçayı alır. FillRect fonksiyonuyla zemini boyar.

MFC'de pencerelerin yaratılacağı WNDCLASS yapısını programcı oluşturmaz. Bu durumda zemin için gereken fırçayı da programcı tespit edemez. O halde bu fırçayı daha sonra değiştirmesi gerekir. Sınıfın fırçası SetClassLong fonksiyonuyla değiştirilebilir. Bu fonksiyon bir sınıfın üye fonksiyonu biçiminde MFC'ye eklenmemiştir. Yani MFC'de de SetClassLong API

77

Page 78: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

fonksiyonunu kullanmak gerekir. Bu durumda MFC'de işlemler şöyle yapılır: WM_CREATE mesajında fırça oluşturulur ve SetClassLong fonksiyonuyla sınıf yapısına yerleştirilir.

m_pBrush = new CBrush(RGB(255, 0, 0));

::SetClassLong(m_hWnd, GCL_HBRBACKGROUND, (LONG)m_pBrush->m_hObject);

Sınıf Çalışması

İskelet MFC programını kullanarak kırmızı zeminli bir pencere yaratınız.

// drag.cpp: implementation of the drag class.#include <afxwin.h>#include "drag.h"BEGIN_MESSAGE_MAP(drag, CFrameWnd)ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_MOUSEMOVE()ON_WM_PAINT()END_MESSAGE_MAP()

CMyGenericApp x;

BOOL CMyGenericApp::InitInstance(){

m_pMainWnd = new drag();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();

return true;}

drag::drag() : rect(30, 10, 100, 100){

Create(NULL, "drag sample backgroud color");m_bIsInRect = false;m_pBrush = new CBrush(RGB(255, 0, 0));::SetClassLong(m_hWnd, GCL_HBRBACKGROUND, (LONG)m_pBrush->m_hObject);

}

drag::~drag(){

}

void drag::OnLButtonDown(UINT nFlags, CPoint pt){

if (rect.PtInRect(pt)) {m_bIsInRect = true;m_prevPoint = pt;

}}

void drag::OnLButtonUp(UINT nFlags, CPoint pt){

m_bIsInRect = false;}

78

Page 79: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void drag::OnMouseMove(UINT nFlags, CPoint pt){

if(!(nFlags & MK_LBUTTON))return;

if (!m_bIsInRect)return;

CDC *pDC = GetDC();CPen whitePen, *pOldPen;whitePen.CreateStockObject(WHITE_PEN);pOldPen = (CPen *)pDC->SelectObject(&whitePen);pDC->Rectangle(&rect);pDC->SelectObject(pOldPen);CPoint dif = pt - m_prevPoint;rect += dif;pDC->Rectangle(&rect);

m_prevPoint = pt;ReleaseDC(pDC);

}

void drag::OnPaint(){

CPaintDC dc(this);

dc.Rectangle(&rect);}

2001-12-13 Perşembe

8.8 KULLANICI MESAJLARIBilindiği gibi bir pencereye istediğimiz bir mesajı yollayabiliriz. Ancak mesaj numarasının Windows'un standart XXX mesaj numaralarıyla karışmaması gerekir. WM_USER ile belirtilen sayıdan 0x7FFF'e kadar olan numaralar programcının kullanabileceği programcının kullanabileceği yani boş olan mesaj numaralarıdır. Programcı kullanıcı mesajlarıyla faydalı işlemler yapabilir. WM_USER ile belirtilen numaradan başlayarak genel olarak mesaj numaraları WM_USER+n biçiminde türetilebilir. MFC'de kullanıcı mesajlarını işlemek için mesaj haritasına ON_MESSAGE makrosu yerleştirilir. Bu makro iki parametrelidir:

ON_MESSAGE(messageno, Func)

Makronun birinci parametresi oluşan mesajın numarası, ikinci parametresiyse çağrılacak üye fonksiyonun adresidir. Üye fonksiyonun şu prototipe sahip olması gerekir:

LRESULT Func(WPARAM wParam, LPARAM lParam);

Sınıf Çalışması

İskelet MFC programını kullanarak ana pencerenin üzerine fareyle click yapıldığında ana pencereye WM_USER numaralı mesajı gönderiniz. Bu mesajı işleyerek message box ile durumu belirtiniz. WM_USER numaralı mesajın wParam ve lParam parametreleri kullanılmadığı için sıfırlanabilir. //USERMESSAGE.H#ifndef _USERMESSAGE_H_#define _USERMESSAGE_H_

#define WM_USER 0x100

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {

79

Page 80: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

public:CMainWnd(void);afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg LRESULT OnMessage(WPARAM wParam, LPARAM lParam);

DECLARE_MESSAGE_MAP()};

#endif

USERMESSAGE.CPP

#include <afxwin.h>#include "UserMessage.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_LBUTTONDOWN()ON_MESSAGE(WM_USER, OnMessage)

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "User Message Application", WS_OVERLAPPEDWINDOW);}

LRESULT CMainWnd::OnMessage(WPARAM wParam, LPARAM lParam){

MessageBox("Message from User");

return TRUE;}

void CMainWnd::OnLButtonDown(UINT nFlags, CPoint point){

SendMessage(WM_USER, 0, 0);}

80

Page 81: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

9 MENÜ İŞLEMLERİ

Menü terminolojisi şöyledir:

Normal olarak pull-down menü kaynaktan hareketle ana pencere yaratıldığında otomatik olarak CreateWindow fonksiyonu tarafından yaratılmaktadır. Aslında pull-down menü sisteminin oluşturulması bir dizi işlem ile gerçekleştirilmektedir. Bir pull-down menü sistemi manuel olarak programın belli bir aşamasında yaratılmak istense API düzeyinde şu aşamalardan geçmek gerekir:

1) CreateMenu fonksiyonuyla pull-down menü çubuğu yaratılır.

2) CreatePopupMenu fonksiyonuyla popup menüler yaratılır.

3) InsertMenuItem, AppendMenu gibi fonksiyonlarla bu popup menüler menü çubuğuna bağlanır. Böylece pull-down menü sistemi oluşturulmuş olur.

HMENU CreateMenu(void);

HMENU CreatePopupMenu(void);

BOOL InsertMenuItem(HMENU hMenu, UINT uItem, BOOL fByPosition,LPCMENUITEMINFO lpmii);

BOOL AppendMenu(HMENU hMenu, UINT uFlags, UINT_PTR uIDNewItem,LPCTSTR lpNewItem);

Hem pull-down menü çubuğunun hem de popup menülerin her birinin birer handle değeri vardır. Bir pull-down menü sisteminin kullanılabilmesi için bir pencereyle ilişkilendirilmesi gerekir. Bu işlem SetMenu fonksiyonuyla yapılmaktadır. Benzer biçimde GetMenu fonksiyonu pencereyle ilişkilendirilmiş olan pull-down menünün handle değerini alır. İstenirse SetMenu fonksiyonu kullanılarak menü sistemi dinamik olarak değiştirilebilir.

HMENU GetMenu(HWND hWnd);

BOOL SetMenu(HWND hWnd, HMENU hMenu); Menünün hem kaynaktan hareketle yaratılması hem de dinamik yaratılması mümkündür. Kaynaktan hareketle yaratılacaksa bütün menü sistemi kaynakta belirtilir. Sonra LoadMenu fonksiyonuyla menü kaynağı yüklenir. LoadMenu aslında pull-down menü sistemini yukarıda açıklanan API fonksiyonlarını kullanarak kendi içerisinde dinamik bir biçimde yaratarak işlemi kolaylaştırmaktadır. LoadMenu fonksiyonuyla alınan handle değeri iki biçimde kullanılabilir:

1) CreateWindow fonksiyonuna parametre yapılır.

2) SetMenu fonksiyonuyla daha sonra set edilir.

81

File Edit

Menü elemanları

Menü çubuğu

Popup menüler

Pull-down

menü sistemi

Page 82: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Sınıf Çalışması

İskelet MFC programını kullanarak kaynakta iki menü yaratınız. Her iki menüyü de WM_CREATE mesajında yükleyiniz. Menülerin handle değerlerini sınıfın veri elemanlarında saklayınız. Sol tuşa basıldığında birinci menüyü, sağ tuşa basıldığında ikinci menüyü görüntüleyiniz. Bütün menü işlemleri API fonksiyonlarıyla yapılacaktır. //PULLDOWN.H#ifndef _PULLDOWN_H_#define _PULLDOWN_H_

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);afx_msg void OnLButtonDown(UINT nFlags, POINT point);afx_msg void OnRButtonDown(UINT nFlags, POINT point);

private:HMENU m_hMenu1;HMENU m_hMenu2;

DECLARE_MESSAGE_MAP()};

#endif

//PULLDOWN.CPP#include <afxwin.h>#include "Pulldown.h"#include "resource.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_LBUTTONDOWN()ON_WM_RBUTTONDOWN()

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "Generic MFC Application", WS_OVERLAPPEDWINDOW);}

void CMainWnd::OnLButtonDown(UINT nFlags, POINT point){

m_hMenu1 = ::LoadMenu(theApp.m_hInstance, MAKEINTRESOURCE(IDR_MENU1));::SetMenu(m_hWnd, m_hMenu1);

}

void CMainWnd::OnRButtonDown(UINT nFlags, POINT point){

m_hMenu2 = ::LoadMenu(theApp.m_hInstance, MAKEINTRESOURCE(IDR_MENU2));::SetMenu(m_hWnd, m_hMenu2);

}

82

Page 83: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

9.1 MFC'de Menü IşlemleriMFC'de menü işlemleri CMenu sınıfıyla temsil edilmiştir.

CObject CMenu

CMenu sınıfı yalnızca pull-down menü çubuğu için değil aynı zamanda popup menüler için de kullanılmaktadır. Sınıfın m_hMenu elemanı vardır. Bu eleman menünün handle değerini tutar. Sınıfın CreateMenu fonksiyonu pull-down menü çubuğu yaratmak için, CreatePopupMenu fonksiyonu popup menü yaratmak için kullanılır. Ayrıca sınıfın LoadMenu fonksiyonu LoadMenu API fonksiyonunu çağırarak kaynaktan işlem yapabilmektedir. CMenu sınıfının bütün üye fonksiyonları API düzeyinde menü handle değerini parametre alan fonksiyonlarla eşdeğerdir.

CWnd sınıfının GetMenu isimli üye fonksiyonu GetMenu API fonksiyonunun MFC karşılığıdır.

CMenu *CWnd::GetMenu(void) const;

CMenu sınıfının da handle ve nesne adreslerini tutan kalıcı ve geçici global handle tablosu vardır. GetMenu fonksiyonunun geri verdiği adres geçici handle tablosu için tahsis edildiğinden idle process sırasında silinebilir. O nedenle o adres saklanmamalıdır. Eğer programın pull-down menüsü kalıcı bir CMenu nesnesiyle ilişkilendirilmek isteniyorsa o zaman şöyle bir yöntem izlenebilir:

CMenu m_menu;//.....m_menu.Attach(GetMenu()->m_hMenu);

Bilindiği gibi bir menü elemanı üzerinde işlem uygulamak için CheckMenuItem, EnableMenuItem gibi fonksiyonlar kullanılır. Bu API fonksiyonları menünün handle değerini parametre olarak aldıkları için MFC'de CMenu sınıfının üye fonksiyonu yapılmışlardır.

UINT CMenu::EnableMenuItem(UINT nIDEnableItem, UINT nEnable);

UINT CMenu::CheckMenuItem(UINT nIDEnableItem, UINT nEnable);

Fonksiyonların ikinci parametresi iki grup sembolik sabitin bit or işlemine sokulmasıyla elde edilir.

Birinci grup : MF_BYCOMMAND, MF_BYPOSITION

İkinci grup : MF_DISABLED, MF_ENABLED, MF_GRAYED, MF_CHECKED, MF_UNCHECKED

Birinci grup birinci parametrenin nasıl olduğunu belirlemekte kullanılır. MF_BYCOMMAND birinci parametrede belirtilenin menü ID değeri olduğunu anlatır (genellikle bu tercih edilir). MF_BYPOSITION birinci parametrede belirtilenin menü elemanının sıra numarası olduğunu anlatır.

Sınıf Çalışması

Menülü bir MFC programı yaratınız. Default olarak bir menü elemanı checked durumda olsun. O menü elemanını seçtiğimizde unchecked, yeniden seçtiğimizde checked biçiminde durumunu değiştiriniz. //MENUCHECK.H

#ifndef _MENUCHECK_H_#define _MENUCHECK_H_

class CGenericApp : public CWinApp {public:

virtual BOOL InitInstance(void);};

83

Page 84: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

class CMainWnd : public CFrameWnd {public:

CMainWnd(void);afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnFileOpen(void);

private:int m_bChecked;

DECLARE_MESSAGE_MAP()};

#endif

//MENUCHECK.CPP

#include <afxwin.h>#include "MenuCheck.h"#include "resource.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)ON_WM_CREATE()ON_COMMAND(ID_FILE_OPENX, OnFileOpen)

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "Menu Check", WS_OVERLAPPEDWINDOW, rectDefault, NULL,MAKEINTRESOURCE(IDR_MENU1));}

int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

GetMenu()->CheckMenuItem(ID_FILE_OPENX, MF_BYCOMMAND | MF_CHECKED);m_bChecked = TRUE;

return 0;}

void CMainWnd::OnFileOpen(void){

if (m_bChecked) {GetMenu()->CheckMenuItem(ID_FILE_OPENX, MF_BYCOMMAND | MF_UNCHECKED);m_bChecked = FALSE;

}else {

GetMenu()->CheckMenuItem(ID_FILE_OPENX, MF_BYCOMMAND | MF_CHECKED);m_bChecked = TRUE;

}}2001-12-19 Perşembe

9.2 Alt Menü Handle Değerlerinin Elde EdilmesiBir pull-down menü sistemi bilindiği gibi popup menülerden oluşmaktadır. Herhangi bir zaman GetSubMenu API fonksiyonu ile pull-down menünün bir popup menüsünün handle değerini alabiliriz.

84

Page 85: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

HMENU GetSubMenu(HMENU hMenu, int nPos);

Fonksiyonun birinci parametresi pull-down menünün handle değeri, ikinci parametresi hangi popup menü penceresinin handle değerinin elde edileceğini belirtir. Bu sayı 0 orijinlidir. 0 en soldaki yani ilk popup pencere anlamına gelmektedir. Bu işlemin MFC karşılığı CMenu sınıfının GetSubMenu üye fonksiyonudur:

CMenu *CMenu::GetSubMenu(int nPos) const;

Elde edilen CMenu adresi geçici handle tablosunda olduğundan saklanmamalıdır. Örneğin:

CMenu *pMainMenu, *pSubMenu;

pMainMenu = GetMenu();pSubMenu = pMainMenu->GetSubMenu(0);

9.3 MFC'DE UPDATE COMMAND MENÜ İŞLEMLERİWin32'de bir menünün elemanları üzerinde ok tuşlarıyla ilerlendiğinde tıpkı list box kontrolünde olduğu gibi kuyruğa mesaj bırakılmaktadır. Söz konusu olan WM_MENUSELECT mesajı iki durumda gönderilir:

1) Aktif bir menü elemanının ok tuşuyla değiştirildiği durumda.

2) Pull-down menünün popup penceresi görüntülendiğinde.

MFC'de pull-down menünün bir popup menüsü seçildiğinde framework (MFC kütüphanesi) WM_MENUSELECT mesajını kullanarak seçilen popup menüdeki menü elemanları için mesaj makrosunda belirtilen fonksiyonları çağırır. Bir popup menü seçildiğinde hangi menü elemanları için hangi fonksiyonların çağrılacağı ON_UPDATE_COMMAND_UI mesaj makrosuyla belirlenir:

ON_UPDATE_COMMAND_UI(newID, Func)

Örneğin pull-down menünün File popup menüsü Open, Close ve Exit menü elemanlarını içersin. Biz bu üç menü elemanı için de ON_UPDATE_COMMAND_UI makrolarını oluşturmuş olalım. Şimdi File popup menüsü seçildiğinde framework sadece bu popup menünün elemanları için mesaj haritasında ON_UPDATE_COMMAND_UI makrolarını arayacak, bulursa belirtilen fonksiyonları çağıracaktır. Örneğin:

BEGIN_MESSAGE_MAP(.....).....ON_UPDATE_COMMAND_UI(ID_FILE_OPEN, OnFileOpenUI)ON_UPDATE_COMMAND_UI(ID_FILE_CLOSE, OnFileCloseUI)ON_UPDATE_COMMAND_UI(ID_FILE_EXIT, OnFileExitUI).....

END_MESSAGE_MAP()

ON_UPDATE_COMMAND_UI makrolarında belirtilen fonksiyonların parametrik yapısı aşağıdaki gibi olmak zorundadır:

void OnUpdateUI(CCmdUI *pCmdUI);

Fonksiyonun parametresi CCmdUI sınıfı türünden bir göstericidir. Framework CCmdUI sınıfı türünden bir nesne oluşturarak bu nesnenin adresiyle belirtilen fonksiyonu çağırır.

9.3.1 CCmdUI SınıfıBu sınıf menü işlemlerinde kolaylık sağlanması amacıyla tasarlanmıştır. Herhangi bir sınıftan türetilmemiştir. CCmdUI sınıfının makroda belirtilen menü elemanı üzerinde işlem yapmak için kullanılan faydalı üye fonksiyonları ve veri elemanları vardır. Örneğin sınıfın Enable üye

85

Page 86: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

fonksiyonu ilgili menü elemanını enable ya da disable etmek için, SetCheck üye fonksiyonu ilgili menü elemanını check ya da unchecked duruma getirmek için, SetText üye fonksiyonuysa menü elemanının yazısını değiştirmek için kullanılabilir. Ayrıca sınıfın çeşitli veri elemanları faydalı değerlerle yüklenmiştir. Örneğin m_pMenu ve m_pSubMenu elemanları sırasıyla pull-down menünün ya da popup menünün CMenu adreslerini tutar. Sınıfın m_nID elemanı menü ID değerini, m_nIndex elemanıysa index numarasını tutmaktadır. Bu elemanlar genellikle kullanılmaz, ayrıntılı işlemler için gerekir.

9.3.2 UPDATE COMMAND MENÜ İŞLEMLERİ İÇİN ÖRNEK UYGULAMAUpdate command menü işlemleri tipik olarak birbirleriyle ilişkili menü elemanlarının durumlarını izleyebilmek amacıyla kullanılır. Örneğin bir menü sistemi şöyle olsun:

Şöyle bir durum istensin: Shape menüsünden bir seçim yapıldığında seçilen eleman checked, diğerleri unchecked olsun. Ayrıca Ellipse seçiliyse File popup menüsü seçildiğinde Exit grayed hale getirilsin. Bu işlemler update command menü işlemleriyle şu adımlardan geçilerek yapılabilir:

1) Shape menü elemanları için sınıfın birer flag değişkeni tanımlanır.

BOOL m_bCircle, m_bRectangle, m_bEllipse;

2) Sınıfın başlangıç fonksiyonu içerisinde bu flag değişkenleri için ilk değerler verilir. Örneğin m_bCircle için TRUE, diğerleri için FALSE olabilir.

3) Shape menüsünün elemanları için ON_COMMAND makroları yazılır. Hangi menü elemanı seçilmişse ona ilişkin flag değişkeni TRUE, diğerleri FALSE yapılır. Örneğin:

void CMainWnd::OnShapeRectangle(void){

.....m_bRectangle = TRUE;m_bCircle = m_bEllipse = FALSE;

}

4) Shape menü elemanları için ON_UPDATE_COMMAND_UI makroları oluşturulur. Bu fonksiyonlarda flag değişkenlerinin konumuna göre uygun checked işlemleri yapılır.

void CMainWnd::OnShapeRectangleUI(CCmdUI *pCmdUI){

pCmdUI->SetCheck(m_bRectangle);}

void CMainWnd::OnShapeCircleUI(CCmdUI *pCmdUI){

pCmdUI->SetCheck(m_bCircle);}

void CMainWnd::OnShapeEllipseUI(CCmdUI *pCmdUI){

pCmdUI->SetCheck(m_bEllipse);

86

Page 87: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

}

5) Exit menü elemanı için düzenleme benzer biçimde yapılabilir.

void CMainWnd::OnFileExitUI(CCmdUI *pCmdUI){

pCmdUI->Enable(!m_bEllipse);}

//Updatecommand uygulaması//resource.h#define IDR_MENU1 101#define IDB_BITMAP1 103#define ID_FILE_NEWX 40001#define ID_FILE_OPENX 40002#define ID_SHAPE_CIRCLE 40006#define ID_SHAPE_RECTANGLE 40007#define ID_SHAPE_ELLIPSE 40008#define ID_FILE_EXITX 40009

// MenuIDR_MENU1 MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "New...", ID_FILE_NEWX MENUITEM "Open...", ID_FILE_OPENX MENUITEM "&Exit", ID_FILE_EXITX END POPUP "&Shape" BEGIN MENUITEM "&Circle", ID_SHAPE_CIRCLE MENUITEM "&Rectangle", ID_SHAPE_RECTANGLE MENUITEM "&Ellipse", ID_SHAPE_ELLIPSE END MENUITEM "&Help...", 65535END//updatecommand.h#ifndef _UPDATECOMMAND_H_#define _UPDATECOMMAND_H_

class CGenericApp: public CWinApp {public:

virtual BOOL InitInstance(void);};

class CMainWnd : public CFrameWnd{public:

HMENU hMenu1;CMainWnd(void);afx_msg void OnUpdateFileExit(CCmdUI *pCmdUI);afx_msg void OnUpdateShapeCircle(CCmdUI *pCmdUI);afx_msg void OnUpdateShapeRectangle(CCmdUI *pCmdUI);afx_msg void OnUpdateShapeEllipse(CCmdUI *pCmdUI);afx_msg int OnCreate( LPCREATESTRUCT );afx_msg void OnShapeCircle();afx_msg void OnShapeRectangle();afx_msg void OnShapeEllipse();

87

Page 88: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

private:BOOL m_bRectangle, m_bCircle, m_bEllipse;DECLARE_MESSAGE_MAP()

};

#endif

#include <afxwin.h>#include "updatecommand.h"#include "resource.h"

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd) ON_UPDATE_COMMAND_UI(ID_FILE_EXITX, OnUpdateFileExit)

ON_UPDATE_COMMAND_UI(ID_SHAPE_CIRCLE, OnUpdateShapeCircle)ON_UPDATE_COMMAND_UI(ID_SHAPE_RECTANGLE, OnUpdateShapeRectangle)ON_UPDATE_COMMAND_UI(ID_SHAPE_ELLIPSE, OnUpdateShapeEllipse)ON_WM_CREATE()ON_COMMAND(ID_SHAPE_CIRCLE, OnShapeCircle)ON_COMMAND(ID_SHAPE_RECTANGLE, OnShapeRectangle)ON_COMMAND(ID_SHAPE_ELLIPSE, OnShapeEllipse)

END_MESSAGE_MAP()

CGenericApp theApp;

BOOL CGenericApp::InitInstance(void){

m_pMainWnd = new CMainWnd();m_pMainWnd->ShowWindow(m_nCmdShow);m_pMainWnd->UpdateWindow();return TRUE;

}

CMainWnd::CMainWnd(void){

Create(NULL, "Updatecommand Uygulamasi", WS_OVERLAPPEDWINDOW, CRect(100, 100, 450, 300));

m_bCircle = m_bRectangle = m_bEllipse = false;}

int CMainWnd::OnCreate( LPCREATESTRUCT LPC){

hMenu1 = ::LoadMenu(theApp.m_hInstance, MAKEINTRESOURCE(IDR_MENU1));::SetMenu(m_hWnd, hMenu1);return 0;

}

void CMainWnd::OnShapeCircle(){

m_bCircle = true;m_bRectangle = m_bEllipse = false;

}

void CMainWnd::OnShapeRectangle(){

m_bRectangle= true; m_bCircle = m_bEllipse = false;

}

void CMainWnd::OnShapeEllipse(){

m_bEllipse = true; m_bCircle = m_bRectangle = false;}

void CMainWnd::OnUpdateShapeCircle(CCmdUI *pCmdUI){

pCmdUI->SetCheck(m_bCircle);}

88

Page 89: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CMainWnd::OnUpdateShapeRectangle(CCmdUI *pCmdUI){

pCmdUI->SetCheck(m_bRectangle);}

void CMainWnd::OnUpdateShapeEllipse(CCmdUI *pCmdUI){

pCmdUI->SetCheck(m_bEllipse);}

void CMainWnd::OnUpdateFileExit(CCmdUI *pCmdUI){

pCmdUI->Enable(!m_bEllipse);}

2001-12-25 Salı

89

Page 90: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

10 WIZARD KULLANIMIWizard bir uygulamayı belirli bir noktaya kadar programcının belirlediği doğrultuda yazan yardımcı bir araçtır. Aynı belirlemeler karşısında wizard'ın ürettiği kodlar aynıdır. Wizard kullanımı uygulama geliştirme zamanını ciddi biçimde azaltmaktadır. MFC wizard'ları doküman özelliği olan ve olmayan biçiminde iki kısma ayrılır (Visual C 5.0 versiyonunda doküman özelliği olmayan wizard'lar yoktu). Wizard kullanmanın en önemli faydalarından biri de "class wizard" denilen yardımcı bir aracın kullanılmasını sağlamaktır. Bir MFC projesi bir .RC dosyasını projeye eklemişse class wizard View / Class Wizard menüsünden ya da Ctrl+W tuşları kullanılarak açılabilir.

Wizard ile çalışmanın iyi bir biçimde anlaşılabilmesi için wizard'ın kodu hangi noktaya kadar getirdiği ve ana hatlarıyla neler yaptığı bilinmelidir. Wizard kodlarının tam olarak analiz edilmesi uygulama geliştirmek için mutlak gerekli olmasa da ana hatlarıyla ne yapıldığının bilinmesi önemlidir.

Wizard project ayarlarını otomatik olarak oluşturmaktadır. Örneğin MFC kütüphane sisteminin link aşamasında dahil edilmesi işlemi otomatik olarak yapılır. Wizard genel bir kod oluşturmaktadır. Programcı isterse wizard'ın oluşturduğu kodu inceleyerek çeşitli kısımlarını kaldırabilir ya da manuel eklemeler yapabilir.

MFC kütüphane sisteminin ve wizard araçlarının kullandığı en önemli kavramlardan biri view kavramıdır.

10.1 VIEW KavramiView teknik olarak programın ana penceresinin çalışma alanını tamamen kaplayan bir alt penceredir. API düzeyinde view kavramı ana pencerenin WM_CREATE mesajında bir alt pencerenin yaratılması ve WM_SIZE mesajında da bu alt pencerenin ana pencerenin çalışma alanını kaplayacak bir biçime getirilmesi ile sağlanır. MFC'de ise view CWnd sınıfından türetilmiş bir sınıf yardımıyla alt pencere biçiminde oluşturulabilir. MFC'de CWnd sınıfından türetilmiş işlemleri kolaylaştıracak nitelikte çeşitli view sınıfları vardır. Wizard kodu üretirken view penceresi olarak neyin kullanılacağını da sormaktadır. MFC framework programın ana penceresi aktif hale getirildiğinde otomatik olarak klavye odağını view penceresine geçirmektedir. Buradan şu sonuç çıkar: Programın penceresi aktif ise klavye mesajları ana pencereye değil view penceresine gider. Ayrıca çalışma alanı üzerindeki tüm pencere mesajları yine ana pencereye değil view penceresine gönderilir. Programcı çizimleri ana pencere üzerine değil, view penceresi üzerine yapmalıdır. Böylelikle view kavramı ile ana pencere yalnızca programın ana penceresini temsil eden bir duruma getirilmiştir. Programcının view penceresi üzerinde çalışması istenmiştir. Ana pencere ile view penceresinin birbirlerinden ayrılması soyutlamayı arttırmakta ve programlamayı kolaylaştırmaktadır.

10.2 Doküman Özelliği Olmayan MFC Wizard Uygulamasinin YaratilmasiUygulama şu aşamalardan geçilerek yaratılabilir:

1) File / New / MFC AppWizard (EXE) seçilir.

2) Bu seçimden sonra karşımıza yeni bir dialog penceresi çıkar. Burada doküman özelliğini kaldırmak için Document / View architecture support unchecked yapılır ve Single Document radio button seçilir.

3) Next butonuna basılarak bir sonraki adıma geçilebilir ancak default belirlemeler de kabul edilebilir. Bunun için Finish ile işlem sonlandırılır.

Bu biçimde yaratılmış bir uygulama şu özelliklere sahiptir:

1) Uygulama klasik bir menüye, tool bar'a ve status bar'a sahiptir.

2) Uygulamanın bir view penceresi vardır ve ana pencerenin çalışma alanını kaplamış durumdadır.

90

Page 91: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3) Programın menüsü şablon bir menüdür. Programcı kaynak kısmına girerek menüde değişiklikler yapabilir, hatta menüyü tamamen kaldırabilir.

4) Programın status bar penceresi tuşların durumlarını ve menü elemanları seçildiğinde kısa açıklamaları barındıracak biçimde oluşturulmuştur.

Wizard tarafından üretilen dosyalar ve sınıflar şunlardır:

1) STDAFX.H isimli dosya içerisinde AFXWIN.H dosyasının da include edildiği genel bir başlık dosyasıdır. Bu başlık dosyası projedeki bütün .CPP dosyalarından include edilmiştir.

2) STDAFX.CPP isimli içi boş bir dosya üretilmiştir. Genel global tanımlamalar burada yapılabilir.

3) Wizard projenin ismi X olmak üzere X.H ve X.CPP dosyalarını üretir. Bu dosyalarda sırasıyla uygulama sınıfının bildirimi ve üye fonksiyonlarının tanımlaması bulunmaktadır. Uygulama sınıfı CWinApp sınıfından türetilmiş sınıftır. InitInstance üye fonksiyonu X.CPP dosyası içerisindedir. Ayrıca wizard programın Help dialog penceresi için kullanılan CAboutDlg sınıfını da bu dosyaların içerisinde tanımlamıştır. Ayrıca uygulama nesnesine ilişkin global sınıf nesnesi de X.CPP içerisinde tanımlanmıştır.

4) Wizard MAINFRM.H ve MAINFRM.CPP isimli iki dosya üretmiştir. CFrameWnd sınıfından türetilmiş olan ana pencere sınıfının bildirimi ve tanımlanması bu dosyalarda yapılmıştır.

5) Wizard CHILDVIEW.H ve CHILDVIEW.CPP isimli iki dosya oluşturmuştur. Bu dosyalarda CWnd sınıfından türetilen view sınıfının bildirim ve tanımlamaları vardır.

6) Wizard X proje ismi olmak üzere X.RC kaynak dosyasını ve RESOURCE.H başlık dosyasını oluşturmuştur. RESOURCE.H dosyası X.H dosyasının içerisinde include edilmiştir.

7) Tüm .CPP dosyalarından STDAFX.H ile X.H dosyaları include edilmiştir. Yani RESOURCE.H dosyası tüm modüllerde tanınmaktadır. Bu durumda projenin tüm modülerinde tanınacak bir bildirim STDAFX.H ya da X.H dosyası içerisinde yapılmalıdır (X.H dosyası tercih edilir). Örneğin a isimli global bir değişkenin tüm modüllerde tanınması için X.H içerisinde;

extern int a;

bildirimi yapılmalı, X.CPP içerisinde de ;

int a;

tanımlaması yapılmalıdır.

10.3 WIZARD'in Ürettiği Kodun Analizi1) InitInstance fonksiyonunun analizi: InitInstance içerisinde programın ana penceresine ilişkin sınıf nesnesi dinamik olarak tahsis edilmiştir ve CFrameWnd sınıfının LoadFrame üye fonksiyonu çağrılmıştır. LoadFrame fonksiyonu birinci parametresiyle belirtilen kaynak ismini alarak programın ana penceresini yaratır. Win32'de aynı isme sahip farklı türden kaynaklar yaratılabilmektedir. LoadFrame fonksiyonu bu kaynak isminden hareketle aşağıdaki belirlemelerle ana pencereyi yaratır:

a) Aynı isimli string kaynağını programın ana pencere başlık yazısı olarak kullanır.

b) Aynı isimli menü kaynağını programın ana menüsü olarak kullanır.

c) Aynı isimli accelerator kaynağını kısayol tuşları için kullanır.

d) Aynı isimli icon kaynağını programın icon'u olarak kullanır.

2) View penceresine ilişkin sınıf nesnesi ana pencere sınıfının veri elemanı olarak alınmıştır ve ana pencerenin WM_CREATE mesajında view penceresi yaratılmıştır. Ana pencerenin WM_CREATE mesajında şunlar yapılmıştır:

91

Page 92: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

a) View penceresi yaratılmıştır.

b) Tool bar penceresi yaratılmıştır.

c) Status bar penceresi yaratılmıştır.

Ana pencere için mesaj haritası oluşturulmuştur ve ilgili mesaj makroları eklenmiştir.

3) View olarak kullanılan sınıfın mesaj haritası oluşturulmuştur. OnPaint fonksiyonu içi boş olarak yazılmıştır.

Bunların dışında wizard tarafından yazılmış çeşitli fonksiyonlar şimdilik inceleme konusu yapılmayacaktır.

2001-12-27 Perşembe

10.4 CLASS WIZARDClass wizard MFC wizard tarafından yaratılmış olan kod üzerinde geliştirme faaliyetlerinin hızlı yapılması amacıyla tasarlanmış bir araçtır. Class wizard projenin o andaki durumunu *.CLW uzantısında bir dosya ile takip eder. *.CLW dosyası çeşitli sebeplerle silinirse class wizard bu dosyayı kaynak kodlardaki yorumlama satırlarına bakarak yeniden oluşturabilir. Class wizard için kullanılan yorum satırları şöyledir:

// {{ Anahtar sözcük .....

.....// }}

Buradaki anahtar sözcük class wizard için anlamlı olan çeşitli seçeneklerden oluşmaktadır. Özetle class wizard aracı . *.CLW uzantılı bir dosyaya bakarak çalışır. Bu bir text dosyadır. *.CLW dosyası kaynak kod içerisindeki yorum satırlarına bakılarak üretilmektedir. Herhangi bir biçimde bu *.CLW dosyası silinirse class wizard yorum satırlarına bakarak yeniden bu dosyayı oluşturabilir. Ya da bir kod wizard özeliği kullanılmadan yaratılmışsa class wizard'ın projenin o andaki durumunun farkına varabilmesi için manuel olarak programcı tarafından bu yorum satırlarının eklenmesi gerekir. Yorum satırlarının nerelere ekleneceği, // {{ yanındaki anahtar sözcüğün ne olacağı ayrıntılı dokümanlarda belirtilmiştir. Proje geliştirme sırasında class wizard yeni yorum satırları ekleyerek bu *.CLW dosyasını güncellemektedir.

Class wizard'ın görüntülenmesi için projeye bir *.RC dosyası eklenmiş olmalıdır. Bu durumda View / Class wizard ya da Ctrl+W ile class wizard görüntülenebilir. Class wizard 5 adet tab'dan oluşmaktadır. En çok kullanılan tab Message Map tab'ıdır. Bu tab'da Class name isimli bir combo box vardır. Bu combo box'da proje içindeki tüm sınıflar görüntülenir. Object ID's isimli list box'ta proje içerisindeki mesaj oluşturabilme potansiyeline sahip RESOURCE.H dosyası içerisinde tanımlanmış olan çeşitli sembolik sabitler vardır. Buradaki sembolik sabitler ya menü elemanlarının ID değerleridir ya da dialog pencerelerinin üzerindeki kontrol değerlerinin ID değerleridir. Burada bir ID seçilirse (seçme işlemi ID'nin üzerinde double click yapmakla olabilir) class wizard bu ID ile ilişkili olabilecek mesaj olasılıklarını Messages isimli yandaki list box'ta görüntüler. Bu mesajlardan bir tanesinin üzerine gelip double click yapılırsa o mesaj oluştuğunda çağrılacak fonksiyon otomatik olarak class wizard tarafından yazılır. Bunun için class wizard şunları yapmaktadır:

1) İlgili mesaj makrosunu mesaj haritasına yerleştirir.

2) Çağrılacak fonksiyonun prototipini sınıf bildirimi içerisine yerleştirir.

3) Mesaj fonksiyonunun tanımlamasını ilgili *.CPP dosyası içerisinde içi boş olarak yapar.

Bu biçimde seçilmiş olan bütün mesaj fonksiyonları Member functions bölümünde belirtilmektedir. Class wizard'da Object ID's kısmında ID'lerden biri seçilmez sınıf ismi seçilirse Messages list box'ında o sınıfa ilişkin bütün mesaj oluşturabilecek olasılıklar ve sanal fonksiyonlar görüntülenir. Seçilen sınıfa ilişkin tüm WM_ mesajlarının görüntülenmesi isteniyorsa class info tab'ında Message Filter combo box'ında Window seçeneği seçilmelidir.

92

Page 93: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Class wizard ile bir pencere mesajı oluşturulduğunda class wizard bu pencere mesajına ilişkin fonksiyonun tanımlamasında taban sınıfın aynı isimli fonksiyonunu da çağırır. Aslında MFC'de bir mesajı işledikten sonra taban sınıfın fonksiyonunun çağrılması bazı durumlarda önemli olmasına karşın bazı durumlarda da gereksizdir. Ancak class wizard her defasında taban sınıfın aynı isimli fonksiyonunu çağıracak biçimde fonksiyonu tanımlamaktadır. Gerekmediği halde taban sınıfın fonksiyonunun çağrılması önemli bir zaman kaybına yol açmaz.

Sınıf Çalışması

Farenin tuşuna basarak bir dikdörtgen çiziniz. Bu dikdörtgenin koordinatlarını saklayarak WM_PAINT mesajında dikdörtgeni yeniden çiziniz.

93

Page 94: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

11 DIALOG PENCERELERİDialog pencereleri API düzeyinde önce bir dialog kaynağı oluşturularak DialogBox API fonksiyonuyla yaratılır. Dialog pencereleri modal ve modeless olmak üzere ikiye ayrılmaktadır. Modal dialog penceresinde dialog penceresi kapatılana kadar akış dialog pencere fonksiyonunun içerisindeki mesaj döngüsünde kalır. Yani dialog penceresi kapatılmadan kod ilerlemez. Modeless dialog pencereleri seyrek kullanılır. Modeless dialog pencereleri CreateDialog API fonksiyonuyla yaratılır. Dialog kaynağında yaratılacak kontrollerin neler olduğu ve hangi ID'ye sahip olacağı belirtilir. Bu işlemler kaynak editörleriyle yapılmaktadır. Modal dialog pencereleri EndDialog API fonksiyonuyla, modeless dialog pencereleri DestroyWindow fonksiyonuyla kapatılır.

11.1 MFC'de Dialog PencereleriMFC'de dialog pencereleri CWnd sınıfından türetilen CDialog sınıfıyla temsil edilmiştir.

CWnd

CDialog

MFC'de tipik bir modal dialog penceresi şu adımlardan geçilerek oluşturulur:

1) Dialog kaynağı kaynak editörle oluşturulur.

2) CDialog sınıfından bir sınıf türetilir.

CWnd

CDialog

CMyDialog

Yani CDialog sınıfı doğrudan değil türetilerek kullanılmalıdır.

3) CDialog sınıfından türetilmiş sınıf türünden bir nesne tanımlanır. Bu nesne dialog kaynağıyla ilişkilendirilir. CDialog sınıfının dialog kaynak ismini parametre olarak alan bir başlangıç fonksiyonu vardır.

4) Dialog penceresinin açılması CDialog sınıfının DoModal üye fonksiyonuyla yapılır. DoModal üye fonksiyonu DialogBox API fonksiyonunu çağırarak dialog penceresini yaratmaktadır.

11.2 CDialog Sinifinin Başlangiç FonksiyonlariCDialog sınıfının üç başlangıç fonksiyonu vardır. Bu başlangıç fonksiyonlarında temel olarak dialog kaynağının ismiyle dialog penceresinin üst penceresinin handle değerleri belirlenmektedir.

CDialog::CDialog();

Default başlangıç fonksiyonuyla bir belirleme yapılmaz. Belirleme daha sonra sınıfın üye fonksiyonlarıyla yapılabilir.

CDialog::CDialog(LPCTSTR lpszTemplateName, CWnd *pParentWnd = NULL);

Fonksiyonun birinci parametresi dialog kaynağının ismi, ikinci parametresi dialog penceresinin üst penceresinin CWnd adresidir. İkinci parametre NULL olarak geçilirse üst pencere doğrudan

94

Page 95: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

uygulamanın ana penceresi olarak alınır (bu pencere CWinApp sınıfının m_pMainWnd elemanı olarak belirlenmiştir).

CDialog::CDialog(UINT nIDTemplate, CWnd *pParentWnd = NULL);

Bu başlangıç fonksiyonunun öncekinden bir farkı yoktur. Kaynak ismi numaraya göre verilmişse bu başlangıç fonksiyonu kullanılabilir.

CDialog sınıfının DoModal üye fonksiyonu parametresiz bir fonksiyondur.

Bu durumda dialog penceresi yaratmak için CDialog sınıfından bir sınıf türetmek ve bu sınıfın default başlangıç fonksiyonunda : syntax'ıyla CDialog sınıfının parametreli başlangıç fonksiyonunun çağrılmasını sağlamak, daha sonra da DoModal üye fonksiyonunu çağırmak yeterlidir.

CMyDialog dlg;

dlg.DoModal();

Bu işlemler Visual Studio sisteminde pratik biçimde şöyle yapılabilir:

1) Dialog kaynağı kaynak editörde oluşturulur ve dialog kaynağının üzerinde double click yapılır.

2) Karşımıza bir dialog penceresi çıkar. Burada "Create a new class" seçilerek OK tuşuna basılır.

3) CDialog sınıfından türetilecek sınıf ismi istenir.

Bu yöntemle wizard tarafından oluşturulan sınıfın başlangıç fonksiyonu şöyledir:

CMyDialog::CMyDialog(CWnd *pParent) : CDialog(CMyDialog::IDD, pParent){

}

Bu başlangıç fonksiyonu default argüman aldığı için default başlangıç fonksiyonu olarak da kullanılabilmektedir. Bu durumda

CMyDialog dlg;

biçiminde nesne tanımlandığında CDialog sınıfının iki parametreli başlangıç fonksiyonu çağrılmış olur. Birinci parametresi kaynak ismi, ikinci parametresi NULL biçiminde oluşturulmuştur.

Dialog penceresi de bir pencere olduğuna göre onun da mesaj haritası vardır. Bu durumda örneğin dialog penceresinin üzerinde fareyle click yaptığımızda bir işlemin yapılmasını sağlayabiliriz. Bunun için class wizard kullanılırken combo box içerisinde dialog penceresinin seçildiğinden emin olunmalıdır.

2002-01-03 Perşembe

11.3 CDialog::DoModal FonksiyonuDoModal üye fonksiyonu DialogBox API fonksiyonunu çağırarak modal dialog penceresini görüntüler. Bundan sonra akış dialog penceresinin içerisindeki mesaj döngüsünde kalır.

virtual int CDialog::DoModal(void);

DoModal fonksiyonunun geri dönüş değeri dialog penceresinin kapatılması için kullanılan CDialog::EndDialog fonksiyonunda belirlenmektedir.

95

Page 96: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

11.4 CDialog::EndDialog FonksiyonuBu fonksiyon EndDialog API fonksiyonunu çağırarak modal dialog penceresini kapatır. Fonksiyona verilen parametre DoModal fonksiyonunun geri dönüş değeri olacaktır.

void CDialog::EndDialog(int nResult);

11.5 DIALOG PENCERELERİNDEKİ Ok ve Cancel TUŞLARIMFC'de bir dialog penceresi kaynağı oluşturulduğunda default olarak Ok ve Cancel push button kontrolleri yerleştirilmiş durumdadır. Bu kontrollere click yapıldığında framework sırasıyla OnOk ve OnCancel sanal fonksiyonlarını çağırmaktadır (framework içerisinde dialog penceresinin ana penceresine gelen WM_COMMAND mesajları ele alınmış, LOWORD(wParam) değeri kontrol edilmiştir. Bu değerler IDOK ya da IDCANCEL ise belirtilen sanal fonksiyonlar çağrılmıştır). Yani bu push button kontrollerinin ID değerlerinin IDOK ve IDCANCEL biçiminde olması gerekir. CDialog sınıfından türettiğimiz sınıf için OnOk ve OnCancel fonksiyonlarını yazmamışsak kütüphanede bulunan CDialog sınıfınınkiler çağrılacaktır. CDialog sınıfının bu sanal fonksiyonları EndDialog fonksiyonunu çağırarak dialog penceresini kapatmışlardır. Ok tuşu için EndDialog penceresinde kullanılan parametre IDOK, Cancel tuşu için kullanılan parametre IDCANCEL biçimindedir. Bu durumda dialog penceresinden Ok tuşuna basılarak çıkıldığı şöyle anlaşılabilir:

11.6 CDialog::OnOk ve CDialog::OnCancel FonksiyonlarıBu sanal fonksiyonlar framework tarafından Ok ve Cancel tuşlarına basıldığında çağrılırlar.

virtual void CDialog::OnOk(void);

virtual void CDialog::OnCancel(void);

Bu sanal fonksiyonlar türemiş sınıf için yeniden yazılacaksa taban sınıfın fonksiyonu da çağrılmalıdır.

void CMyDialog::OnOk(void){

// .....CDialog::OnOk();

}

Zaten bu fonksiyonlar class wizard ile yaratıldığında iskelet içerisindeki görünüm bu biçimde olacaktır.

11.7 Dialog Pencere SınıfıDialog penceresini yaratmakta kullandığımız sınıf tıpkı diğer sınıflar gibi bir pencere sınıfıdır. Yani bu sınıfın da bir mesaj haritası vardır. Dialog pencereleri de MFC'nin global handle tablosuna yazılmaktadır. Örneğin dialog penceresinin üzerine mesaj haritasını kullanarak çizim yapabiliriz, fare mesajlarını kullanarak ana pencere için işlemler yapabiliriz. Dialog penceresinin üzerindeki kontroller default olarak MFC mekanizmasına dahil değildir. Yani dialog penceresi yaratıldığında üzerindeki kontroller için otomatik olarak CWnd nesneleri oluşturulmaz.

11.8 Dialog Penceresi Üzerindeki Kontrollerle IşlemleriMFC'de de API düzeyinde olduğu gibi dialog penceresi yaratıldığında dialog penceresinin pencere fonksiyonu sırasıyla WM_CREATE ve WM_INITDIALOG mesajlarıyla çağrılır. WM_CREATE mesajı gönderildiğinde dialog penceresinin ana penceresi yaratılmıştır ancak kontroller yaratılmamıştır. WM_INITDIALOG mesajında kontroller de yaratılmıştır. Ancak dialog penceresi görünür durumda değildir. Kontrollerle ilgili birtakım ilk işlemler WM_INITDIALOG içerisinde yapılmalıdır.

96

Page 97: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

MFC'de WM_CREATE mesajları mesaj haritası yoluyla ON_WM_CREATE makrosu ile işlenir. Halbuki WM_INITDIALOG sanal fonksiyon mekanizmasıyla işlenmektedir. Yani framework WM_INITDIALOG mesajını aldığında CDialog::OnInitDialog sanal fonksiyonunu çağıracak biçimde yazılmıştır.

virtual BOOL CDialog::OnInitDialog(void);

Fonksiyonu türemiş sınıf için yazdığımızda normal olarak TRUE değeriyle geri dönmeliyiz. O zaman framework klavye odağını kaynakta belirtilen ilk kontrole yerleştirecektir. FALSE ile geri dönülürse klavye odağı yerleştirilmez. Bu fonksiyon türemiş sınıf için yazılacaksa taban sınıfınki de bilinçli olarak çağrılmalıdır. Zaten class wizard ile bu fonksiyonu oluşturduğumuzda iskelet yapıda taban sınıfınki çağrılmış olacaktır. Örneğin:

BOOL CMyDialog::OnInitDialog(void){

CDialog::OnInitDialog();// .....

return TRUE;}

Dialog penceresi içerisindeki kontroller üzerinde işlem yapmak için onların handle değerlerini, MFC söz konusuysa CWnd adreslerini bilmek zorundayız. API düzeyinde handle GetDlgItem fonksiyonuyla alınır:

HWND GetDlgItem(HWND hWnd, int nID);

MFC'de GetDlgItem fonksiyonu CWnd sınıfının üye fonksiyonu olarak yazılmıştır:

CWnd *CWnd::GetDlgItem(int nID) const;

Dialog penceresi kontrolleri için otomatik birer CWnd nesnesi yaratılmadığı için fonksiyon böyle bir nesneyi yaratarak geçici handle tablosuna yerleştirir ve bu geçici nesne adresiyle geri döner. Bu nedenle GetDlgItem fonksiyonunun geri dönüş değeri hemen işleme sokulmalıdır. Bu değer saklanmamalıdır. Bu kontrolleri uzun süre kullanmak için handle'ları elde edilip attach yapılmalıdır. Tabii GetDlgItem gerçekte ID'ye uygun türden bir sınıf nesnesi yaratır. Yani ID edit box kontrol'üne ilişkinse CEdit sınıfı türünden bir nesne yaratıp o nesnenin adresiyle geri dönecektir. C++'da geri dönüş değeri mecburen CWnd * türünden ifade edilebilmiştir. Bu nedenle alınan adresin kullanılması için tür dönüştürmesi gerekir.

BOOL CMyDialog::OnInitDialog(void){

CDialog::OnInitDialog();CString str;CListBox *pList;

pList = (CListBox *)GetDlgItem(IDC_LIST1);for (int i = 0; i < 100; ++i) {

str.Format("%d", i);pList->AddString(str);

}}

Kalıcı bir biçimde nesne şöyle oluşturulabilir:

BOOL CMyDialog::OnInitDialog(void){

CDialog::OnInitDialog();m_list.Attach(GetDlgItem(IDC_LIST1)->m_hWnd);

// .....}

97

Page 98: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Burada m_list CMyDialog sınıfının veri elemanıdır. Aslında MFC'de dialog penceresi kontrolleri üzerinde işlemleri kolaylaştıran DDX (Dialog Data Exchange) ve DDV (Dialog Data Validation) mekanizmaları vardır. Bu mekanizma işlemleri kolaylaştırdığı için tercih edilmektedir.

Sınıf Çalışması

MFC Wizard kullanarak bir uygulama yaratınız. File menüsüne dialog elemanını ekleyiniz. Gereksiz menüleri siliniz. Dialog menü elemanı seçildiğinde bir dialog penceresi görüntüleyiniz. Dialog penceresine bir list box kontrolü yerleştiriniz. List box içerisine çeşitli yazıları OnInitDialog fonksiyonunu kullanarak yerleştiriniz. Bir list box elemanına double click yapıldığında elemanı yazdırınız.

// MyDialog.cpp : implementation file

#include "stdafx.h"#include "dialog_uygulamasi.h"#include "MyDialog.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[ ] = __FILE__;#endif

/////////////////////////////////////////////////////////////////////////////// CMyDialog dialog

CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/): CDialog(CMyDialog::IDD, pParent)

{//{{AFX_DATA_INIT(CMyDialog)

// NOTE: the ClassWizard will add member initialization here//}}AFX_DATA_INIT

}

void CMyDialog::DoDataExchange(CDataExchange* pDX){

CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CMyDialog)

// NOTE: the ClassWizard will add DDX and DDV calls here//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CMyDialog, CDialog)//{{AFX_MSG_MAP(CMyDialog)

98

Page 99: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

ON_LBN_DBLCLK(IDC_LIST1, OnDblclkList1)//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////// CMyDialog message handlers

BOOL CMyDialog::OnInitDialog() {

CDialog::OnInitDialog();

CListBox *pList;CString str;

pList = (CListBox *)GetDlgItem(IDC_LIST1);for (int i = 0; i < 100; ++i) {

str.Format("%d", i);pList->AddString(str);

}return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE

}

void CMyDialog::OnDblclkList1() {

CListBox *pList;CString str;

pList = (CListBox *)GetDlgItem(IDC_LIST1);int index = pList->GetCurSel();pList->GetText(index, str);MessageBox(str);

}// MainFrm.cpp : implementation of the CMainFrame class#include "stdafx.h"#include "dialog_uygulamasi.h"#include "MyDialog.h"#include "MainFrm.h"//wizardın yazdığı koda aşağıdak kod eklenerek dialog penceresi yaratılır.void CMainFrame::OnFileDialog() {

CMyDialog dlg;dlg.DoModal();

}2002-01-08 Salı

11.9 Dialog Penceresi Kontrollerinin Sınıfın Veri Elemanı Biçiminde OluşturulmasıGetDlgItem fonksiyonu kontrole ilişkin nesneyi geçici handle tablosunda oluşturduğundan saklamaya izin vermez. Sınıfın veri elemanı olarak kalıcı bir biçimde sınıf nesnesi oluşturmak için şunlar yapılabilir:

1) OnInitDialog fonksiyonunda sınıf nesnesi Attach yapılarak kontrole bağlanır.

BOOL CMyDialog::OnInitDialog(void){

m_listBox.Attach(GetDlgItem(IDC_LIST1)->m_hWnd);// .....

}

2) Ana dialog penceresi yok edilmeden örneğin WM_DESTROY mesajında, Detach fonksiyonu ile bağlantı kesilmelidir.

void CMyDialog::OnDestroy(void){

m_listBox.Detach();

99

Page 100: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

// .....}

11.10Dialog Pencerelerinde DDX / DDV MekanizmalariDDX / DDV (Dialog Data Exchange / Dialog Data Validation )mekanizması dialog penceresi kontrolleri üzerinde kolay bir biçimde işlem yapmayı sağlayan kullanışlı bir mekanizmadır. DDX / DDV mekanizması class wizard tarafından da desteklenmektedir. Dialog pencerelerinde en sık geçen tema Ok tuşuna basıldığında dialog penceresi içerisindeki belirlemeleri elde etmektir. Bunun yanı sıra dialog penceresi ilk açıldığında ya da herhangi bir zaman dialog penceresi kontrollerinde herhangi bir değerin oluşturulması istenebilir. İşte DDX (Dialog Data Exchange) mekanizması kontrollerdeki bilgileri almak ya da istenildiği zaman kontrollere bilgi yerleştirmek için kullanılan ve bu işlemi kolaylaştıran bir mekanizmadır.

DDX mekanizması olmasaydı Ok tuşuna bastığımızda kontrollerdeki bilgiyi şöyle elde ederdik:

1) OnOk sanal fonksiyonunu işleyip GetDlgItem fonksiyonuyla kontrol sınıflarının adreslerini alırdık.

2) Bu kontrol sınıfları kullanılarak kontrolden bilgileri alıp CDialog sınıfından türettiğimiz sınıfın veri elemanlarında saklardık.

3) Bu bilgileri işleyen kod da şöyle olurdu (soyutlanmiş hali, kavramsal olarak):

CMyDialog dlg;

if (dlg.DoModal() == IDOK) {WriteData(dlg.m_edit1, dlg.m_edit2, m_radioResult);

// .....}

Aslında DDX mekanizması kendi içerisinde bu mekanizmaya çok yakın işlemler yapmaktadır.

11.11DDX / DDV Mekanizmasının Tasarım ve KullanımıDDX / DDV mekanizmasını oluşturan en önemli fonksiyon CWnd::DoDataExchange sanal fonksiyonudur. DDX / DDV mekanizmasını kullanabilmek için CDialog sınıfından türettiğimiz sınıf için bu fonksiyonun yazılmış olması gerekir:

virtual void CWnd::DoDataExchange(CDataExchange *pDX);

DoDataExchange fonksiyonu framework ya da programcı tarafından doğrudan çağrılan bir fonksiyon değildir. Programcı ya da framework CWnd::UpdateData fonksiyonunu çağırır, DoDataExchange bu fonksiyon içerisinden çağrılmaktadır. DoDataExchange yerine UpdateData'nın çağrılmasının ve işlerin dolaylı yapılmasının nedeni şunlardır:

1) DoDataExchange fonksiyonuna geçirilen adrese ilişkin sınıf nesnesi UpdateData fonksiyonunun içerisinde yerel olarak yaratılmıştır ve içi UpdateData fonksiyonu tarafından doldurulmuştur.

2) UpdateData, DoDataExchange fonksiyonunu çağırırken bazı küçük işlemler de yapmaktadır.

Class wizard CDialog sınıfından türetme yapıldığında DoDataExchange fonksiyonunu türetilmiş sınıf için default olarak içi boş bir biçimde oluşturur.

UpdateData fonksiyonu transfer yönünü belirten bir parametreye sahiptir:

BOOL CWnd::UpdateData(BOOL bSaveAndValidate = TRUE);

Fonksiyon FALSE parametreyle çağrılırsa dialog kontrollerine bilgi yerleştirileceği, TRUE parametreyle çağrılırsa dialog kontrollerinden bilgi alınacağı anlamına gelir. UpdateData fonksiyonu framework tarafından iki yerde çağrılır:

100

Page 101: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

1) CDialog::OnInitDialog fonksiyonu içerisinde FALSE parametreyle çağrılmaktadır. Bilindiği gibi bu fonksiyon WM_INITDIALOG mesajında framework tarafından çağrılmaktadır. Bu fonksiyonu türemiş sınıf için yazarsak bizim de CDialog sınıfının OnInitDialog fonksiyonunu bilinçli bir biçimde çağırmamız gerekir.

2) CDialog::OnOK fonksiyonu içerisinden TRUE parametresiyle çağrılmaktadır.

Sınıfın veri elemanları ile kontroller arasında transfer işlemi DoDataExchange fonksiyonu içerisinde çağrılan DDX_ ve DDV_ önekiyle başlayan fonksiyonlar tarafından yapılmaktadır. Yani DoDataExchange fonksiyonu içerisine bu fonksiyonlar yerleştirilmelidir. DDX_ ve DDV_ ile başlayan bu fonksiyonlar global fonksiyonlar olup MFC kütüphanesi içerisinde bulunmaktadır. DDX_ fonksiyonları her kontrol için çeşitli faydalı işlemleri yapacak biçimde tasarlanmışlardır. Bir DDX_ fonksiyonunun tipik parametrik yapısı şöyledir:

void DDX_XXX(pDX, id, m_data);

DDX_ fonksiyonlarının birinci parametresi DoDataExchange fonksiyonuna geçirilen CDataExchange sınıf adresidir. Fonksiyonların ikinci parametresi transfer işlemine konu olan kontrolün id değeridir. Üçüncü parametre ise transfer işlemine konu olan veri elemanına ilişkindir. Tabii bu parametre referans biçimindedir.

DDX_ fonksiyonları her iki yönde de transfer işlemini yapabilecek biçimde tasarlanmıştır. Çünkü transfer yönü CDataExchange sınıfının m_bSaveAndValidate public veri elemanında yazmaktadır. Kuşkusuz bu veri elemanı UpdateData fonksiyonu tarafından, UpdateData fonksiyonunda belirtilen yöne göre oluşturulmaktadır.

Bu durumda özetle DDX işlemlerini manuel olarak sağlamak için şunlar yapılmalıdır:

1) Transfer işleminde kullanılacak veri elemanları public bölümde tanımlanır.

2) DoDataExchange fonksiyonu içerisine çağrılacak DDX_ fonksiyonları yerleştirilir.

3) Aşağıdaki gibi bir kodla kullanım gerçekleşir:

CMyDialog dlg;

dlg.m_editName = "Taner Üstuntaş";dlg.m_cehckPrinter = 1;// .....if (dlg.DoModal() ==IDOK) {

MessageBox(m_editName);// .....

}

Burada DoModal fonksiyonuyla birlikte WM_INITDIALOG dolayısıyla UpdateData FALSE parametresiyle çağrılacaktır. Böylece DoDataExchange fonksiyonu içerisindeki DDX_ fonksiyonları veri elemanlarından kontrollere doğru bir transfer yapacaktır. Bu da dialog penceresinin bu bilgilerle görünmesini sağlayacaktır. Dialog penceresinden Ok tuşuyla çıktığımızda UpdateData TRUE parametresiyle çağrılacak ve DoDataExchange içerisindeki DDX_ fonksiyonları kontrollerden veri elemanlarına transferleri gerçekleştirecektir.

11.12DDX Işlemlerinin Manuel Yapilmasinin Zorluğu ve Işlemlerin Class Wizard Ile Yapılması

MFC'de önceden tanımlanmış pek çok DDX_ fonksiyonu vardır. Üstelik bir kontrole özgü pek çok DDX_ fonksiyonu da bulunabilmektedir. Örneğin edit box içerisindeki yazıya CString nesnesi ile transfer eden ve yazıyı sayıya dönüştürerek int bir değişkenle transfer eden edit box'a özgü birden fazla DDX_ fonksiyonu vardır. Bu fonksiyonların isimlerinin ve varyasyonlarının bilinmesi ve ezberlenmesi zordur. Halbuki class wizard bir kontrole özgü DDX_ fonksiyonlarını listelemekte, transfer işleminde kullanılacak veri elemanını tanımlamakta ve ilgili DDX_ fonksiyonunu DoDataExchange fonksiyonu içerisinde yerleştirmektedir.

2001-01-10 Perşembe101

Page 102: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

İşlemler class wizard ile şöyle yapılır;

Class Wizard member variables seçilir.

Bu dialog penceresinde DDX / DDV işlemi yapılabilecek bütün potansiyel kontrol ID’leri görüntülenir.

Bir kontrolün ID’si üzerine double click yapılır ve bir dialog penceresi açılır. Dialog penceresi içindeki EditBox’a kontrolle ilişkilendirilecek veri elemanının ismi yazılır.

Category ComboBox’ında Control ve Value biçiminde iki seçenek vardır. Kategori kontrol olarak seçilirse class wizard seçilen kontrol türünden bir sınıf nesnesi oluşturup kontrolü o nesneyle Attch ederek kullanıma hazır hale getirir. Aslında class wizard kontrol ilişkilendirmesi için de bir DDX_ fonksiyonu yerleştirmektedir. Yani bu ilişkilendirme işlemi yine bir DDX_ fonksiyonu ile yapılmaktadır. (Dialog penceresi kontrolleri otomatik olarak herhangi bir nesne ile ilişkilendirilmez. Onun için bu kontrollerin HANDLE değeri GetDlgItem ile alınıp Attach / Detach edilerek kullanılabilir.)

Kategori ComboBox’unda Value seçilirse Variable Type ComboBox’unda kontrole ilişkin bütün ilişkilendirme seçenekleri gözükür. Örneğin bir edit box kontrolü CString ile ya da int türü ile ilişkilendirilebilir. Her kontrole ilişkin farklı ilişkilendirme türleri vardır. Örneğin bir ListBox kontrolü CString ile ilişkilendirirlirse UpdateData(TRUE) işlemi sonucunda ListBox’taki aktif eleman yazısı o nesneye yerleştirilir. Kuşkusuz bütün bu ilişkilendirme işlemi class wizard’ın yerleştirdiği DDX_ fonksiyonlarla yapılır.

SINIF ÇALIŞMASI :

Bir EditBox ve CheckBox içeren dialog penceresi hazırlayınız. Dialog penceresi açıldığında EdtBox içinde default bir isim bulunsun. OK tuşuna basıldığında EditBox ve CheckBox durumları MessageBox ile yazdırılsın.

Class wizard kontrollerle ilişkilendirilecek nesnelere Dialog sınıfının başlangıç fonksiyonu içinde default bir ilk değer verir. Bu nedenle dialog penceresi açıldığında görüntülenecek default değerler doğrudan başlangıç fonksiyonu içinde yapılabilir. Hazırlanan proje DDX2 içinde mevcuttur. OnOK fonksiyonunda // MyDialog.cpp : implementation file#include "stdafx.h"#include "DDX2.h"#include "MyDialog.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[ ] = __FILE__;#endif

//////////////////////////////////////// CMyDialog dialogCMyDialog::CMyDialog(CWnd* pParent /*=NULL*/)

: CDialog(CMyDialog::IDD, pParent){

//{{AFX_DATA_INIT(CMyDialog)m_edit = _T("");m_check = FALSE;//}}AFX_DATA_INIT

}

void CMyDialog::DoDataExchange(CDataExchange* pDX){

CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CMyDialog)DDX_Text(pDX, IDC_EDIT1, m_edit);DDX_Check(pDX, IDC_CHECK1, m_check);//}}AFX_DATA_MAP

}

102

Page 103: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

BEGIN_MESSAGE_MAP(CMyDialog, CDialog)//{{AFX_MSG_MAP(CMyDialog)//}}AFX_MSG_MAP

END_MESSAGE_MAP()

///////////////////////////////////////////////////// CMyDialog message handlersvoid CMyDialog::OnOK() {

UpdateData(TRUE);CString str;str = m_edit;if (m_check == TRUE)

str += " - Sigortali";else

str += " - Sigortasiz";AfxMessageBox(str);

}

biçiminde kodlama yapılmıştır. m_edit EditBox ile ilişkilendirilmiş olan CString değişkendir (Value). CheckBox ile de m_check isimli BOOL değişken ilişkilendirilmiştir.

SINIF ÇALIŞMASI :

Bir dialog penceresi içerisine bir EditBox birde ListBox kontrolü yerleştiriniz. “Ekle” isimli bir Push Button’a basıldığında EditBox içindeki bilgileri ListBox’a ekleyiniz. Çıkış tuşuna basıldığında dialog penceresini kapatınız. EditBox kontrolünü CString nesnesi ile ListBox kontrolünü de CListBox nesnesi ile ilişkilendiriniz. Ekle Push Button’una click yapıldığında UpdateData(TRUE) uygulayarak EditBox’un ilişkilendirildiği CString nesnesinden alınız. Hazırlanan proje DDX3 içinde bulunmaktadır. // MyDialog.cpp : implementation file#include "stdafx.h"#include "DDX3.h"#include "MyDialog.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[ ] = __FILE__;#endif

////////////////////////////////////////////// CMyDialog dialogCMyDialog::CMyDialog(CWnd* pParent /*=NULL*/)

: CDialog(CMyDialog::IDD, pParent){

//{{AFX_DATA_INIT(CMyDialog)m_EditStr = _T("");//}}AFX_DATA_INIT

}void CMyDialog::DoDataExchange(CDataExchange* pDX){

CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CMyDialog)DDX_Control(pDX, IDC_LIST1, m_ListBox);DDX_Text(pDX, IDC_EDIT1, m_EditStr);//}}AFX_DATA_MAP

}BEGIN_MESSAGE_MAP(CMyDialog, CDialog)

//{{AFX_MSG_MAP(CMyDialog)ON_BN_CLICKED(ID_EKLE, OnEkle)//}}AFX_MSG_MAP

END_MESSAGE_MAP()/////////////////////////////////////////////////////// CMyDialog message handlersvoid CMyDialog::OnEkle()

103

Page 104: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

{UpdateData(TRUE);m_EditStr.TrimLeft();m_EditStr.TrimRight();if (m_EditStr.IsEmpty() != TRUE)

m_ListBox.AddString(m_EditStr);}

11.13Bir Grup Radio Button’ın DDX fonksiyonu ile ilişkilendirilmesiNormal olarak bir grup Radio Button kontrolünün ilkinde WS_GROUP özelliğinin belirtilmiş olması gerekir. Class wizard yalnızca WS_GROUP özellikli Radio Button’ların ID’lerini gösterir. Bu ID inr bir tür ile ilişkilendirildiğinde grubu temsil etmektedir. UpdateData(TRUE) yapıldığında ilişkilendirilen veri elemanına 0 orjinli bir sayı yerleştirilir. Bu sayı gruba ilişkin hangi Radio Button kontrolünün check durumda olduğunu belirtir.

SINIF ÇALIŞMASI :

Bir dialog penceresine bir test sorusu yazınız ve a, b, c biçiminde şıkları Radio Button kontrolleri ile belirtiniz. OK tuşuna basıldığında hangi şıkkı seçildiğini MessageBox ile yazdırınız. Proje DDX4 içinde bulunabilir. // MyDialog.cpp : implementation file#include "stdafx.h"#include "DDX4.h"#include "MyDialog.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[ ] = __FILE__;#endif//////////////////////////////////////////////////// CMyDialog dialogCMyDialog::CMyDialog(CWnd* pParent /*=NULL*/)

: CDialog(CMyDialog::IDD, pParent){

//{{AFX_DATA_INIT(CMyDialog)m_RadioSelect = -1;//}}AFX_DATA_INIT

}void CMyDialog::DoDataExchange(CDataExchange* pDX){

CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CMyDialog)DDX_Radio(pDX, IDC_RADIO1, m_RadioSelect);//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CMyDialog, CDialog)//{{AFX_MSG_MAP(CMyDialog)//}}AFX_MSG_MAP

END_MESSAGE_MAP()////////////////////////////////////////////////////// CMyDialog message handlersvoid CMyDialog::OnOK() {

UpdateData(TRUE);switch(m_RadioSelect) {

case 0:AfxMessageBox("Evet Biter");break;

case 1:AfxMessageBox("Hayir Bitmez");break;

case 2:AfxMessageBox("Umarim");break;

}

104

Page 105: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

}2002-01-15 Sali

11.14DDV FONKSİYONLARIDDV fonksiyonları DoDataExchange fonksiyonu içerisine yerleştirilen geçerlilik kontrolü yapan fonksiyonlardır. DDV fonksiyonları DDX fonksiyonları gibi aktarım yapmaz. Yalnızca geçerlilik kontrolleri yapar. DDV fonksiyonları global fonksiyonlardır ve isimleri DDV_ ile başlar. Az sayıda DDV fonksiyonu vardır. Tabii programcı kendisi için yeni DDV fonksiyonları yazabilir. DDV fonksiyonlarının genel biçimi şöyledir:

DDV_XXX(pDX, .....);

DDV fonksiyonları çift taraflı çalışabilir. Class wizard'da DDX işlemleriyle aynı menüde DDV işlemi yapılmaktadır. DDV fonksiyonları geçerlilik sınamasında başarısız olursa bir message box çıkartarak durumu kullanıcıya bildirir. Başarısız durumunda aynı zamanda bir exception'da oluşmaktadır. DDV fonksiyonları kontrolün kendisiyle değil, kontrolün ilişkilendirildiği sınıf veri elemanıyla ilişkilendirilir. Örneğin bir edit box içerisindeki sayısal değerin belirli bir aralıkta olması gerektiği sınansın. Önce edit box int türden bir sınıf veri elemanı ile DDX fonksiyonu kullanılarak ilişkilendirilir. Daha sonra bu veri elemanı DDV fonksiyonu ile aralık sınama işlemine sokulur.

11.15CDataExchange SINIFIBu sınıf DDX ve DDV fonksiyonları için tasarlanmış bir sınıftır. Bu sınıf türünden nesne UpdateData fonksiyonu tarafından oluşturulur. Programcı kendi DDX ve DDV fonksiyonlarını yazmak için bu sınıfa gereksinim duyar.

Sınıfın iki public veri elemanı vardır. m_bSaveAndValidate elemanı aktarımın yönünü belirtir. Bu eleman UpdateData fonksiyonuna geçirilen parametre ile doldurulmuş olur. m_pDlgWnd elemanı o andaki dialog penceresinin nesne adresini tutar (aslında DDX ve DDV mekanizması manuel olmak koşuluyla herhangi bir pencere ve alt pencere olarak kontrol söz konusu olduğunda kullanılabilir).

CDataExchange sınıfının PrepareCtrl, PrepareEditCtrl ve Fail üye fonksiyonları klavye odağına ilişkin işlemler yapar.

Anahtar Notlar : Win32'de kritik işlem yapan bazı API fonksiyonları işlemin başlangıcında ve/veya işlemin bitiminde mesajlarla pencereyi durumdan haberdar eder. Bu fonksiyonlardan bazıları şunlardır:

CreateWindow WM_CREATE

DestroyWindow WM_DESTROY

SetFocus WM_SETFOCUS, WM_KILLFOCUS

GetWindowText WM_GETTEXT

SetWindowText WM_SETTEXT

SetActiveWindow WM_ACTIVATE

EnableWindow WM_ENABLE, WM_CANCELMODE

Kontrol yazarken bu mesajların çoğunun işlenmesi gerekir.

11.16DIALOG TABANLI UYGULAMALARProgramın ana penceresinin dialog penceresi olduğu uygulamalara dialog tabanlı uygulamalar denir. Dialog tabanlı uygulamalar tipik olarak küçük programlar için kontrollerin kolay kullanıldığı gerekçesiyle tercih edilirler. DialogBox API fonksiyonu kendi içerisinde mesaj döngüsü içerdiği için API düzeyinde dialog tabanlı uygulama tipik olarak aşağıdaki gibi yazılır:

105

Page 106: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

int WinMain(.....){

return DialogBox(.....);}

MFC'de dialog tabanlı uygulamalar şöyle oluşturulur:

1) InitInstance fonksiyonu içerisinde dialog sınıfına ilişkin nesne tanımlanır ve DoModal fonksiyonu çağrılır.

2) Dialog pencere sınıfının başlangıç adresi m_pMainWnd elemanına yazılır.

3) InitInstance fonksiyonundan FALSE ile geri dönülür.

Bu işlemlerle InitInstance içerisinde programın ana penceresi yerine dialog penceresi yaratılmış olur ve FALSE ile geri dönmeyle MFC programı mesaj döngüsüne girmeden sonlandırılır. Bu durumda InitInstance fonksiyonu aşağıdaki gibi olmalıdır://DlgCalc.h içindeclass CDlgCalcApp : public CwinApp{public:

CDlgCalcApp();//.......

//DlgCalc.cppBOOL CDlgCalcApp::InitInstance(){

CDlgCalcDlg dlg;m_pMainWnd = &dlg;if (dlg.DoModal() == ID_OK) { //program sonlanmadan son kez

// ..... //yapılmak istenen işleri için if var.}else {

// .....}

return FALSE;}

11.17Dialog Tabanlı Uygulamaların Wizard Yardımıyla GerçekleştirilmesiMFC wizard ile dialog tabanlı uygulama yaratıldığında wizard şu işlemleri yapmış olur:

1) CWinApp sınıfından bir sınıf türetir ve InitInstance fonksiyonunu yukarıda belirtildiği gibi oluşturur.

2) CDialog sınıfından bir sınıf türetir ve boş bir dialog kaynağını bu sınıfla ilişkilendirir.

3) Program çalıştırıldığında karşımıza boş bir dialog penceresi dialog tabanlı uygulama olarak gelir.

4) Wizard aynı zamanda diğer wizard işlemlerinde olduğu gibi bir Help dialog penceresi de oluşturur.

5) Wizard üç tane .CPP ve .H dosyası, bir tane .RC dosyası üretmektedir. Üretilen dosyalar şunlardır:

X.CPP Uygulama sınıfıXDLG.CPP Dialog sınıfıSTDAFX.CPP Boş

Wizard'ın ürettiği koddan sonra programcı kontrolleri dialog kaynağına ekleyerek DDX / DDV fonksiyonları ile işlemleri yürütür.

Sınıf Çalışması:

106

Page 107: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Aşağıda üretilen basit hesap makinasını dialog tabanlı uygulama olarak yazınız.

Açıklama :

Hesap makinası 0-9 arası tuşları

+, -, *, /, = tuşlarını içerecektir.

Hesap makinası tuşları push button kontrolü olarak, sonucun yazılacağı yer read only edit box kontrolü biçiminde gerçekleştirilecektir.

Sınıfa şu veri elemanları eklenirse tasarım kolaylaşır:

İşlemin her iki operandını tutan iki ayrı eleman.

Yapılacak işlemi tutan bir veri elemanı.

Flag değişkenleri: Bu değişkenler işlem tuşlarına ve sayı tuşlarına basıldığında hangi durumda olunduğunu belirler.

Programda sembolik sabitler gerekiyorsa .H dosyası içerisine ya da sınıfın içerisine enum sabitleri biçiminde oluşturulabilir.

2002-01-22 Salı

11.18STANDART DIALOG PENCERELERİWindows 3.1 ile birlikte Windows programlamada kullanılan pek çok Windows penceresi standart hale dönüştürülmüştür. Bu dialog pencereleri programcı tarafından çağrılan API fonksiyonlarıyla çağrılabilir. Standart dialog pencereleri şunlardır:

The Common Dialog ClassesClass Dialog Type(s)CFileDialog Open and Save As dialog boxesCPrintDialog Print and Print Setup dialog boxesCPageSetupDialog Page Setup dialog boxesCFindReplaceDialog Find and Replace dialog boxesCColorDialog Color dialog boxesCFontDialog Font dialog boxes

Open ve Save As, Renk seçim ekranı, Font, Find / Replace, Print, Page setup

Standart dialog pencereleri API düzeyinde geniş birer yapı ile tanımlanmıştır. Programcı bu yapıların içini doldurur ve bu yapı değişkeninin adresiyle ilgili API fonksiyonunu çağırır. Bu yapılar çok geniş olduğu için yalnızca bazı elemanlarına ilk değer verilebilir. 0 değeri elemanlar için default işlem yaptığından ilk değer verme işleminden önce yapının sıfırlanması gerekir. Örneğin Open dialog penceresini açmak için OPENFILENAME isimli bir yapının içi doldurulur ve GetOpenFileName API fonksiyonu çağrılır.

MFC'de standart dialog pencereleri birer sınıfla temsil edilmiştir. Bütün standart dialog pencereleri CDialog sınıfından türetilen CCommonDialog sınıfından türetilen sınıflar biçiminde oluşturulmuştur. CCommonDialog sınıfı ciddi bir amaçla kullanılan bir sınıf değildir. Yani bu sınıf bütün standart dialog pencerelerine taban sınıflık yapmaktadır ve bunun dışında bir işlevi yoktur (yani tasarımda bu sınıf kaldırılabilirdi).

107

Page 108: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

11.19Open / Save As DIALOG PENCERESİ VE CFileDialog SINIFICFileDialog sınıfı hem Open hem de Save As dialog pencerelerini oluşturmak için kullanılır (aslında Open ve Save As dialog pencereleri farklı API fonksiyonlarıyla çıkartılmaktadır). Bu sınıf şöyle kullanılır:

1) Programcı CFileDialog sınıfı türünden bir nesne tanımlar ve sınıfın başlangıç fonksiyonunda belirlemeleri yapar (sınıfın bir tek başlangıç fonksiyonu vardır). Bu sınıfın kullanılması için türetme yapmaya gerek yoktur. Türetme bu dialog pencerelerini ciddi biçimde değiştirmek için kullanılan bir yöntemdir.

2) Sınıf nesnesi ile CFileDialog sınıfının DoModal üye fonksiyonu çağrılır.

3) Programcı OK ile dialog penceresinden çıkarsa seçilmiş olan dosya ismini almak ister. Bunun için sınıfın GetPathName, GetFileName, GetFileExit ve GetFileTitle fonksiyonları kullanılır.

4) Ayrıca CFileDialog sınıfının OPENFILENAME türünden m_ofn public veri elemanı da vardır. Daha ince çalışmak için bu veri elemanı kullanılabilir.

11.20CFileDialog Sınıfının Başlangıç FonksiyonuBaşlangıç fonksiyonunda şu belirlemeler yapılır:

Open'mı, Save As dialog penceresi mi açılacak.

Klavye ile uzantısız bir dosya ismi girildiğinde sonuna uzantı eklenecek mi?

Edit box'ta görüntülenecek default dosya ismi.

OFN_ sembolik sabitlerini bit or işlemine sokarak isteğe uygun hale getirme.

CFileDialog::CFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlag = OFN_HIDEREADONLY |FN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd *pParentWnd = NULL);

11.21Filitreleme ParametresiFilitreleme parametresi dosya türü combo box'ındaki yazıları ve filitreleyici joker

karakterlerini oluşturmakta kullanılır. Filitreleme yazısı | karakteri ile ayrılmış çiftlerden oluşur. Yazının sonunda || olması gerekir. Çiftin birinci elemanı combo box'la çıkacak yazıyı, ikinci elemanı gerçek filtre yazısını belirtir. Örneğin:

"All files(*.*) | *.* | Text files(*.txt) | *.txt||"

11.22Seçilen Dosya İsminin Alınarak KullanılmasıDoModal fonksiyonunun geri dönüş değeri ID_OK ise dialog penceresinden OK tuşu ile çıkılmıştır. Programcı seçilen dosya üzerinde işlem yapmak ister. Seçilen dosya ismini veren sınıfın üye fonksiyonları CString sınıf nesnesi ile geri dönmektedir.

11.23Open Dialog Penceresinde Çoklu SeçimEğer nesne yaratılırken OFN_ALLOWMULTISELECT kullanılmışsa Open dialog penceresi birden fazla dosyanın seçilmesine olanak sağlar. Seçilen dosya isimleri CFileDialog sınıfının kendi içerisindeki bir bağlı listeye aktarılır. Seçilen dosya isimlerini elde etmek için GetStartPosition ve GetNextPathName üye fonksiyonları kullanılır.

POSITION CFileDialog::GetStartPosition(void) const;

CString CFileDialog::GetNextPathName(POSITION &pos) const;

108

Page 109: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

POSITION içsel bağlı listenin eleman adresine ilişkin bir typedef ismidir ve bir gösterici türündendir. GetNextPathName bağlı listedeki o andaki dosya ismini vererek bir sonraki node için pozisyonu günceller. Özetle çoklu seçim işleminde bütün dosya isimleri şöyle elde edilebilir:

POSITION pos = fdlg.GetStartPosition();while (pos != NULL) {

MessageBox(fdlg.GetNextPathName(pos));// .....

}

Sınıf Çalışması

Aşağıdaki açıklanan dialog tabanlı uygulamayı yazınız:

Açıklama : Programda dialog penceresi üzerinde bir multiline edit kontrolü, Open, Save ve OK push button kontrolleri bulunmalıdır. Program bir editör gibi çalışmaktadır.

// FileDialogDlg.cpp : implementation file#include "stdafx.h"#include "FileDialog.h"#include "FileDialogDlg.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[ ] = __FILE__;#endif

//////////////////////////////////////////////////////// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog{public:

CAboutDlg();

// Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };//}}AFX_DATA

// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:

109

Page 110: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support//}}AFX_VIRTUAL

// Implementationprotected:

//{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()

};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD){

//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT

}

void CAboutDlg::DoDataExchange(CDataExchange* pDX){

CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)//{{AFX_MSG_MAP(CAboutDlg)

// No message handlers//}}AFX_MSG_MAP

END_MESSAGE_MAP()

///////////////////////////////////////////////////////////// CFileDialogDlg dialog

CFileDialogDlg::CFileDialogDlg(CWnd* pParent /*=NULL*/): CDialog(CFileDialogDlg::IDD, pParent)

{//{{AFX_DATA_INIT(CFileDialogDlg)m_Editor = _T("");//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

void CFileDialogDlg::DoDataExchange(CDataExchange* pDX){

CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CFileDialogDlg)DDX_Text(pDX, IDC_EDIT1, m_Editor);//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CFileDialogDlg, CDialog)//{{AFX_MSG_MAP(CFileDialogDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_OPEN, OnOpen)ON_BN_CLICKED(IDC_SAVE, OnSave)//}}AFX_MSG_MAP

END_MESSAGE_MAP()

////////////////////////////////////////////////////////////////// CFileDialogDlg message handlers

BOOL CFileDialogDlg::OnInitDialog(){

CDialog::OnInitDialog();

// Add "About..." menu item to system menu.

// IDM_ABOUTBOX must be in the system command range.

110

Page 111: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){

CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()){

pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX,

strAboutMenu);}

}

// Set the icon for this dialog. The framework does this automatically// when the application's main window is not a dialogSetIcon(m_hIcon, TRUE); // Set big iconSetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here

return TRUE; // return TRUE unless you set the focus to a control}

void CFileDialogDlg::OnSysCommand(UINT nID, LPARAM lParam){

if ((nID & 0xFFF0) == IDM_ABOUTBOX){

CAboutDlg dlgAbout;dlgAbout.DoModal();

}else{

CDialog::OnSysCommand(nID, lParam);}

}

void CFileDialogDlg::OnPaint() {

if (IsIconic()){

CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icondc.DrawIcon(x, y, m_hIcon);

}else{

CDialog::OnPaint();}

}

// The system calls this to obtain the cursor to display while the user drags// the minimized window.HCURSOR CFileDialogDlg::OnQueryDragIcon(){

return (HCURSOR) m_hIcon;}

111

Page 112: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CFileDialogDlg::OnOpen() {

CFileDialog fdlg(TRUE, "txt", NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "All Files(*.*)|*.*|text files(*.txt)|*.txt||");

CFile file;

if (fdlg.DoModal() == IDOK){file.Open(fdlg.GetPathName(), CFile::modeRead);DWORD fileLength = file.GetLength();char *buf = new char[fileLength + 1];file.Read(buf, fileLength);buf[fileLength] = '\0';m_Editor = buf;UpdateData(FALSE);delete [ ]buf;

}

}

void CFileDialogDlg::OnSave() {

CFileDialog fdlg(FALSE, "txt", NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "All Files(*.*)|*.*|text files(*.txt)|*.txt||");

CFile file;if (fdlg.DoModal() == IDOK){

file.Open(fdlg.GetPathName(), CFile::modeCreate|CFile::modeWrite);UpdateData();file.Write((LPCTSTR) m_Editor,m_Editor.GetLength());

}

}

11.24RENK SEÇME DIALOG PENCERESİAPI düzeyinde renk seçim dialog penceresi çıkartmak için CHOOSECOLOR yapısının içi doldurulup ChooseColor API fonksiyonu çağrılır. MFC'de bu dialog penceresi CColorDialog sınıfıyla temsil edilmiştir. Bu sınıf ile renk seçim dialog penceresini çıkarmak Open ve Save As dialog pencerelerini çıkarmakla aynı adımları içerir. Ancak kullanımı çok daha kolaydır. CColorDialog sınıfının başlangıç fonksiyonu aşağıdaki gibidir:

CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, CWnd *pParentWnd = NULL);

Flags MeaningCC_ANYCOLOR Causes the dialog box to display all available colors in the set of basic colors. CC_ENABLEHOOK Enables the hook procedure specified in the lpfnHook member of this structure. This flag is

used only to initialize the dialog box.CC_ENABLETEMPLATE Indicates that the hInstance and lpTemplateName members specify a dialog box template

to use in place of the default template. This flag is used only to initialize the dialog box.CC_ENABLETEMPLATEHANDLE Indicates that the hInstance member identifies a data block that contains a preloaded dialog

box template. The system ignores the lpTemplateName member if this flag is specified. This flag is used only to initialize the dialog box.

CC_FULLOPEN Causes the dialog box to display the additional controls that allow the user to create custom colors. If this flag is not set, the user must click the Define Custom Color button to display the custom color controls.

CC_PREVENTFULLOPEN Disables the Define Custom Colors button.CC_RGBINIT Causes the dialog box to use the color specified in the rgbResult member as the initial color

selection.CC_SHOWHELP Causes the dialog box to display the Help button. The hwndOwner member must specify

the window to receive the HELPMSGSTRING registered messages that the dialog box sends when the user clicks the Help button.

CC_SOLIDCOLOR Causes the dialog box to display only solid colors in the set of basic colors.

Fonksiyonun birinci parametresi renk seçim dialog penceresi açıldığında seçilmiş olan başlangıç rengini belirtir. İkinci parametre dialog penceresinin görünümüne ilişkin CC_ sembolik sabitlerinden oluşur. CC_FULLOPEN dialog penceresinin tüm özellikleriyle gösterileceği

112

Page 113: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

anlamına gelir. CC_RGBINIT birinci parametreyle belirtilen rengin default renk olarak gözükebilmesi için zorunlu kullanılmaktadır. DoModal fonksiyonundan çıkıldıktan sonra GetColor üye fonksiyonu ile seçilen renk alınabilir. Örnek bir kullanım şöyle olabilir:

CColorDialog colorDlg;

if (colorDlg.DoModal() == IDOK) {::SetClassLong(m_hWnd, GCL_HBRBACKGROUND),(LONG)::CreateSolidBrush(colorDlg.GetColor()));InvalidateRect(NULL);

}

// ChildView.cpp : implementation of the CChildView class#include "stdafx.h"#include "renksec.h"#include "ChildView.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[ ] = __FILE__;#endif

/////////////////////////////////////////////////////////////// CChildView

CChildView::CChildView(){}

CChildView::~CChildView(){}

BEGIN_MESSAGE_MAP(CChildView,CWnd )//{{AFX_MSG_MAP(CChildView)ON_WM_PAINT()ON_COMMAND(ID_FILE_RENK, OnFileRenk)//}}AFX_MSG_MAP

END_MESSAGE_MAP()////////////////////////////////////////////////////////////////// CChildView message handlersBOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) {

if (!CWnd::PreCreateWindow(cs))return FALSE;

113

Page 114: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

cs.dwExStyle |= WS_EX_CLIENTEDGE;cs.style &= ~WS_BORDER;cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,

::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

return TRUE;}

void CChildView::OnPaint() {

CPaintDC dc(this); // device context for painting}

void CChildView::OnFileRenk() {

CColorDialog colorDlg(RGB(0,255,0),CC_FULLOPEN);if (colorDlg.DoModal() == IDOK) {

SetClassLong(m_hWnd, GCL_HBRBACKGROUND, (LONG)::CreateSolidBrush(colorDlg.GetColor()));

InvalidateRect(NULL);}

}2002-01-24 Perşembe

11.25STANDART DIALOG PENCERELERİNİN DEĞİŞTİRİLMESİStandart dialog pencerelerindeki kontrollerin ID'leri dökümante edilmiş olduğundan bu ID'lere ilişkin kontroller üzerinde değişiklikler yapılabilir. Bunun dışında MFC'de standart dialog sınıflarından sınıflar türeterek daha ciddi değişiklikler yapılabilmektedir.

11.26PROPERTY SHEET'LERProperty sheet, tab kontrol içeren çoklu dialog pencereleridir. Her tab'a basıldığında farklı bir dialog penceresi görünür. Property sheet'in tab kısmı ayrı bir kontrol olup bağımsız bir biçimde yaratılabilmektedir. Tab kontrol ve property sheet API düzeyinde de oluşturulup kullanılabilmektedir. Ancak API düzeyinde bu kontrollerin yaratılıp kullanılması zahmetlidir. Property sheet'ler aynı konuya ilişkin birden fazla dialog penceresinin tek bir dialog penceresiymiş gibi ele alınacağı durumlarda tercih edilmelidir.

MFC'de bir property sheet yaratabilmek için iki sınıf kullanılır. Property sheet'in tamamı CPropertySheet isimli sınıfla temsil edilir. Property sheet içerisindeki her bir dialog penceresi ayrı ayrı CPropertyPage türünden nesnelerle temsil edilir.

CWnd CWnd

CPropertySheet CDialog

CPropertyPage

11.27PROPERTY SHEET'in Sayfalarını OluşturmakProperty sheet'in sayfaları öncelikle aynı büyüklükte dialog kaynağı biçiminde kaynakta oluşturulmalıdır. Tabii bu dialog kaynaklarının OK ve Cancel tuşları olmamalıdır. Property sheet'in sayfaları normal bir dialog kaynağı olmakla birlikte aşağıdaki özellikleri sağlamalıdır (eğer belirtilen bu özellikler sağlanmazsa genellikle işlemde yine bir problem ortaya çıkmaz, bazı uç kullanımlarda problemler oluşmaktadır).

114

Page 115: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

1. Style popup yerine child olmalıdır, 2. Border thin olmalıdır.

3. Title bar olmalıdır. 4. Sistem menüsü unchecked olmalıdır.

5. WS_VISIBLE pencere biçimi kullanılmamalıdır. 6. Disabled özelliği kullanılmalıdır

Bu özelliklere sahip dialog kaynağı normal bir dialog kaynağının değiştirilmesiyle sağlanabilir. Ancak Visual C++ kaynak editörü small, medium ve large büyüklükte bu özellikleri sağlayan dialog kaynağı oluşturabilmektedir.

Her sayfa için dialog kaynağı oluşturulduktan sonra bu dialog kaynakları CDialog değil, CPropertyPage sınıfıyla ilişkilendirilmelidir. Örneğin 5 tab'lı bir property sheet için bu işlemlerden sonra 5 tane sınıf oluşturulmuş olmalıdır. CPropertyPage sınıfı CDialog sınıfından türetildiği için yani bir dialog penceresi olduğu için DDX / DDV mekanizmasını desteklemektedir. Bir dialog penceresi CPropertyPage sınıfından türetilen bir sınıfla ilişkilendirildiğinde wizard sınıf içindeki başlangıç fonksiyonu ve DoDataExchange fonksiyonunu yazar. CPropertyPage'den türetilen bu sınıflar CPropertySheet sınıfı tarafından kullanılmaktadır.

11.28PROPERTY SHEET Nesnesinin OluşturulmasıProgramcı sayfaları oluşturduktan sonra CPropertySheet sınıfından bir sınıf türeterek bu sınıf türünden bir nesne tanımlayıp sınıfın DoModal üye fonksiyonunu çağırarak property sheet'i açar.

CWnd

CPropertySheet

CMyPropertySheet

CMyPropertySheet ps("Sample");

ps.DoModal();

Property sheet görüntülendiğinde sayfa olarak hazırlanan dialog kaynaklarının başlık yazıları property sheet'in tab yazıları biçiminde görüntülenir. Property sheet görüntülendikten sonra programcı tab'lar arasındaki geçiş ile uğraşmaz, bu işlemler otomatik olarak gerçekleştirilir. CPropertySheet sınıfı CWnd'den türetilmiştir, yani bir pencere sınıfıdır. Bu durumda bu karmaşık pencere sisteminin tasarımı şöyle yapılmıştır:

Property sheet'in tab kısmı ayrı bir pencere sistemidir ve bir kontroldür.

Property sheet'in sayfaları property sheet'in ana penceresinin birer alt penceresi gibi görüntülenmektedir.

Bu ana pencere CPropertySheet sınıfıyla temsil edilir. Sayfalar ise CPropertyPage sınıflarıyla temsil edilmektedir.

11.29Sayfaların PROPERTY SHEET İle İlişkilendirilmesiSayfaların property sheet ile ilişkilendirilmesi CPropertySheet sınıfının AddPage üye fonksiyonuyla yapılır.

115

Page 116: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CPropertySheet::AddPage(CPropertyPage *pPage);

Bu durumda her bir sayfa için CPropertyPage sınıfından türettiğimiz sınıf türünden birer nesne yaratılmalı, bu nesneler AddPage fonksiyonuyla property sheet ile ilişkilendirilmelidir. Nesne yönelimli tasarıma göre iki sınıfın ömür ilişkisi dikkate alındığında tasarımın şöyle yapılması uygundur: CPropertyPage sınıfından türetilen sınıf türünden nesneler CPropertySheet sınıfından türetilen sınıfın public veri elemanı yapılmalı ve bu sınıfın başlangıç fonksiyonu içerisinde AddPage ile property sheet'e eklenmelidir.

Property sheet oluşturmanın adımları şunlardır:

1) Sayfalara ilişkin dialog kaynakları oluşturulur ve CPropertyPage sınıfından türetilen sınıflarla ilişkilendirilir.

2) CPropertySheet sınıfından sınıf türetilir ve sayfalar bu sınıfın veri elemanları biçiminde tanımlanır.

3) CPropertySheet sınıfından türetilen sınıfın başlangıç fonksiyonunda AddPage üye fonksiyonu ile sayfalar eklenir.

4) CPropertySheet sınıfından türetilen sınıf türünden nesne tanımlanır ve CPropertySheet sınıfının DoModal fonksiyonu çağrılır.

5) Sayfa sınıflarına ilişkin başlık dosyaları CPropertySheet sınıfından türettiğimiz sınıfın başlık dosyası içerisinde, bu başlık dosyası ise property sheet'in kullanılacağı yerde include edilmelidir. (MyPropertySheet uygulamasina bak)

Wizard CPropertySheet sınıfından bir sınıf türettiğimizde iki başlangıç fonksiyonu yazmaktadır:

CMyPropertySheet::CMyPropertySheet(UINT nIDCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0) : CPropertySheet(nIDCaption, pParentWnd, iSelectPage);

{// .....

}

CMyPropertySheet::CMyPropertySheet(LPCTSTR lpCaption, CWnd *pParentWnd = NULL, UINT iSelectPage = 0) : CPropertySheet(lpCaption, pParentWnd, iSelectPage);

{// .....

}

Fonksiyonların birinci parametresi property sheet penceresinde çıkacak yazıdır. İkinci parametre property sheet'in üst penceresini belirtir. Default NULL değerini almıştır. Son parametre property sheet açıldığında aktif halde görüntülenecek sayfayı belirtir.

Sınıf Çalışması

İlkinde bir, ikincisinde iki, üçüncüsünde üç tane edit box olan, üç sayfadan oluşan bir property sheet tasarlayınız ve menüden ilgili eleman seçilince görüntüleyiniz.

2002-01-29 Salı

11.30PROPERTY SHEET Üzerinde İşlemlerProperty sheet yaratılırken API düzeyinde ya da MFC'de DoModal yapıldığında her sayfa için WM_INITDIALOG mesajı oluşturulur. Yani her sayfa için başlangıç işlemleri yine WM_INITDIALOG mesajında yapılabilmektedir. CPropertySheet sınıfının sayfa düzenlenmesi için kullanılan pek çok yararlı üye fonksiyonu vardır.

GetPageCount üye fonksiyonu property sheet'in kaç sayfadan oluştuğu bilgisini verir.

116

Page 117: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

GetPage fonksiyonu bir index parametresi alarak ilgili sayfayı oluşturan property page nesnesinin adresini verir. Her sayfanın eklenme sırasına göre bir index numarası vardır. Bu index numarası aynı zamanda property sheet'deki tab sırasıdır.

AddPage ve RemovePage fonksiyonları sayfa ekleyip çıkartmak amacıyla kullanılır.

EndDialog üye fonksiyonu property sheet'i kapatır (property sheet OK ya da Cancel tuşlarına basıldığında da zaten framework tarafından EndDialog çağrılmaktadır).

SetTitle üye fonksiyonu daha sonra property sheet'in pencere başlığı yazısını değiştirmekte kullanılır.

Default olarak property sheet'e çok fazla sayfa eklendiğinde Windows sayfaları tab kontrol üzerinde satırlara bölerek yönetir. EnableStackTabs fonksiyonu FALSE parametresiyle çağrılırsa sayfalar tab kontrol üzerinde scroll'lu bir biçimde görüntülenir. Bu fonksiyon DoModal üye fonksiyonundan önce ya da property sheet'in (CPropertySheet sınıfının) WM_CREATE mesajı içerisinde çağrılmalıdır.

CPropertySheet sınıfının PROPSHEETHEADER türünden m_psh isimli bir public veri elemanı da vardır. PROPSHEETHEADER yapısı API düzeyinde property sheet oluşturmak için kullanılan bir yapıdır. Yani aslında framework bu yapının içini doldurarak API düzeyinde işlemini yapar. m_psh elemanı uç noktalarda bazı ayrıntılı işlemlerde kullanılır. Bu elemanın kullanılmasına bir örnek property sheet'in Apply tuşunun görünmemesini istediğimiz durumdur. Bunun için PROPSHEETHEADER yapısının dwFlags elemanına PSH_NOAPPLYNOW özelliğinin eklenmesi gerekir.

m_psg.dwFlags != PSH_NOAPPLYNOW

typedef struct _PROPSHEETHEADER { DWORD dwSize; DWORD dwFlags; HWND hwndParent; HINSTANCE hInstance; union { HICON hIcon; LPCTSTR pszIcon; }; LPCTSTR pszCaption; UINT nPages; union { UINT nStartPage; LPCTSTR pStartPage; }; union { LPCPROPSHEETPAGE ppsp; HPROPSHEETPAGE FAR *phpage; }; PFNPROPSHEETCALLBACK pfnCallback;

#if (_WIN32_IE >= 0x0500) union { HBITMAP hbmWatermark; LPCTSTR pszbmWatermark; }; HPALETTE hplWatermark; union { HBITMAP hbmHeader; LPCSTR pszbmHeader; };#endif} PROPSHEETHEADER, FAR *LPPROPSHEETHEADER;

117

Page 118: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

dwFlags

Flags that indicate which options to use when creating the property sheet page. This member can be a combination of the following values:

PSH_DEFAULT

PSH_HASHELP

PSH_HEADER

PSH_MODELESS

PSH_NOAPPLYNOW

PSH_NOCONTEXTHELP

PSH_PROPSHEETPAGE

PSH_PROPTITLE

PSH_RTLREADING

PSH_STRETCHWATERMARK

PSH_USECALLBACK

PSH_USEHBMHEADER

PSH_USEHBMWATERMARK

PSH_USEHICON

PSH_USEHPLWATERMARK

PSH_USEICONID

PSH_USEPAGELANG

PSH_USEPSTARTPAGE

PSH_WATERMARK

PSH_WIZARD

PSH_WIZARD97

PSH_WIZARDCONTEXTHELP

PSH_WIZARDHASFINISH

PSH_WIZARD97

PSH_WIZARD_LITE

Programlama yoluyla aktif sayfayı değiştirebilmek için SetActivePage üye fonksiyonu kullanılır.

11.31PROPERTY SHEET'LERDE DDX / DDV MEKANİZMASIProperty sheet aslında birden fazla dialog penceresinin aynı anda görüntülenmesi gereksiniminden doğmuştur. MFC programcısı için property sheet'in bütün sayfaları ayrı bir dialog penceresiymiş gibi düşünülmelidir. Property sheet DoModal fonksiyonuyla açıldığında index sırasına göre tüm sayfalar için UpdateData, FALSE parametresiyle çağrılır. Böylelikle programcı DDX / DDV özelliğini kullanarak bütün sayfalardaki başlangıç durumunu ayarlayabilir. Örneğin property sheet iki sayfadan oluşmuş olsun. Sayfalardan birincisi bir edit box, ikincisi bir check box içeriyor olsun. Birinci sayfadaki edit box'ın bir CString nesnesi ile, ikinci sayfadaki check box'ın int türünden bir nesne ile ilişkilendirildiğini düşünelim. Bu durumda başlangıç belirlemelerinin yapılması ve sonuç bilgilerinin alınması şöyle yapılabilir:

Page 1

Cstring m_edit

Page 2

İnt m_check

m_page m_page

propsheet.m_page1.m_edit = "Ankara";propsheet.m_page2.m_edit = TRUE;propsheet.DoModal();MessageBox(propsheet.m_page2.m_edit);

Aslında property sheet tab'ları arasında geçişler sırasında önceki sayfa için UpdateData TRUE parametresi ile, yeni sayfa için UpdateData FALSE parametresiyle çağrılır. Yani her tab geçişi sırasında iki kez geçiş yapılan sınıflar için UpdateData fonksiyonu çağrılmaktadır.

118

Page 119: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

11.32PROPERTY SHEET Penceresinin TuşlarıNormal olarak property sheet yaratıldığında üzerinde OK, Cancel ve Apply tuşları vardır. Apply tuşu daha önce açıklandığı gibi kaldırılabilir. OK ve Cancel tuşları property sheet'i dialog pencerelerinde olduğu gibi tamamen kapatır. Apply tuşu property sheet'i kapatmaz. O zamana kadar yapılan belirlemelerin property sheet kapatılmadan işleme konulması için düşünülmüştür. Property sheet yaratıldığında Apply tuşu pasif durumdadır.

OK tuşuna basıldığında yalnızca o andaki sayfa için UpdateData TRUE parametresiyle çağrılır (çünkü zaten geçişler yapıldığında diğerleri için UpdateData TRUE işlemi yapılmış durumdadır). Cancel tuşuyla çıktığımızda hiçbir sayfa için UpdateData fonksiyonu çağrılmaz. Tabii Cancel ile çıkılmış olsa bile daha önceki sayfa geçişlerinde o sayfalar için DDX nesnelerine kayıtlar yapılmıştır. Tabii programcı Cancel tuşuyla çıkıldığında bu kayıt yapılan bilgileri kullanmak istemeyecektir.

Özetle:

1) DoModal yapıldığında yalnızca ilk sayfa için UpdateData FALSE yapılır.

2) Sayfalar arası geçişte önceki sayfa için UpdateData TRUE, geçilen sayfa için FALSE yapılır.

3) OK tuşuna basıldığında yalnızca aktif sayfa için UpdateData TRUE yapılır.

4) Cancel tuşuna basıldığında hiçbir sayfa için UpdateData çağrılmamaktadır.

Ayrıca OK ya da Cancel tuşuna basıldığında tek tek bütün sayfalar için OnOK ve OnCancel sanal fonksiyonları çağrılır.

11.33APPLY Tuşu İle İlgili İşlemlerApply tuşu tüm sayfalar için bir tanedir ve başlangıçta pasif durumdadır. Aktif hale geçirilmesi CPropertyPage sınıfının SetModified fonksiyonunun FALSE parametresi kullanılarak çağrılmasıyla yapılır. Apply tuşu ne zaman aktif hale getirilmelidir? Herhangi bir sayfada bir değişiklik yapıldığı zaman. Herhangi bir sayfadaki değişikliğin anlaşılabilmesi için programcının bütün kontrolleri izlemesi gerekir. Örneğin combo box'ta bir değişiklik yapıldığı combo box'ın gönderdiği mesajlardan, edit box'da bir değişiklik yapıldığı edit box'ın gönderdiği mesajlardan anlaşılabilir. Apply tuşuna basıldığında bütün sayfalar için OnApply sanal fonksiyonu çağrılmaktadır. OnApply CPropertyPage sınıfının sanal bir fonksiyonudur. Aslında Apply tuşuna basıldığında yalnızca OnApply sanal fonksiyonları değil, OnOK sanal fonksiyonları da çağrılmaktadır. Benzer biçimde OK tuşuna basıldığında da yalnızca OnOK değil, OnApply fonksiyonları da çağrılmaktadır.

Sınıf Çalışması

Bir property sheet içerisinde belirlenen şekli çizen örnek uygulamayı yazınız.

Açıklama :

Birinci sayfada x ve y merkez koordinatları girilen iki edit box kontrolü olacaktır. İkinci sayfada bir combo box olmalı ve bu combo box içerisinde kırmızı, yeşil, mavi ve siyah renkleri olmalıdır.

Bu belirlemelere göre property sheet kapatıldığında ya da Apply tuşuna basıldığında view ekranına bir daire çizilecektir.

Edit box'larda ya da combo box'ta bir değişiklik olduğunda Apply tuşu yine aktif hale getirilmelidir.

119

Page 120: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

// PSheetShape.cppCPSheetShape::CPSheetShape(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)

:CPropertySheet(pszCaption, pParentWnd, iSelectPage){

AddPage(&m_Color);AddPage(&m_Coordinate);

}

// PageCoordinatesDlg.cpp : implementation file// CPageCoordinatesDlg property page

IMPLEMENT_DYNCREATE(CPageCoordinatesDlg, CPropertyPage)

CPageCoordinatesDlg::CPageCoordinatesDlg() : CPropertyPage(CPageCoordinatesDlg::IDD){

//{{AFX_DATA_INIT(CPageCoordinatesDlg)m_x = 20;m_y = 30;//}}AFX_DATA_INIT

}

void CPageCoordinatesDlg::DoDataExchange(CDataExchange* pDX){

CPropertyPage::DoDataExchange(pDX);//{{AFX_DATA_MAP(CPageCoordinatesDlg)DDX_Text(pDX, IDC_EDIT2, m_x);DDX_Text(pDX, IDC_EDIT1, m_y);//}}AFX_DATA_MAP

}

// PageColorDlg.cpp : implementation file// CPageColorDlg property page

IMPLEMENT_DYNCREATE(CPageColorDlg, CPropertyPage)

CPageColorDlg::CPageColorDlg() : CPropertyPage(CPageColorDlg::IDD){

//{{AFX_DATA_INIT(CPageColorDlg)m_ncolor = 2;//}}AFX_DATA_INIT

}

2002-01-31 Salı

120

Page 121: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

11.34ON_CONTROL_RANGE MESAJ MAKROSUPek çok durumda bir dizi kontrolün mesaj fonksiyonlarının aynı fonksiyon yapılması istenir. Örneğin bir hesap makinesi uygulamasında pek çok push button bulunabilir ve hepsi için aynı fonksiyonun çağrılmasını isteyebiliriz. Ya da bir property sheet'in bir sayfasında birçok edit kontrolü olabilir. Bu edit kontrollerinin herhangi birinde değişiklik yapıldığında Apply tuşu aktif hale getirilmek istenebilir. Edit kontrollerinin EN_CHANGE işlem kodunda çağrılacak fonksiyonların aynı olması işimize gelir. Bunun için ON_CONTROL_RANGE mesaj makrosu kullanılır:

ON_CONTROL_RANGE(wNotifyCode, id1, id2, memberFunc)

Makronun birinci parametresi HIWORD(wParam) değeri yani notification code'dur. İkinci ve üçüncü parametreler hangi aralıktaki kontroller için işlemin yapılacağını belirtir. Makronun son parametresi çağrılacak fonksiyondur. Çağrılacak fonksiyonun geri dönüş değeri void, parametresi UINT türünden olmalıdır. Fonksiyona kontrole ilişkin ID değeri geçirilmektedir. Bu makro class wizard içerisine eklenmemiştir, manuel olarak yazılması gerekir.

11.35ON_COMMAND_RANGE MESAJ MAKROSUBu makro ON_CONTROL_RANGE makrosunun daraltılmış bir biçimidir. Bu makronun notification code parametresi yoktur. Dolayısıyla belli aralıktaki tüm WM_COMMAND mesajları için belirtilen fonksiyon çağrılır.

ON_COMMAND_RANGE(id1, id2, memberFunc)

Buradaki fonksiyonun geri dönüş değeri void, parametresi UINT türünden olmak zorundadır. Bu makro tipik olarak menü seçimlerinde tercih edilmektedir. Örneğin pek çok menü elemanı olduğunda ve bunlar çok küçük işlemler yaptığında pek çok fonksiyon yazmak yerine yalnızca bir fonksiyon yazıp onun içerisinde ID değerini switch işlemine sokabiliriz.

121

Page 122: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

12 KONTROLLERİN RENKLENDİRİLMESİEdit box, list box, static kontrol, combo box gibi kontrollerin renk ya da font özelliklerini dışarıdan değiştirebiliriz. Örneğin static kontrol ile yazılan yazının zemin rengi dialog penceresi rengindedir. Static kontrolleri beyaz zeminli pencerelerde kullandığımızda kötü bir görüntü oluşur. Edit box içerisindeki yazının rengini değiştirmek isteyebiliriz. Benzer biçimde dialog pencerelerinin zemin rengi de istenirse değiştirilebilir. Kontrollerin pencere fonksiyonları böylesi değişikliklere izin verecek biçimde yazılmıştır. Şöyle ki: Kontrollerin WM_PAINT mesajı içerisinde DC elde edildikten sonra bu DC ile üst pencere WM_CTLCOLOR mesajıyla çağrılır. Kontrolü yaratan kişi bu mesajı işler. Mesaja geçirilen DC üzerinde değişiklikler yapar ve bir fırçayla geri döner. Böylece kontrol DC'de belirlenen renkleri ve fontu çizim yapmakta kullanır. Fırçayla da zemini boyar. Windows 3.x zamanında bütün kontroller renklendirme için üst pencereyi WM_CTLCOLOR mesajıyla çağırıyordu. Ancak Win32'de kontrol grupları ayrı mesajlar gönderecek biçimde birbirlerinden ayrılmıştır. Örneğin edit box kontrolleri WM_CTLCOLOR_EDIT, static kontroller WM_CTLCOLOR_STATIC mesajını gönderirler.

MFC'de Windows 3.x ile Win32 arasında yapılan bu değişiklik dikkate alınmamıştır. Yani MFC'de Windows 3.x'de olduğu gibi bütün kontroller için tek bir fonksiyon çağrılmaktadır. MFC'de kontrolleri renklendirebilmek için üst pencerenin mesaj haritasına ON_WM_CTLCOLOR makrosu yerleştirilmelidir. Çağrılacak fonksiyonun ismi ve parametrik yapısı şöyle olmak zorundadır:

afx_msg HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtrlColor);

Fonksiyonun birinci parametresi kontrolün gönderdiği DC, ikinci parametresi kontrol nesnesinin adresi, üçüncü parametresi ise kontrolün türüdür. Bu parametre CTLCOLOR_XXX sembollerinden biri olur.

Anımsatma : Bilindiği gibi pencere içerisine her tür yazı DrawText ya da TextOut API fonksiyonlarıyla yazılır. DrawText dikdörtgensel bir bölge belirlenmesini ister ve yazıyı oraya yazar. Bu API fonksiyonları dikdörtgensel bölgenin içini DC'de "yazının zemin rengi" bileşenini kullanarak boyar. Yazının kendisini de DC'nin "yazının şekil rengi" bileşeniyle yazar. DC'deki yazının şekil ve zemin rengi bileşenlerini değiştirmek için SetTextColor ve SetBkColor API fonksiyonları kullanılır. Bu API fonksiyonları MFC'de CDC sınıfının üye fonksiyonu biçiminde yazılmıştır.

Static kontrol tüm pencere koordinatları kullanılarak DrawText fonksiyonuyla yazının yazılması suretiyle gerçekleştirilmiştir. Dolayısıyla static kontrolde fırça değiştirmekle bir ilgimiz olamaz. Dolayısıyla static kontrolün zemin ve şekil rengini değiştirebilmek için SetTextColor ve SetBkColor fonksiyonlarını kullanmamız gerekir. Edit box kontrolünde ise zeminin tamamı renk mesajından dönülen fırçayla boyanmıştır. Her tuşa bastığımızda karakterler TextOut fonksiyonuyla yazılmıştır. Bu durumda edit box'ın zemin rengini değiştirebilmek için renk mesajında fırçayla geri dönmenin yanısıra, aynı rengin SetBkColor fonksiyonuyla set edilmesi gerekir.

Sınıf ÇalışmasıDialog tabanlı bir uygulama yazınız. Üzerine iki edit box yerleştiriniz. Edit box'ların şekil ve zemin renklerini farklı yapınız. Static kontrolleri ise kırmızı yapınız.

Açıklama : MFC'de renk mesajında bir fırçayla geri dönebilmek için tavsiye edilen yöntem şudur:

1) Üst pencereye ilişkin sınıfta CBrush türünden bir nesne tanımlanır.

2) Üst pencereye ilişkin sınıfın başlangıç fonksiyonunda ya da OnCreate, OnInitDialog fonksiyonlarında fırça CreateSolidBrush gibi bir fonksiyonla yaratılır.

3) Renk mesajının sonunda ;

122

Page 123: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

return (HBRUSH)m_brush.m_hObject;

biçiminde geri dönülür.

// ctlcolorDlg.cpp : implementation file#include "stdafx.h"#include "ctlcolor.h"#include "ctlcolorDlg.h"//......int CCtlcolorDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) {

if (CDialog::OnCreate(lpCreateStruct) == -1)return -1;

m_redBrush.CreateSolidBrush(RGB(255, 0, 0));m_blueBrush.CreateSolidBrush(RGB(0, 0, 255));return 0;

}//kontrollerin yazi ve zemin rengi olusturuluyorHBRUSH CCtlcolorDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);CPaintDC dc(this);

if(nCtlColor == CTLCOLOR_EDIT && pWnd->GetDlgCtrlID() == IDC_EDIT1) {pDC->SetTextColor(RGB(0, 0, 0));pDC->SetBkColor(RGB(255, 0, 0));hbr = m_redBrush;

}if(nCtlColor == CTLCOLOR_EDIT && pWnd->GetDlgCtrlID() == IDC_EDIT2) {

pDC->SetTextColor(RGB(0, 0, 0));pDC->SetBkColor(RGB( 0, 0, 255));hbr = m_blueBrush;

}if(nCtlColor == CTLCOLOR_STATIC && pWnd->GetDlgCtrlID() == IDC_STATIC1) {

pDC->SetTextColor(RGB(0, 0, 0));pDC->SetBkColor(RGB(0, 0, 255));hbr = m_blueBrush;

}if(nCtlColor == CTLCOLOR_STATIC && pWnd->GetDlgCtrlID() == IDC_STATIC2) {

pDC->SetTextColor(RGB(0, 0, 0));pDC->SetBkColor(RGB(255, 0, 0));hbr = m_redBrush;

}return hbr;

}2002-02-07 Perşembe

12.1 Sistem Renklerinin KullanılmasıBazı programlarda kontrol panelden renkler değiştirildiğinde program bunu hemen anlayıp ilgili renklerini kendisi değiştirmektedir. Pencere yaratılırken WNDCLASS yapısının hbrBackground elemanı ile zemin boyanmaktadır. Biz bu değeri sabit olarak seçersek kontrol panelden yapılan herhangi bir değişiklik bizim programımıza yansımaz. Kontrol panelden pencere içi zemin rengini değiştirdiğimizde bizim programımızın bundan etkilenebilmesi için kontrol paneldeki bu

123

Page 124: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

sistem renklerini alarak onları kullanmamız gerekir. GetSysColor ve SetSysColor fonksiyonları sistem renkelerini alıp set etmekte kullanılır.

DWORD GetSysColor(int nIndex);BOOL SetSysColor(int CElements, const int *lpaElements,const COLORREF *lpaRGBValue);

lpa : a, array manasında kullanılmıştır. MSDN April 2001

GetSysColor fonksiyonunun parametresi kontrol paneldeki hangi belirlemenin renginin alıncağını belirtir. Örn; bu parametre COLOR_WINDOW olarak girilirse pencere arka plan rengi alınır, COLOR_MENU olarak girilirse menünün zemin rengi elde edilir. Ya da örneğin COLOR_MENUTEXT girilirse menünün içindeki yazının rengi elde edilir.

Kontrol paneldeki değişiklikler kalıcı değişikliklerdir. Yani Windows oturumunu kapattığımızda buradaki belirlemeler registry dosyalarına yazılır ve açılışta yine kullanılır.

( GetSysColor(int nIndex) fonksiyonun nIndex parametresinin alabileceği değereler aşağıdaki tabloda verilmiştir. )Value MeaningCOLOR_3DDKSHADOW Dark shadow for three-dimensional display elements.

COLOR_3DFACE, COLOR_BTNFACE Face color for three-dimensional display elements and for dialog box backgrounds.

COLOR_3DHILIGHT, COLOR_3DHIGHLIGHT, COLOR_BTNHILIGHT, COLOR_BTNHIGHLIGHT

Highlight color for three-dimensional display elements (for edges facing the light source.)

COLOR_3DLIGHT Light color for three-dimensional display elements (for edges facing the light source.)

COLOR_3DSHADOW, COLOR_BTNSHADOW Shadow color for three-dimensional display elements (for edges facing away from the light source).

COLOR_ACTIVEBORDER Active window border.

COLOR_ACTIVECAPTION

Active window title bar. Windows 98/Me, Windows 2000/XP: Specifies the left side color in the color gradient of an active window's title bar if the gradient effect is enabled.

COLOR_APPWORKSPACE Background color of multiple document interface (MDI) applications.COLOR_BACKGROUND, COLOR_DESKTOP Desktop.COLOR_BTNTEXT Text on push buttons.COLOR_CAPTIONTEXT Text in caption, size box, and scroll bar arrow box.

COLOR_GRADIENTACTIVECAPTION

Windows 98/Me, Windows 2000/XP: Right side color in the color gradient of an active window's title bar. COLOR_ACTIVECAPTION specifies the left side color. Use SPI_GETGRADIENTCAPTIONS with the SystemParametersInfo function to determine whether the gradient effect is enabled.

COLOR_GRADIENTINACTIVECAPTIONWindows 98/Me, Windows 2000/XP: Right side color in the color gradient of an inactive window's title bar. COLOR_INACTIVECAPTION specifies the left side color.

COLOR_GRAYTEXT Grayed (disabled) text. This color is set to 0 if the current display driver does not support a solid gray color.

COLOR_HIGHLIGHT Item(s) selected in a control.COLOR_HIGHLIGHTTEXT Text of item(s) selected in a control.

COLOR_HOTLIGHT Windows 98/Me, Windows 2000/XP: Color for a hot-tracked item. Single clicking a hot-tracked item executes the item.

COLOR_INACTIVEBORDER Inactive window border.

COLOR_INACTIVECAPTION

Inactive window caption. Windows 98/Me, Windows 2000/XP: Specifies the left side color in the color gradient of an inactive window's title bar if the gradient effect is enabled.

COLOR_INACTIVECAPTIONTEXT Color of text in an inactive caption.COLOR_INFOBK Background color for tooltip controls.COLOR_INFOTEXT Text color for tooltip controls.COLOR_MENU Menu background.

COLOR_MENUHILIGHTWindows XP: The color used to highlight menu items when the menu appears as a flat menu (see SystemParametersInfo). The highlighted menu item is outlined with COLOR_HIGHLIGHT.

COLOR_MENUBAR

Windows XP: The background color for the menu bar when menus appear as flat menus (see SystemParametersInfo). However, COLOR_MENU continues to specify the background color of the menu popup.

COLOR_MENUTEXT Text in menus.COLOR_SCROLLBAR Scroll bar gray area.COLOR_WINDOW Window background.COLOR_WINDOWFRAME Window frame.

124

Page 125: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

COLOR_WINDOWTEXT Text in windows.

12.2 Pencere Zemin Renginin Kontrol Panel Belirlemelerine Göre Otomatik Değiştirilmesi

Pencere zemin renginin kontrol panel ayarlamaları ile otomatik değiştirilebilmesi için iki yöntem kullanılabilir.

Pencerenin yaratılmasında kullanılan WNDCLASS yapısının hbrBackground elemanı sistemdeki zemin rengi olacak biçimde verilebilir. (Bu yaratılma sırasında değil istenirse WM_CREATE içinde SetClassLong fonksiyonu ile değiştirilebilir. Çünkü WM_CREATE’te pencere daha görünür durumda değildir.)

WNDCLASS wndClass;wndClass.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_WINDOW));

Ancak bu değişikliğin yapılmış olması kontrol paneldeki değişikliğin yansıyacağı anlamına gelmez. Değişikliğin yansıtılması için WM_SYSCOLORCHANGE mesajından faydalanılır. Bu mesaj kontrol panelde herhangi bir renk değişikliği yapıldığında bütün pencerelere gönderilmektedir. O halde bu mesaj içinde COLOR_WINDOW rengini kullanarak yeni bir fırça yaratılmalı ve SetClassLong fonksiyonu ile sınıftaki fırça bu renk ile değiştirilmelidir. Tabi önceki fırçanın da DeleteObject ile silinmesinde fayda vardır.

HBRUSH, HPEN gibi GDI nesneleri birer void pointer olduğu için Win32 sistemlerinde bu türlere ilişkin HANDLE değerlerinin yüksek anlamlı WORD değerleri sıfır olamaz. Eğer yüksek anlamlı WORD değerleri sıfır ise ve düşük anlamlı WORD değerleri kontrol paneldeki renk sembolik sabitlerini içeriyorsa bu durum GDI alt sistemi için özel anlamlar taşır. GDI alt sistemi bu biçimde yaratılmış fırçalar için kontrol panel renklerini çekerek sanki o renkler belirlenmiş gibi kullanmaktadır. Örneğin aşağıdaki gibi bir fırça yaratılmış olsun;

wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

İşte WNDCLASS yapısının hbrBackground elemanı böyle oluşturulmuşsa zemin rengi doğrudan kontrol panledeki pencere zemin rengi olarak alınır. Üstelikte WM_SYSCOLORCHANGE mesajını da işlemeye gerek kalmaz. Çünkü WM_ERASEBKGND mesajı içinde sistem rengi bulunarak çizim yine ona göre yapılır. HANDLE içine atanan değerin + 1 içermesi zorunludur. Çünkü renk sembolik sabitlerinin orjini sıfırdır ve sıfır NULL pointer anlamına geldiği için en azından ASSERT işlemlerinde problem oluşturur. Birinci yönteme göre çok daha etkin bir yöntemdir.

MFC’de birinci ve ikinci yöntemler aynı biçimde uygulanabilir. Zaten ikinci yöntem MFC’de otomatik olarak uygulanmıştır. CWnd::Create fonksiyonunun birinci parametresi yani sınıf ismi parametresi NULL olarak geçildiğinde MFC’nin kendisinin belirlediği WNDCLASS yapısı kullanılmaktadır. Bu yapının da hbrBackground elemanı bu biçimde oluşturulduğu için tüm MFC programlarının zemin rengi değişimi kontrol panel belirlemelerine uygundur.

12.3 CWnd::PreCreateWindow Sanal fonksiyonuCWnd::Create fonksiyonu CreateWindow API fonksiyonunu çağırmadan hemen önce CretaeWindow API fonksiyonunda kullanacağı parametreleri içeren CREATESTRUCT türünden bir yapı referansı ile PreCreateWindow sanal fonksiyonunu çağırır. Bu fonksiyon sayesinde yaratılacak pencerenin önemli değişiklikleri son noktada gerçekleştirilebilmektedir.

125

Page 126: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

13 TIMER İŞLEMLERİBilindiği gibi API düzeyinde bir timer yaratabilmek için SetTimer ve KillTimer fonksiyonları kullanılır. Bu iki fonksiyon da bir pencere HANDLE parametresi aldığı için MFC’de CWnd sınıfının üye fonksiyonu biçiminde yazılmıştır. Bilindiği gibi timer yaratıldıktan sonra periyodik işlemler iki yolla yapılabilir.

WM_TIMER mesajında işlemleri yapmak.

Bir callback fonksiyonun çağırılmasını sağlayarak işlemleri o fonksiyonda yapmak.

API’deki SetTimer ve KillTimer fonksiyonlarının CWnd üye fonksiyonlarından hiçbir farkı yoktur. Sadece CWnd’nin üye fonksiyonlarının HANDLE parametreleri yoktur. Fonksiyonların prototipleri şöyledir;

UINT CWnd::SetTimer( UINT nIDEvent, UINT nElapse, void(CALLBACKEXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD));

BOOL CWnd::KillTimer(UINT nIDEvent);

SetTimer fonksiyonunun birinci parametresi Timer’in ID değeridir. ID değeri programcı tarafından girilir. “1”den başlayarak girilen bir değerdir. (Biz “0” girsek bile fonksiyon kendisi bu değeri “1” yapar) Thread başına anlamlı bir değerdir. Fonksiyonun ikinci parametresi mesaj periyodunu milisaniye cinsinden belirtir. Fonksiyonun son parametresi NULL girilirse programcı periyodik mesajları WM_TIMER mesajı ile işler. Bu parametreye bir fonksiyon adresi girilirse periyodik olarak bu fonksiyon çağırılacaktır. Fonksiyonun geri dönüş değeri yaratılan timer’in ID değeridir. Fonksiyon başarısızsa sıfır değerine geri döner. Yaratılacak maksimum timer sayısı Win32 sistemlerinde neredeyse sınırsızdır. Ancak çok fazla timer yaratılması sistemi ciddi biçimde yavaşlatmaktadır. Win32 sistemleri thread’in mesaj kuyruğuna birden fazla timer mesajı yerleştirmezler. Yani Windows timer periyodu gelse bile kuyrukta WM_TIMER mesajı varsa yeni bir tane yerleştirmez. Yaratılan timer’ların freaknsında +, - duyarlılık hataları oluşabilmektedir. (Bu konuda bir MSDN makalesi vardır.) Tipik olarak 1000 ms. için +50, -50 sapma değerleri sözkonusudur. Timer mesajları ister WM_TIMER ile isterse callback fonksiyon yöntemiyle işlensin her ikisinde de aslında WM_TIMER mesajının kuyruğa bırakılması ile işlem gerçekleşir. Callback fonksiyon yönteminde tipik olarak mesaj yine kuyruğa yazılır, callback fonksiyonu DispatchMessage fonksiyonu tarafında çağırılır. Bu durum konsol uygulamalarında timer özelliğinin neredeyse kullanılamamasına yol açmıştır. (API düzeyinde hem HWND hem de callback fonksiyon parametresi NULL geçilirse yine de WM_TIMER mesajı kuyruğa bırakılır. Bu durumda mesaj, mesaj döngüsü içinde işlenmelidir.) Timer’i biz KillTimer ile yoketmezsek thread yokedildiğinde yokedilir. Mesaj kuyruğu thread başına olduğu için timer’lar da thread başınadır.

SINIF ÇALIŞMASI :

Bir pencere içerisinde pencerenin ortasında dijital bir saat görüntüsü oluşturunuz. Açıklamalar;

Timer WM_CREATE mesajında yaratılıp, WM_DESTROY mesajında silinmelidir.

Şu andaki tarihi ve zamanı alabilmek için CTime sınıfının GetCurrentTime static fonksiyonu kullanılabilir.

CTime ctime;ctime = CTime::GetCurrentTime();

WM_TIMER mesajı class wizard kullanılarak işlenir.

Çizim WM_TIMER içerisinde GetDC ile DC alınarak ya da CClientDC sınıfı kullanılarak DrawText ya da TextOut fonksiyonuyla yazdırılmalıdır. Aynı zamanda çizimler yine WM_PAINT içinde de yapılmalıdır.

Pencerenin boyutu değiştirilse bile saat ortada çıkacaktır. Bunun için WM_SIZE mesajının işlenmesi gerekebilir.

126

Page 127: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CMy28TimerDlg::OnTimer(UINT nIDEvent) {

char *buf[ ]={ "Pazar", "Pazartesi", "Salı", "Carşamba", "Perşembe", "Cuma", "Cumartesi"};

CTime time;time = CTime::GetCurrentTime();

m_strTime.Format("%02d:%02d:%02d\t %02d/%02d/%04d\t", time.GetHour(), time.GetMinute(), time.GetSecond(), time.GetDay(), time.GetMonth(), time.GetYear());

m_strTime += buf[time.GetDayOfWeek()-1];

UpdateData(FALSE);

CDialog::OnTimer(nIDEvent);}

HBRUSH CMy28TimerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {

HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

// TODO: Change any attributes of the DC herepDC->SetTextColor(RGB(255, 0, 0));

// TODO: Return a different brush if the default is not desiredreturn hbr;

}BOOL CMy28TimerDlg::OnInitDialog(){

CDialog::OnInitDialog();ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){

CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()){

pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

}}SetIcon(m_hIcon, TRUE); // Set big iconSetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization hereSetTimer(1, 1000, NULL);//her 1 sn de timer mesajı gönderilecekreturn TRUE; // return TRUE unless you set the focus to a control

}2002-02-12 Salı

13.1 Birden Fazla Timer ile ÇalışmakBirden fazla timer ile çalışıldığında ve özellikle callback fonksiyon yöntemi kullanılmıyorsa mesajın hangi timer tarafından oluşturulduğu WM_TIMER mesajının parametrelerinden anlaşılabilir. MFC’de timer mesajları ON_WM_TIMER mesaj makrosuyla işlenir. Çağırılacak olan fonksiyon OnTimer fonksiyonudur.

127

Page 128: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

afx_msg void OnTimer(UINT nIDEvent);

MFC’de fonksiyonun parametresi olan nIDEvent switch içine alınabilir ve mesajın hangi timer’den geldiği bulunabilir.

SINIF ÇALIŞMASI :

Dialog tabanlı bir saat uygulamasıyazınız. Dialog penceresi üzerine bir static kontrolü koyunuz. Her “1” sn’de bir o anki zamanı alarak SetWindowText fonksiyonuyla ya da DDX / DDV mekanizması ile static kontrole yazınız. Her timer geldiğinde o andaki zaman bilgisi şöyle alınabilir.

CTime time,

time = CTime::GetCurrentTime();time.GetHour();

NOT : MFC’de bütün static kontrollere default olarak “–1“ biçiminde define edilmiş olan IDC_STATIC sabit değeri verilir ve bu değer class wizard’da görünmez (DDX / DDV için ilişkilendirme yapılan Member Variables kısmında falan görünmez). Onun için static kontrole default olarak verilen IDC_STATIC ismi yerine IDC_STATIC1 vb. biçiminde başka isimler kullanmalıyız. O zaman class wizard static kontrolü görür hale geliyor.

128

Page 129: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

14 STATUS BAR KONTROLÜPencerelerin aşağısında bulunan herhangi bir durum hakkında bilgi vermekte kullanılan özel alt pencerelere status bar denir. API düzeyinde status bar CreateWindow(Ex) fonksiyonunda sınıf ismi olarak “Statusclassname” alınarak yaratılır. Status bar yaratılırken pencere başlığı ya da pencere koordinatları parametrelerinin hiçbir önemi yoktur. Status bar WM_SIZE mesajını aldığında otomatik olarak kendini üst pencereye göre genişletir. Status bar aynı zamanda API düzeyinde CreateWindow(Ex) onksiyonu yerine CreateStatusWindow API fonksiyonuyla da yaratılabilir. Status bar yaratıldıktan sonra pencereye SB_XXX mesajları gönderilerek faydalı bir duruma getirilir. Status bar yaratıldıktan sonra SB_SETPARTS mesajı gönderilerek bölümler oluşturulur. Bölümler yaratıldıktan sonra programcı genellikle uygun bir durum oluştuğunda SB_SETTEXT mesajını göndererek bölümlerde istenilen yazının yazılmasını sağlar.

API düzeyinde status bar’ın bölümlere ayrılması ve içine yazı yerleştirilmesi dışında bir kolaylık yoktur. Yani örneğin CapsLock tuşuna basıldığında Caps yazısının status bar’ın bir bölümünde görüntülenmesi otomatik yapılmaz. Bu işlem tipik olarak status bar’ın üst penceresinde CapsLock tuşuna basıldığının tespit edilmesinin ardından SB_SETTEXT mesajının status bar’a gönderilmesi ile yapılır.

CStatusBar Class MembersConstructionCStatusBar Constructs a CStatusBar object.

Create Creates the status bar, attaches it to the CStatusBar object, and sets the initial font and bar height.

CreateEx Creates a CStatusBar object with additional styles for the embedded CStatusBarCtrl object.SetIndicators Sets indicator IDs.AttributesCommandToIndex Gets index for a given indicator ID.GetItemID Gets indicator ID for a given index.GetItemRect Gets display rectangle for a given index.GetPaneInfo Gets indicator ID, style, and width for a given index.GetPaneStyle Gets indicator style for a given index.GetPaneText Gets indicator text for a given index.GetStatusBarCtrl Allows direct access to the underlying common control.SetPaneStyle Sets indicator style for a given index.SetPaneText Sets indicator text for a given index.SetPaneInfo Sets indicator ID, style, and width for a given index.OverridablesDrawItem Called when a visual aspect of an owner-draw status bar control changes.

14.1 MFC’de Status Bar İşlemleriMFC’de status bar işlemleri framework tarafından kolaylaştırılmıştır. MFC’de eğer status bar frame penceresine bağlanırsa bazı faydalı işlemler otomatik olarak framework tarafından yapılır. Status bar tipik olarak programın ana penceresine ilişkin olmalıdır. MFC’de frame penceresinin alt penceresi biçiminde yaratılmalıdır.

MFC’de status bar işlemleri CStatusBar sınıfı ile temsil edilmiştir. MFC’de status bar oluşturmanınn adımları şöyledir;

Frame penceresinin veri elemanı olarak (aslında status bar herhangi bir pencerede yaratılabilir) CStatusBar türünden bir nesne tanımlanır.

Frame penceresinin WM_CREATE mesajı içinde CStatusBar::Create fonksiyonunu kullanarak status bar penceresi yaratılır.

Bölümleri yaratmak için CStatusBar::SetIndicators fonksiyonu çağırılır.

BOOL SetIndicators( const UINT* lpIDArray, int nIDCount );

129

Page 130: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Bölümler üzerinde ince ayarlamalar yapabilmek için CStatusBar::SetPaneInfo fonksiyonundan yararlanılır. (Statusc bar’ın bölümlerine MFC’de pane denilmektedir.)

BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );

Herhangi bir bölüme yazı yerleştirmek için CStatusBar::SetPaneText fonksiyonu kullanılır.

14.2 CStatusBar::Create Fonksiyonu

BOOL CStatusBar::Create(CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, UINT nID = AFX_IDW_STATUS_BAR );

dwStyle

CBRS_TOP Control bar is at top of frame window.

CBRS_BOTTOM Control bar is at bottom of frame window.

CBRS_NOALIGN Control bar is not repositioned when the parent is resized.

BOOL CreateEx( CWnd* pParentWnd, DWORD dwCtrlStyle = 0 ,DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM,UINT nID = AFX_IDW_STATUS_BAR );

Fonksiyonun ikinci parametresi WS_CHILD | WS_VISIBLE’ın yanı sıra CBRS_BUTTON, CBRS_TOP, CBRS_NOALIGN pencere biçimlerinden birini de içerebilir. Bu pencere biçimleri status bar’ın görüntüleneceği yer üzerinde etkili olur. Fonksiyonun son parametresi alt pencere ID değeridir.

14.3 CStatusBar::SetIndicators FonksiyonuBu fonksiyon ile status bar’ın bölümleri oluşturulur.

BOOL CStatusBar::SetIndicators(const UINT* lpIDArray, int nIDCount);

Fonksiyona UINT türden bir dizinin adresi ve uzunluğu verilir.

Wizard

SetIndicators(array, sizeof(array) / sizeof(int));

biçiminde kod üretir. Böylece dizinin eleman sayısı değişse bile bu çağırmanın değiştirilmesine gerek yoktur.

Sözkonusu UINT dizinin her elemanı aşağıdaki sembolik sabitlerden biri olarak verilir.

ID_SEPARATORID_INDICATOR_CAPSID_INDICATOR_NUMID_INDICATOR_SCRL

ID_SEPARATOR dışındaki sembolik sabitler sıarasıyla CapsLock, NumLock ve ScrollLock gibi tuşların basılıp basılmadığını görüntülemek için kullanılır. Bu sembolik sabitler kullanıldığında bu özel tuşlara basılıp basılmadığı basıldıysa ilgili yazının gösterilmesi tamamen framework tarafından (yani CFrameWnd sınıfının kodları tarafından – başka bir sınıfa bağlarsak bu işlemler yapılmaz. İlla ki frame window olmalı ki yapılsın.) yapılmaktadır. Bu tuşlara basıldığında görüntülenecek yazı bu sembolik sabitlerle aynı isimli string kaynakları kullanılarak belirlenebilir. Bu bölümlerin uzunlukları bu yazıların uzunluğuna bakılarak otomatik tespit edilmektedir.

130

Page 131: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Programcı kendi isteği doğrultusunda bir bölüm açmak isterse bunu ID_SEPARATOR değeri ile yapar. ID_SEPARATOR ile açılan ölümlerin uzunluğu otomatik alınır ancak daha sonra programcı ID_SEPARATOR’a ilişkin bölüm uzunluğunu ayarlayabilir.

Dizinin birinci elemanının ID_SEPARATOR olması özel bir anlam ifade eder. Böyle olduğunda framework menü elemanlarının üzerinde gezinildiğinde menü elemanlarının ID’leri ile aynı ID’ye sahip string kaynaklarının yazısını bu bölümde otomatik olarak gösterir. (Her menü eleman ID’si ile aynı ID’ye sahip string kaynağının yazısı \n ile ayrılmış iki kısımdan oluşur. Birinci kısım status bar’da görüntülenecek yazıdır. İkinci kısım ise fareyi toolbar üzerinde gezdirdiğimizde tooltip olarak görünecek yazıdır.) Özel olarak AFX_IDLE_MESSAGE ID’sine sahip string kaynağı menüden hiçbir seçim yapılmadığı durumda görüntülenecek yazıyı içerir.

Programcı kendi bölümünü yaratmak için genellikle dizideki ID_SEPARATOR’un yanına ID_SEPARATOR değerli eleman ekler. Daha sonra SetPaneInfo fonksiyonunu çağırır. (Yani SetIndicators’tan sonra SetPaneInfo ile uzunluklar ayarlanır.)

void CStatusBar::SetPaneInfo( int nIndex, UINT nID, UINT style, int cxWidth);

Fonksiyonun birinci parametresi bölümün index numarasıdır. İkinci parametre bölümün yeni ID’sidir. (Burası tipik olarak ID_SEPARATOR biçimindedir.) Bölümün türü SetIndicators fonksiyonunda belirlendikten sonra burada değiştirilebilmektedir. Üçüncü parametre bölümlerin sınır görüntüleri üzerinde etkili olur. Bu parametre tipik olarak SBPS_NORMAL biçiminde girilir. (olabilecek diğer parametreler aşağıdaki gibidir)

SBPS_NOBORDERS No 3-D border around the pane.

SBPS_POPOUT Reverse border so that text “pops out.”

SBPS_DISABLED Do not draw text.

SBPS_STRETCH Stretch pane to fill unused space. Only one pane per status bar can have this style.

SBPS_NORMAL No stretch, borders, or pop-out.

Son parametre bölümün piksel uzunluğudur.

2002-02-14 Perşembe

14.4 CStatusBar::SetPaneText FonksiyonuBu fonksiyon status bar’ın ilgili bölümüne yazı yerleştirmek için kullanılır.

BOOL CStatusBar::SetPaneText( int nIndex, LPCTSTR lpszText, BOOL bUpdate = TRUE);

Fonksiyonun birinci parametresi bölümün indeks numarası, ikinci parametresi yerleştirilecek olan yazıdır. Üçüncü parametresi ise değişikliğin hemen yansıtılıp yansıtılmayacağı bilgisidir. (FALSE dersek WM_PAINT geldiğinde işlem yapılır)

SINIF ÇALIŞMASI :

Wizard kullanarak bir uygulama yaratınız. Ana pencerenin StatusBar’ına bir bölüm ekleyiniz. Bir timer’den faydalanarak burada saati gösteriniz. Hazırlanan proje StatusBar1 içinde mevcuttur.

131

Page 132: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CMainFrame::~CMainFrame(){

KillTimer(13);}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)return -1;

// create a view to occupy the client area of the frameif (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,

CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL)){

TRACE0("Failed to create view window\n");return -1;

}

if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{TRACE0("Failed to create toolbar\n");return -1; // fail to create

}

if (!m_wndStatusBar.Create(this) ||!m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))

{TRACE0("Failed to create status bar\n");return -1; // fail to create

}m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(&m_wndToolBar);

m_wndStatusBar.SetPaneInfo(1, ID_SEPARATOR, SBPS_NORMAL, 45);SetTimer(13, 500, NULL);

return 0;}

void CMainFrame::OnTimer(UINT nIDEvent) {

char *buf[ ]={ "Pazar", "Pazartesi", "Salı", "Carşamba", "Perşembe", "Cuma", "Cumartesi"};

CTime time;CString strTime;

time = CTime::GetCurrentTime();strTime.Format("%02d:%02d:%02d ",

time.GetHour(), time.GetMinute(), time.GetSecond());strTime += buf[time.GetDayOfWeek()-1];m_wndStatusBar.SetPaneInfo(1,ID_SEPARATOR ,SBPS_NORMAL, 100);m_wndStatusBar.SetPaneText(1, strTime);CFrameWnd::OnTimer(nIDEvent);

}

14.5 StatusBar ID’leriStatusBar penceresinin her bölümünün ayrı bir ID değeri vardır. Bazı ID değerleri özel anlam ifade etmektedir. Ancak ID_SEPARATOR genel kullanım için düşünülmüştür. Aslında bölümlerin ID değerleri herhangi bir değer olabilir. Ancak ID_SEPARATOR MFC içinde define

132

Page 133: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

edildiği için kolay bir kullanım sunar. Yani biz örneğin resource.h dosyası içinde ID_MYSEPARATOR diye bir sembolik sabit tanımlayıp ID_SEPARATOR yerine onu da kullanabiliriz.

Yeni bir bölümün ID’si ID_SEPARATOR olabilir. Bunun hiçbir sakıncası yoktur. Ancak StatusBar ile UpdateCommand mekanizmasını kullanacaksak bu durumda farklı ID’ler almamız gerekebilir.

133

Page 134: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

15 TOOLBAR KULLANIMIToolbar bir grup tuş şekillerinden oluşan menüden seçim yapmak yerine doğrudan fare ile click yapmaya olanak sağlayan genel bir kontroldür. Toolbar API düzeyinde CreateWindow(Ex) fonksiyonu kullanılarak “Toolbarclassname” sınıf ismi ile yaratılır. Toolbar aynı zamanda CreateToolbarEx özel fonksiyonuyla da yaratılabilmektedir. Toolbar tuş şekilleri bir .BMP dosya içine çizilmelidir. .BMP dosyası içinde tuşlar default olarak 16 piksel genişlik 15 piksel yüksekliğe sahip olacak biçimde oluşturulur. Aslında toolbar tuş bölümlerinden oluşur. Tuş şekilleri bu bölümlerin içindedir. Tuşların yerleştirildiği bölümler default olarak 23 piksel genişlik 21 piksel yüksekliktedir.

Bu durumda her bölümün çizgisi ile birlikte uzunluğu 24 piksel olmaktadır. API düzeyinde toolbar oluşturabilmek için böyle bir bitmap dosyanın oluşturulması gerekir. Buradaki büyüklükler defaut büyüklüklerdir, değiştirilebilirler. Tabi değişik boyutlardaki toolbarlar yaratıldığında toolbar kontrolüne bir mesaj gönderilip her toolbar bölümünün genişliği ve yüksekliği bildirilmelidir.

API düzeyinde toolbar kontrolü yaratıldıktan sonra TB_XXX mesajları gönderilerek butonlar eklenir. Toolbar’ın her tuşunun bir ID değeri vardır. Bir tuşa basıldığında toolbar üst pencereye mesaj göndererek bu durumu bildirmektedir. Toolbar’ın her tuşunun ayrıca görüntüsünün dışında bir de yazısı olabilir. Fare bir toolbar tuşunun üzerine getirildiğinde bir yazı görüntülenir. Bu yazıya tooltip denir.

15.1 Gelişkin Kontroller (Common Controls) ve WM_NOTIFY MesajıStatusBar, toolbar, progress bar, spinner gibi kontroller Win32 sistemleri ile birlikte (bazıları NT ile birlikte çoğu da Windows 95 ile birlikte) standart bir kontrol haline getirilmiştir. Win 3.X sistemlerinde bu kontroller standart olmadığı için her programcı kendi kontrolünü yazmak zorunda idi. Win32 ile birlikte eklenen bütün bu kontrollere gelişkin kontroller (common controls) denir. Windows’un standart kontrolleri bilindiği gibi user32.dll modülü içindedir. Halbuki gelişkin kontroller comctl32.dll dosyası içindedir. Bu DLL Windows ile otomatik bir biçimde yüklenmemektedir. Bu DLL’in user seviyesinde yüklenmesi için InitCommonControls ya da InitCommonControlsEx fonksiyonlarının çağırılması gerekir. API düzeyinde ya da MFC’de bu kontrollerin kullanılabilmesi için bu fonksiyonun başlangıçta bir kez çağırılması gerekir. MFC wizard tarafından bu fonksiyon zaten otomatik olarak çağırılmaktadır.

WM_COMMAND mesajı standart kontrollerin üst pencereye bildirimde bulundukları durumda kullanılır. Maalesef WM_COMMAND mesajında yalnızca notification code, alt pencere ID değeri ve alt pencere HANDLE bilgileri üst pencereye gönderilebilmektedir. Programcı hangi olay olduğunu tespit ettikten sonra işlem detayları için alt pencereye mesaj göndermek zorunda kalmaktadır. Oysa gelişkin kontroller bildirim mesajlarında pek çok bilgi yollamak isterler. Bu nedenle gelişkin kontroller üst pencereye kısıtlı WM_COMMAND mesajı yerine WM_NOTIFY mesajı yollarlar. WM_NOTIFY mesajının parametreleri şöyledir.

wParam Kontrol IDlParam NMHDR* (veya LPNMHDR)

Mesajın lParam parametresi NMHDR türünden bir adrestir. Bu yapı gelişkin kontrol tarafından tahsis edilip içi doldurulmaktadır. NMHDR aslında lParam tarafından gösterilen bilgi alanının başlık kısmıdır. Yani aslında lParam değişken uzunlukta bir alanı gösterir. Ancak bu alanın başında her zaman NMHDR yapısı vardır. lParam’ın gösterdiği yapı mesajdan mesaja değişebilmektedir. Ancak bu yapının ilk elemanı NMHDR yapısıdır.

typedef struct tagNMHDR {HWND hwndFrom; // Hangi kontrolden

134

Page 135: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

UINT IDFrom; // Kontrolün ID değeriUINT code; // Notification code

}NMHDR, *LPNMHDR;

UINT code aşağıda sıralanmıştır.NM_CLICK The user has clicked the left mouse button within the control.NM_DBLCLK The user has double-clicked the left mouse button within the control.NM_KILLFOCUS The control has lost the input focus.NM_OUTOFMEMORY The control could not complete an operation because there is not enough memory available. NM_RCLICK The user has clicked the right mouse button within the control.NM_RDBLCLK The user has double-clicked the right mouse button within the control.NM_RETURN The control has the input focus, and the user has pressed the ENTER key.NM_SETFOCUS The control has received the input focus.

Bu durumda WM_NOTIFY mesajı işlenirken önce lParam NMHDR türünden göstericiye atanır. Sonra notification code ya da ID switch içine sokularak mesajın hangi gelişkin kontrolden geldiği bulunur. Bundan sonra lParam gelişkin kontrole özgü yapıya dönüştürülür ve işlemler yapılır.

case WM_NOTIFY:pNmHdr = (LPNMHDR) lParam;switch(pNmHdr->code) {

case TTP_GETDISPINFO: // Tooltip için gelen codepText = (LPTOOLTIPTEXT) lParam;// ...

}}

MFC’de framework gelişkin kontrol mesajları için WM_NOTIFY mesajını işleyerek kolaylık sağlamaktadır. Yani MFC’de gelişkin kontrollerin WM_COMMAND yerine WM_NOTIFY yollamaları framework içinde gizlenmiştir. Anımsanacağı gibi MFC’de hem WM_COMMAND hem de WM_NOTIFY mesajları için OnCommand sanal fonksiyonu çağırılmaktadır.

135

Page 136: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

16 MFC’DE TOOLBAR İŞLEMLERİMFC’de toolbar işlemleri CToolBar sınıfı ile yapılmaktadır. CToolBar sınıfı CStatusBar sınıfı gibi CControlBar sınıfından türetilmiştir.

CWnd

CControlBar

CStatusBar CToolBar

Görüldüğü gibi CToolBar sınıfı status bar, toolbar gibi bazı gelişkin kontroller için taban sınıf rolündedir. Toolbar aslında herhangi bir pencerenin alt penceresi olarak yaratılabilir. Ancak toolbar’ların ana pencerelerin içinde yaratılıp kullanılmaları önerilmektedir. Bu nedenle MFC’de CToolBar nesnesi frame sınıfının veri elemanı biçiminde tanımlanmalıdır ve tıpkı status bar kontrolünde olduğu gibi frame penceresinin WM_CREATE mesajı içinde yaratılmalıdır.

CToolBar Class MembersConstructionCToolBar Constructs a CToolBar object.

Create Creates the Windows toolbar and attaches it to the CToolBar object.

CreateEx Creates a CToolBar object with additional styles for the embedded CToolBarCtrl object.

SetSizes Sets the sizes of buttons and their bitmaps.

SetHeight Sets the height of the toolbar.

LoadToolBar Loads a toolbar resource created with the resource editor.

LoadBitmap Loads the bitmap containing bitmap-button images.

SetBitmap Sets a bitmapped image.

SetButtons Sets button styles and an index of button images within the bitmap.AttributesCommandToIndex Returns the index of a button with the given command ID.

GetItemID Returns the command ID of a button or separator at the given index.

GetItemRect Retrieves the display rectangle for the item at the given index.

GetButtonStyle Retrieves the style for a button.

SetButtonStyle Sets the style for a button.

GetButtonInfo Retrieves the ID, style, and image number of a button.

SetButtonInfo Sets the ID, style, and image number of a button.

GetButtonText Retrieves the text that will appear on a button.

SetButtonText Sets the text that will appear on a button.

GetToolBarCtrl Allows direct access to the underlying common control

2002-02-19 Salı

16.1 Toolbar Yaratmanın AdımlarıMFC’de toolbar yaratmak için kaynak (resource) kullanılır ya da kaynak kullanılmadan da işlem yapılabilir. Toolbar kaynağı API düzeyinde anlamlı ve tanımlı bir kaynak cinsi değildir yalnızca CToolBar sınıfı için anlamlı bir kaynak türüdür. Toolbar kaynağı hem işlemleri kolaylaştırmak için hem de ClassWizard etkileşimini arttırmak için düşünülmüştür. Toolbar yaratma adımları şunlardır;

Pencere sınıfının (yani Frame sınıfının) veri elemanı olarak CToolBar sınıfı türünden bir nesne tanımlanır.

CToolBar sınıfı türünden nesne ile CToolBar::Create fonksiyonu çağırılır. (Bu işlem Frame penceresinin WM_CREATE mesajında yapılabilir)Artık toolbar penceresi yaratılmıştır. Ancak henüz bir tuş görüntüleme işlemi yapılmamıştır.

Toolbar butonları için bir .BMP dosyası çizilir ve CToolBar::LoadBitmap fonksiyonu ile bu .BMP dosyası toolbar kullanımı için yüklenir. (Bu fonksiyon parametre olarak BMPnin

136

Page 137: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

resource’daki ismini ister) Bu aşamada toolbar’ın butonları da şekilsel olarak oluşturulmuş durumdadır.

Artık toolbar tuşlarının tek tek ID değerleri ile ilişkilendirilmesi gerekir. Çünkü bir tuşa click yapıldığında hangi ID ile ON_COMMAND makrosunun çağırılacağı bilinmelidir. Bu işlem CToolBar::SetButtons ile yapılır.

Eğer toolbar kaynak kullanılarak oluşturulacaksa 3. ve 4. adımlar yerine (LoadBitmap, SetButtons yerine) CToolBar::LoadToolBar kullanılır. Bu fonksiyon toolbar kaynağını yüklemektedir. Zaten toolbar kaynağında 3. ve 4. aşamadaki belirlemeler yapılmaktadır.

16.2 CToolBar::Create Fonksiyonu

BOOL CToolBar::Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP, UINT nID = AFX_IDW_TOOLBAR);

Fonksiyonun ikinci parametresi pencere biçimleri, üçüncü parametresi alt pencere ID değerleridir. Bu fonksiyonun yanısıra aynı sınıfın CreateEx fonksiyonu da vardır. Bu fonksiyonda ek olarak toolbar biçimine ilişkin başka bir parametre daha eklenmiştir. Görüldüğü gibi Create fonksiyonlarında toolbar’ın ilk kez nerede görüntülebeceği de belirtilmektedir.

BOOL CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle = TBSTYLE_FLAT, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect rcBorders = CRect(0, 0, 0, 0), UINT nID = AFX_IDW_TOOLBAR);the control bar için dwStyleCBRS_ALIGN_TOP CBRS_ALIGN_BOTTOM CBRS_ALIGN_LEFT CBRS_ALIGN_RIGHT CBRS_ALIGN_ANY CBRS_BORDER_TOP CBRS_BORDER_BOTTOM CBRS_BORDER_LEFT CBRS_BORDER_RIGHT CBRS_FLOAT_MULTI CBRS_TOOLTIPS CBRS_FLYBY CBRS_GRIPPER

16.3 CToolBar::LoadBitmap Fonksiyonu

BOOL CToolBar::LoadBitmap( LPCTSTR lpszResourceName );BOOL CToolBar::LoadBitmap( UINT nIDResource );

Fonksiyonun parametreleri kaynağın alfabetik ya da sayısal isimleridir.

Tabi toolbar kaynaktan hareketle yaratılacaksa (kaynakta yaratılırsa ClassWizard’da çıkar) bu fonksiyonun çağırılmasına gerek yoktur.

16.4 CToolBar::SetButtons FonksiyonuBu fonksiyon toolbar tuşarı ile ID’leri ilişkilendirir.

BOOL CToolBar::SetButtons( const UINT* lpIDArray, int nIDCount );

Bu fonksiyon tuşlara karşılık gelen ID’lerin bulunduğu dizinin başlangıç adresi ile uzunluğunu parametre olarak alır.

16.5 Toolbar Kaynağının KullanılmasıToolbar kaynağı tuş ID değerlerinden oluşmaktadır. Toolbar kaynak ismi ile aynı isimli bir bitmap kaynağı olmalıdır. CToolBar::LoadToolbar toolbar kaynak ismini parametre olarak alır.

137

Page 138: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Aynı isimli bir bitmap dosyasını ve tuş ID’lerini toolbar kaynağından alır. Toolar’a ilişkin tipik bir kaynak .RC dosyasında şu görünümdedir.

IDR_TOOLBAR Bitmap Toolbar.bmpIDR_TOOLBAR Toolbar 16, 15{

BUTTON ID_MYBUTTON1BUTTON ID_MYBUTTON2...SEPARATORBUTTON ID_MYBUTTON3BUTTON ID_MYBUTTON4

}(Altı çizili olanlar anahtar sözcüklerdir.)

CToolBar::LoadToolBar fonksiyonunun prototipi şöyledir;

BOOL CToolBar::LoadToolBar( LPCTSTR lpszResourceName );BOOL CToolBar::LoadToolBar( UINT nIDResource );

Tabi bu kaynak metni el ile değil kaynak editör sayesinde yazdırılmaktadır.

16.6 Wizard İle Yaratılmış Toolbar’ı KullanmakUygulamalarda genellikle yeni bir toolbar yaratmak yerine wizardın yaratmış olduğu toolbar üzerinde değişiklikler yapılır. Bunun için bazı toolbar tuşları programcı tarafından silinebilir ya da yenileri eklenebilir. Programcı hiç toolbar kullanmak istemeyebilirde. Wizardın yarattığı toolbar’ı silmek için

1 . Resource kaynak bölümünden toolbar kaynağı silinmelidir.

2 . Frame penceresinin WM_CREATE mesajındaki toolbar yaratma satırları silinmelidir.

3 . Toolbar veri elemanı silinmelidir.

16.7 Dockable Toolbar Toolbarın penceresini bir köşesinden diğer köşesine taşınabilme özelliğine dockable toolbar özelliği denir. Toolbarın dosckable hale getirilebilmesi için şu işlemler yapılmalıdır;

1 . CToolbar sınıfının taban sınıfı olan CControlBar sınıfının EnableDocking üye fonksiyonu çağırılır.

void CControlBar::EnableDocking( DWORD dwStyle );dwStyle aşağıdaki gibidir.CBRS_ALIGN_TOP Allows docking at the top of the client area. CBRS_ALIGN_BOTTOM Allows docking at the bottom of the client area. CBRS_ALIGN_LEFT Allows docking on the left side of the client area. CBRS_ALIGN_RIGHT Allows docking on the right side of the client area. CBRS_ALIGN_ANY Allows docking on any side of the client area. CBRS_FLOAT_MULTI Allows multiple control bars to be floated in a single mini-frame window.

Fonksiyonun parametresi hangi köşelere dock işlemi yapılabileceğini belirten sembolik sabitlerin bit OR işlemine sokulmasıyla elde edilir. CBRS_ALIGN_ANY her yere dock yapılabileceğini belirtir.

2 . Toolbar’ın dock işleminden çeşitli çizim nedenlerinden dolayı Frame penceresinin haberdar edilmesi gerekir. Bu işlem CFrameWnd::EnableDocking üye fonksiyonunun çağırılması ile yapılır. Bu fonksiyonun parametresi de aynı biçimde docking yerin belirlemekte kullanılır. Burada belirtilen yerler toolbar’da belirtilen yerleri kapsamalıdır.

3 . Artık docking işlemi için gerekli hazırlıklar yapılmıştır. Toolbar CFrameWnd::DockControlBar fonksiyonu ile dock işlemine sokulur. Toolbar bu fonksiyonun çağırılmasıyla bu fonksiyonun parametresi ile belirtilen köşede görüntülenir.

138

Page 139: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CFrameWnd::DockControlBar( CControlBar * pBar, UINT nDockBarID = 0, LPCRECT lpRect = NULL );

Fonksiyonun ikinciparametresi dock yapılacak yeri belirler. Bu parametre default olarak sıfır değerini almıştır. Bu parametre sıfır olarak geçilirse CToolBar::Create fonksiyonunda belirlenen yere dock işlemi yapılır. //toolbar yüklemek için gerekli kod aşağıdaki gibidir

m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(&m_wndToolBar);

m_wndStatusBar.SetPaneInfo(1, ID_SEPARATOR, SBPS_NORMAL, 45);

16.8 CToolBar Sınıfının Diğer FonksiyonlarıToolbar default boyutundan farklı çizilecekse yeni uzunluğun SetSizes fonksiyonuyla belirtilmesi gerekir. SetButtonStyle fonksiyonu ile toolbar tuşları SEPARATOR ya da normal tuş biçimine dönüştürülebilir. Ayrıca toolbar bir şeklin yanısıra onunla ilişkili bir yazı da içerebilmektedir. Bir toolbar yazısı SetButtonText fonksiyonuyla set edilebilir. Bu yazının görüntülenebilmesi için toolbar tuşu ile bitmap büyüklüğü arasında belirli bir büyüklük olması gerekir.

16.9 Toolbar Mesajlarının İşlenmesiAPI düzeyinde toolbar için en önemli mesajlar farenin toolbar üzerinde gezdirilmesi ile oluşan mesajlar ve butona tıklandığında oluşan mesajlardır. Fare üzerinde gezinirken tooltip görüntüleme işlemi yapılmaktadır. Click mesajı herhangi bir işlemi başlatmak amacıyla kullanılmaktadır. Toolbar bilindiği gibi üst pencereye WM_NOTIFY mesajı göndermektedir.

MFC’de bilindiği gibi bir dizi işlem sonrasında CWnd::OnNotify sanal fonksiyonu çağırılmaktadır. Bu fonksiyon mesaj haritasında ON_COMMAND makrolarını çalıştırmaktadır. Sonuç olarak toolbar tuşuna click yapıldığında MFC’de işlem yine ON_COMMAND makrosu ile yapılır.

Genellikle her toolbar tuşunun bir menü karşılığı vardır. Programcı menü ID’si ile toolbar tuş ID’sini aynı yaparsa toolbar ve menü işlemlerini birleştirir. Genellikle bir tane ON_COMMAND makrosu vardır. Menüden seçim yapıldığında da toolbar’dan seçim yapıldığında da aynı fonksiyon çağırılır.

MFC’de tooltip işlemleri framework tarafından otomatik olarak yapılmaktadır. Dolayısıyla bir toolbar tuşuna ilişkin tooltip çıkartmak için aynı isimli bir string kaynağı yaratılıp \n karakterinin sağına yazı girilir. Özetle aynı ID değerine sahip bir toolbar tuşu, bir menü elemanı ve bir string kaynağı varsa sistemin yönetilmesi çok kolaylaşır.

16.10Birden Çok Toolbar İle ÇalışmakBazen aynı pencereye ilişkin birden fazla toolbar da kullanılabilir. Birden fazla toolbarın görüntülenmesinde bir problem yoktur. Aynı adımlar izlenmelidir. Toolbarların her ikisi birden dockable yapılabilir. Bazen iki toolbar yaratılır ancak bunlar çeşitli sıralarda görüntülenir, yani aynı anda görüntülenmez. Toolbarları görünmez yapmak için CFrameWnd::ShowControlBar fonksiyonu kullanılır.

void CFrameWnd::ShowControlBar( CControlBar* pBar, BOOL bShow, BOOL bDelay );Aynı fonksiyon StatusBar’ı görünmez yapmak için de kullanılabilir. Fonksiyonun ikinci parametresi toolbar ya da status barın görünür olup olmayacağını belirler (TRUE görünür, FALSE gizlemek için). Fonksiyonun son parametresi TRUE ise işlem biraz gecikmeli olabilmektedir. FALSE ise ani olmaktadır. (Mesaj döngüsüne bırakılıp bırakılmaması durumu)

139

Page 140: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

16.11StatusBar ve Toolbar Kontrollerinin UpdateCommand Mekanizması İle İlişkisiMenü elemanlarında olduğu gibi StatusBar ve Toolbar kontrollerinde de UpdateCommand mekanizması kullanılabilmektedir. StatusBar kaynak tabanlı olmadığı için StatusBar için UpdateCommand makroları programcı tarafından elle girilmelidir. Toolbar kaynak tabanlı yaratılmışsa toolbar ID’leri Class Wizard’da görüntülendiği için UpdateCommand makroları Class Wizard ile oluşturulabilmektedir.

StatusBar ve ToolBar kontrollerine ilişkin Update Command makroları belirli bir olay gerçekleştiğinde değil thread’in idle process işleminde çağırılmaktadır. Toolbar click işlemi ile menüden seçim işleminin birbirleri ile koordinasyonu için toolbar elemanlarına ilişkin UpdateCommand makroları da çağırılmaktadır. Bir toolbar tuşuna ilişkin UpdateCommand fonksiyonu yazmışsak bu fonksiyon idle process tarafından sürekli çağırılır. UpdateCommand makrolarının arka planda sürekli çağırılması idle process tarafından yapıldığından bir çalışma yavaşlığına yol açmaz. Benzer biçimde StatusBar bölümleri için de UpdateCommand makroları ve fonksionları yazılabilir. Bir StatusBar bölümü için UpdateCommand makrosu yazılacaksa o bölümün ID’si ile aynı ID’ye sahip bir string kaynağı olmak zorundadır.

UpdateCommand fonksiyonlarına geçirilen CCmdUI parametresi yalnızca menü işlemlerinde değil toolbar ve StatusBar işlemlerinde de kullanılabilir. Örneğin UpdateCommand fonksiyonu StatusBar bölümü için çağırılmışsa biz fonksiyon içinde CCmdUI sınıfının SetText fonksiyonunu çağırırsak StatusBar’ın ilgili bölümünün yazısını set eder. Genel olarak CCmdUI sınıfı yalnızca menü işlemlerini değil StatusBar ve ToolBar işlemlerini de yapacak biçimde tasarlanmıştır.

2002-02-26 Salı

SINIF ÇALIŞMASI :

MFC wizard’ın ürettiği koda yeni bir toolbar ekleyiniz. Menüden bir eleman seçildiğinde bu toolbar’ı görünür hale getiriniz.

140

Page 141: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

17 SINIF BİLGİLERİNİN ÇALIŞMA ZAMANINDA ELDE EDİLMESİBazı uygulamalarda özellikle çoklu türetmenin olduğu durumlarda taban sınıf göstericisine atanmış olan bir adresin gerçekte hangi türemiş sınıfa ilişkin olduğunu tespit etmek gerekebilir. Nesnenin gerçek türünü tespit eden programcı taban sınıfa ilişkin göstericiyi gerçek türe dönüştürerek işlemler yapmak isteyebilir. Gerçi doğru bir nesneye yönelimli tasarımda aşağıya doğru dönüştürme (downcast) işlemine gereksinim duyulmamalıdır. Bu işlemler yerine sanal fonksiyon kullanımı tercih edilmelidir. (Türünü bilmeden işlem yapmaya polymorphism denir.)

C++’ta programın çalışma zamanı sırasında adresi elde edilen bir nesnenin hangi sınıfa ilişkin olduğu tespit edilebilmektedir. Yani türemiş sınıf nesnesini kütüphane içindeki bir fonksiyona geçirsek bu fonksiyonun parametresi taban sınıf türünden bir gösterici olsa fonksiyon yazıldığı zaman mevcut olmayan türemiş sınıfın türünü tespit edebilir. Bunun için C++’a typeid operatörü eklenmiştir. typeid operatörü type_info sınıfı türünden bir referans ile geri döner. type_info sınıfı araştırılacak sınıfın sınıf bilgilerini veren elemanlara sahiptir. Türetme durumunda yalnızca adres bilgisi bilinen bir türemiş sınıf nesnesinin bilgilerinin edinilebilmesi için sınıf sisteminin sanal fonksiyon tablosuna sahip olması gerekir. Çünkü derleyiciler type_info sınıfındaki bilgileri sanal fonksiyon tablosunda tutarlar. Bu nedenle bir dizi türetme içerisinde böyle bir tespitin yapılabilmesi için taban sınıfın en az bir sanal fonksiyonu olmalıdır. (Bunu sağlamanın en kolay yolu taban sınıfın destructor’unu sanal yapmaktır.) typeid operatörü aslında her nesneye uygulanabilmektedir. Ancak sınıf sisteminin sanal fonksiyon tablosu yoksa bu durumda derleyici derleme sırasında nesnenin türüne bakarak tespitini static düzeyde yapar. Programın çalışma zamanı sırasında nesnenin türünün tespit edilebilmesi için derleyici verimli olmayan yöntemler uygulamaktadır. (Sınıf bilgilerini sanal fonksiyon tablosuna yazarak tabloyu büyütmek gibi) Bu yüzden derleyicilerin çoğunda bu özellik default olarak bulunmaz derleyicinin ayarları ile oynanarak etkin hale getirilir. Örneğin Visual C++’ta bu özellik etkin değildir. Etkin hale getirebilmek için, RTTI özelliğinin seçilmesi gerekir.

MFC’de çeşitli durumlarda bir sınıfın gerçek türünün tespit edilmesi gerekmiştir. Ancak bu işlemler typeid operatörü ile yapılmamıştır. Zaten typeid operatörü C++’a MFC’den sonra eklenmiştir. MFC’de RTTI (Run-Time Type Info) özelliği için özel makrolar kullanılmaktadır. Bu makrolar aslında sınıfa veri elemanı ve fonksiyon ekleyip bulara ilk değerler vermektedir.

141

Page 142: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

17.1 CRuntimeClass SınıfıCRuntimeClass sınıfı herhangi bir sınıfın ismi, taban sınıfı, uzunluğu gibi önemli bilgileri tutan yardımcı bir sınıftır. CRuntimeClass sınıfı bir yapı gibidir. Yani aggregate bir sınıftır. Bu türeden sınıf nesnelerine küme parantezleri içinde ilk değer verilebilir. CRuntimeClass sınıfı iki üye fonksiyona ve pek çok veri elemanına sahip bir yapı görünümündedir.

17.2 DECLARE_DYNAMIC ve IMPLEMENT_DYNAMIC MakrolarıBu makrolar bir sınıf için RTTI bilgilerinin oluşturulmasına kolaylık sağlamak amacıyla kullanılırlar. DECLARE_DYNAMIC makrosu şöyle yazılmıştır;

#define DECLARE_DYNAMIC(class_name) \pulic: \

static const CRuntimeClass class##class_name; \virtual CRuntimeClass *GetRuntimeClass() const;

(Makrolarda #, “” içinde yazılmasını sağlar, ## token pasting (birleştirme) yapar.)

Görüldüğü gibi DECLARE_DYNAMIC makrosu sınıfa CRuntimeClass sınıfı türünden static bir sınıf nesnesi ile GetRuntimeClass isimli sanal bir fonksiyonun prototipini eklemiştir. CRuntimeClass türünden static nesne sınıfa ilişkin önemli bilgileri tutar. GetRuntimeClass sanal fonksiyonu ise bu nesnenin adresini vermektedir. Böylece programın çalışma zamanı sırasında taban sınıf göstericisi yoluyla nesnenin orijinaline ilişkin sınıf hakkında bilgi edinilebilir. Bunun için

1 – Taban sınıf göstericisi ile GetRuntimeClass sanal fonksiyonu çağırılır. Bu fonksiyon sınıf hakkında bilgilerin bulunduğu CRuntimeClass türünden nesnenin adresi ile geri döner.

2 – CRuntimeClass nesnesine başvurularak sınıfın bilgileri elde edilir.

(Görüldüğü gibi aslında yukarda yapılanlar ile C++’ta typeid operatörü ile yapılanlar aynı şeylerdir. Mekanizma çok benzerdir. C++’taki type_info sınıfı buradaki CRuntimeClass sınıfına karşılık gelmektedir.)

DECLARE_DYNAMIC makrosu sınıf bildirimi içine yerleştirilmelidir. (public bir alan açtığı için sona yerleştirilmesi uygundur.) Örnek;

class CMyClass : public CWnd {// ...DECLARE_DYNAMIC(CMyClass)

};

IMPLEMENT_DYNAMIC makrosu şöyle yazılmıştır;

#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \// static nesneye ilk değer veriliyor

CRuntimeClass class_name::class##class_name : { \#class_name, sizeof(class_name), ... } \// sınıfın adı “” içinde static nesneye veri olarak girilmişCRuntimeClass* class_name::GetRuntimeClass() const \{ return &class##class_name; }

Görüldüğü gibi IMPLEMENT_DYNAMIC makrosu static nesneye ilk değer verip GetRuntimeClass fonksiyonunun tanımlamıştır. Bu makro .CPP dosyasının tepesine (global bölümüne) yazılmalıdır. Örneğin;

IMPLEMENT_DYNAMIC(CMyClass, CWnd)

MFC’de RTTI bilgileri için bir sınıf türettiğimizde türettiğimiz sınıflarda DECLARE_DYNAMIC ve IMPLEMENT_DYNAMIC makrolarını yazmamız gerekir. Eğer yazmazsak türettiğimiz sınıf bu mekanizmanın dışında kalır.

142

Page 143: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

17.3 Programın Çalışma Zamanı Sırasında Türü Bilinmeyen Bir Sınıf Türünden Nesne Yaratılması

Bazen bir sınıf sisteminde yeni bir sınıf türetiriz ve kütüphanede bulunan bir fonksiyonun da türettiğimiz sınıf türünden dinamik nesne yaratması gerekir. Bu işlem nasıl yapılabilir? Ancak iki yolla yapılabilir. Örneğin B sınıfından bir C sınıfı türetmiş olalım

ABC

ve Func isimli fonksiyonun da türünü bilmediği sınıf türünden nesne yaratması istensin;

1 – ) Aşağıdaki gibi sanal fonksiyon kullanılarak yapılabilir;

(a)void Func(A* p){

p->Create();}

(b)class C : public B {

//...public:A* C::Create(){

return new C();}};

(c)C c;Func(&c);

Burada Create kendi sınıfı türünden dinamik bir nesne yaratan sanal bir fonksiyondur.

2 - ) Birinci tasarımda nesne yaratabilmek için gereksiz bir nesne tanımlanmak zorunda kalınmıştır. Eğer sınıfa nesne yaratan static bir fonksiyon eklenir ve onun adresi Func fonksiyonun geçirilirse problem daha iyi çözülür.

(a)void Func(void (*p)()){

(*p)();}

(b)class C : public B {

//...public:

static A* Create(){

return new C();}

};

(c)Func(C::Create);

MFC’de benzer bir yöntem makrolar yardımıyla uygulanmaktadır. Bu işlemler için MFC’de DECLARE_DYNCREATE ve IMPLEMENT_DYNCREATE makroları kullanılmaktadır.

143

Page 144: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

17.4 DECLARE_DYNCREATE ve IMPLEMENT_DYNCREATE MakrolarıBu makrolar kendi içlerinde DECLARE_DYNAMIC ve IMPLEMENT_DYNAMIC makrolarını içerir ve aynı zamanda sınıfa statik bir yaratıcı fonksiyon ekler.

DECLARE_DYNCERATE şöyle yazılmıştır;

#define DECLARE_DYNCREATE(class_name) \DECLARE_DYNAMIC(class_name) \static CObject CreateObject();

IMPLEMENT_DYNCREATE ise şöyle yazılmıştır;

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \IMPLEMENT_DYNAMIC(class_name, base_class_name) \CObject* class_name::CreateObject() \{ return new class_name; }

bu makrolar türetilen sınıfın .H ve .CPP dosyalarına yazılmalıdır. Bu makrolar yukarıda yazılanlardan biraz farklıdırlar. Örneğin CreateObject fonksiyonunun adresi aynı zamanda bu makrolarla CRuntimeClass türünden nesnenin içine yazılmaktadır. Özetle, bu makrolarla CRuntimeClass türünden sınıf nesnesi sınıfın CreateObject static fonksiyonunun adresini de tutar hale gelmektedir.

2002-02-28 Perşembe

Programcı bir sınıf için DECLARE_DYNCREATE ve IMPLEMENT_DYNCREATE makrolarını eklediğinde şunları sağlmanış olur.

1 – Sınıfa CRuntimeClass türünden static bir sınıf nesnesi ile nesne yaratan CreateObject isimli static bir fonksiyon eklenmiştir.

2 – Bu static sınıf nesnesinin içine sınıf ile ilgili önemli bütün bilgiler yazılmıştır ve yaratıcı fonksiyonun adresi de bu nesnenin içindedir.

Bu durumda bir fonksiyonun bir sınıf türünden nesneyi dinamik olarak yaratabilmesi için ya yaratıcı fonksiyon olan CreateObject fonksiyonunun başlangıç adresini alması ya da CRuntimeClass türünden static nesnenin adresini alması gerekir. (Çünkü bu static nesne içinde CreateObject fonksiyonunun adresi bulunmaktadır.) Ayrıca CRuntimeClass sınıfının yaratıcı fonksiyonu çağırarak nesne yaratan CreateObject isimli bir üye fonksiyonu da vardır.

Özetle, kütüphanedeki bir fonksiyonun bizim türettiğimiz bir sınıf türünden dinamik bir nesne yaratbilmesi için fonksiyonun parametresinin CRuntimeClass türünden bir gösterici olması gerekir. Bizim de makrolar tarafından sınıfa yerleştirilmiş olan CRuntimeClass türünden static nesnenin adresini fonksiyona geçmemiz gerekir.

1 - ) Kütüphanedeki fonksiyon

void Func(CRuntimeClass* pRuntimeClass){

CObject* pNewObject;pNewObject = pRuntimeClass->CreateObject();

// ...}

2 - )

// .H dosyadaclass CMyWnd:: public CWnd {

//...DECLARE_DYNCREATE(CMyWnd)

}

// .CPP dosyada

144

Page 145: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

IMPLEMENT_DYNCREATE(CMyWnd, CWnd)

3 - ) Fonksiyonun çağırılması

Func(&CMyWnd::classCMyWnd); //Makrodaki class##class_name’den dolayı

Görüldüğü gibi bir fonksiyon CRuntimeClass türünden gösterici parametresi almışsa dinamik bir nesne yaratmak istemektedir. Biz de fonksiyona parametre olarak makroların yerleştirdiği static nesnenin adresini vermeliyiz.

Sınıfın CRuntimeClass türünden static nesnesinin ismi makro içinde oluşturulmaktadır. Bu ismi doğrudan kullanmak yerine RUNTIME_CLASS isimli makro bu static nesnenin adresini elde eder.

#define RUNTIME_CLASS(class_name) (&class_name::class##class_name)

Böylece programcı CRuntimeClass türünden gösterici parametresine sahip fonksiyona parametreyi RUNTIME_CLASS makrosunu kullanarak geçer. Örneğin

Func(RUNTIME_CLASS(CMyWnd));

145

Page 146: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

18 THREADLERLE ÇALIŞMAWin32’de her process birden fazla threadden oluşabilir. İşletim sistemi çizelgelemeyi (scheduling) thread tabanında yapmaktadır. Win32’de thread’ler arası geçiş 20 ms.’lik quanta süresindedir. Aynı process’in thread’leri arasındaki geçiş sırasında düşük anlamlı 2GB’lik alana dokunulmaz. Böylece bir process’e ilişkin thread’ler aynı bellek alanı içinde çalışırlar. Yani aynı global değişkenleri kullanabilirler. Bir process çalıştırıldığında sistem otomatik olarak ismine ana thread (main thread) denilen bir başlangıç thread’i oluşturur. Process bu ana thread’den çalışmaya başlar. Tipkı olarak çok threadli çalışmada çalışma ana threadle başlar ve programcı CreateThread API fonksiyonunu çağırarak diğer thread’leri yaratır. Threadler arasında parent – child ilişkisi yoktur. Threadler normal olarak thread fonksiyonunun bitmesiyle ya da ExitThread API fonksiyonuyla sonlandırılırlar.

Thread bir akış belirtir. Bir thread’in başlangıç noktası CreateThread API fonksiyonunda bir fonksiyon adresi ile belirtilir. Her threadin kullandığı Stack diğerinden ayrıdır ve default 1MB uzunluğundadır. Threadlerin Stacklerinin ayrı olması yerel değişkenlerinin farklı kopyalarının yaratılması anlamına gelir. Yani iki thread aynı fonksiyon üzerinde ilerliyor olsun. Yerel değişkenler birbirine karışmaz, farklı kopyalar üzerinde işlemler yapılıyordur.

Aslında thread fonksiyonu bittiğinde yine ExitThread fonksiyonu çağırılarak thread yok edilmektedir. CreateThread fonksiyonu yeni bir akış oluşturur ve kendisi başarılı bir biçimde geri döner.

... CreateThread(...){

Yeni bir akış oluştur,Başlangıç noktasını BEGIN olarak belirleve END’e atla

BEGIN:call ThreadFunccall ExitThread

END:}Win32’de bir process’i sonlandırmak için ExitProcess API fonksiyonu çağırılır. (exit Standart C fonksiyonu default olarak bu fonksiyonu çağırmaktadır.) Normal bir GUI uygulamasında WinMain içinde ExitProcess çağırılmamışsa programın akışı mesaj döngüsünden çıkar, WinMain biter ve akış startup modülden devam eder. Bu noktada startup modülde ExitProcess uygulanmıştır. ExitProcess normal olarak process’in tüm thredlerini tek tek sonlandırır. Buradan önemli bir onuç çıkar; Main thread içinde birkaç thread yaratılmış olsun. Örneğin bir console uygulamasında biz bu threadleri beklemezsek ana thread main fonksiyonunu bitirir ve tüm process threadleri ile birlikte biter. Bu tür durumlarda diğer threadler sonlanana kadar WaitForSingleObject ya da WaitForMultipleObjects fonksiyonlarıyla beklenmelidir.

void main(void){

//...hThread1 = CreateThread();hThread2 = CreateThread();WaitForMultipleObjects();//...

}

18.1 Threadler Neden Kullanılır?1 – ) Arka planda birtakım işlemlerin kontrol edildiği durumlarda (örneğin bir işlemi yaparken aynı zamanda bir donanım olayının olup olmadığını anlamak) thread kullanımı tasarım bakımından önemli bir algoritmik fayda sağlamaktadır.

2 - ) Birden fazla thread ile çalışıldığında bir bloke işlemi sonucunda bütün process durmaz yalnızca o thread durur. Yani programın çalışma yüzdesi arttırılmaktadır. Programın ne kadar çok threadi varsa o kadar çok CPU zamanı harcar.

146

Page 147: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3 - ) Bir processin iki farklı threadi tek bir processor varsa aynı anda çalışamaz. Ama birden fazla processor varsa gerçekten aynı anda çalışabilir. Bunun için ayrı bir programlama tekniğinin kullanılması gerekir. Bu duruma paralel programlama denir.

4 - ) Threadler birbirleri ile global değişkenler yoluyla haberleşebildiği için threadler arası haberleşme processler arası haberleşmeden çok daha kolaydır. Bu nedenle birden fazla programın yaptığı iş yerine tasarım tek bir programın birden fazla threadinin yaptığı iş biçiminde ele alınmaktadır. (Multi processing yerine multi threading daha iyidir.)

18.2 Win32’nin Thread ÇizelgelemesiWin32 sistemleri döngüsel öncelikli çizelgeleme (Round Robin Priority Scheduling) denilen çizelgeleme algoritmasını kullanır. Win32 sistemlerinde 0 – 31 arası bir öncelik derecesi vardır. Win32 sistemlerinde her zaman en yüksek öncelikli eşit önceliğe sahip thread grubu kendi arasında döngüsel çizelgelemeye sokulur. En yüksek grubun tamamı bittiğinde ya da bloke olduğunda bir sonraki gruba geçilir. Örneğin bir sistemde 18 öncelikli 2 thread, 16 öncelikli 2 thread ve 8 öncelikli 2 thread bulunsun. Win32 önce 18 öncelikli 2 threadi kendi aralarında döngüsel çizelgelemeye sokar. Bunların her ikisi de bittiğinde ya da bloke olduğunda 16 önceliğe sahip 2 threadi kendi aralarında çizelgelemey sokar. Burada akla gelen iki klasik soru vardır.

1 - ) 31 öncelikli bir thread bütün threadlerin çalışmasını engeller mi?

2 - ) 0 öncelikli bir thread çalışabilir mi?

0 öncelikli thread seyrek olsa da bütün threadlerin bloke olup geçici süre çizelge dışı bırakılmaları sonucunda çalışma fırsatı bulabilmektedir. Tabi 31 öncelikli bir thread yaratıp bunun hiç bloke olmamasını sağlarsak diğer programlar çalışma fırsatı bulamaz. Bir threadin default öncelik derecesi 8’dir. (Örneğin DOS sessionları 8 öncelik ile çalıştırılır.)

Sistemin 0 öncelikli ve ismine idle process denilen bir threadi vardır. Yani hiçbir thread çalışmadığı zaman bu thread çalışabilmektedir. 0 öncelikli bu thread kullanılmayan bellek bölgelerini sıfırlamak, Windows Explorer için dizinleri dolaşıp bilgi toplamak gibi kritik önemde olmayan işlemleri yapmaktadır. Ancak Microsoft 0 öncelikli bu threade daha fazla işte yükleyebileceğini belirtmiştir. Bu nedenle 0 öncelikli threadin arada bir çalışması şimdilerde zorunlu olmasa da gelecekte zorunlu olabilecektir. Böylece biz 8 öncelikli normal bir thread yazsak bile o threadin arad bir bloke olmasını sağlamalıyız.

18.3 Worker Thread ve GUI Thread KavramlarıBir thread hiç pencere yaratmamışsa mesaj döngüsüne de gereksinimi yoktur. Yani düz bir fonksiyon gibi yazılır. Genellikle bu threadler hesaplama, arka plan işlemlerin kontrol edilmesi gibi işler için açılır. Bu tür threadlere worker thread denir.

Win32’de her threadin ayrı bir mesaj kuyruğu vardır. Yani bir thread bir pencere yarattığında bir mesaj konusu oluşmaktadır ve mesajların işlenmesi için bir mesaj döngüsü kurulmalıdır. En az bir pencere yaratmış olan threadlere GUI threadleri denir.

18.4 MFC’de Thread İşlemleriMFC’de thread işlemleri CWinThread sınıfı ile temsil edilmiştir. MFC’de thread yaratmak için AfxBeginThread global fonksiyonu kullanılır. Bu fonksiyonun iki versiyonu vardır. Birisi worker thread yaratmak için diğeri ise GUI thread yaratmak için kullanılır. Bu fonksiyon worker thread yaratırken thread fonksiyonunun adresini ve diğer parametreleri alır, kendi içinde CWinThread türünden bir nesneyi dinamik olarak yaratır. Daha sonra CreateThread API fonksiyonuyla threadi yaratarak threadin HANDLE değerini ve diğer önemli bilgilerini nesne içine yazar ve yarattığı nesnenin başlangıç adresi ile geri döner.

CWinThread* AfxBeginThread(...);

2002-03-05 Salı147

Page 148: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

18.5 Worker Thread YaratılmasıWorker thread yaratmak için AfxBeginThread fonksiyonunun şu prototipi kullanılır;

CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

Fonksiyonun birinci parametresi thread fonksiyonunun başlangıç adresini alır. AFX_THREADPROC şu prototipe sahip bir fonksiyon göstericisidir.

UINT ThreadProc(LPVOID pParam);

typedef UINT (*AFX_THREADPROC)(LPVOID);

(Standart C fonksiyonlarının çoğu multi-thread olamayacak biçimde yazılmıştır. Bir thread bir Standart C fonksiyonunu çağırmış olsun. Sonra o thread bitsin ve C fonksiyonu tam ortada diğer thread çalışmaya başlasın ve aynı C fonksiyonu çağırsın. Bu durumda Standart C fonksiyonu saçmalar. Onun için Standart C kütüphanesinin multi-thread versiyonu vardır. VC6.0 Projects – Settings – C/C++ - Category=Code generation ile hangi kütüphanenin kullanılacağı belirlenebilir. VC kendisi API programlamada multi-thread’e çeker.)

Görüldüğü gibi thread fonksiyonu __stdcall değil __cdecl çağırma biçimine sahiptir.

ANAHTAR NOTLAR : İki farklı thread Standart C fonksiyonlarını kullandığında bazı Standart C fonksiyonları probleme yol açmaktadır. Bu fonksiyonlar static datalar üzerinde çalışan strtok gibi fonksiyonlardır. Bu nedenle Windows altında Standart C fonksiyonları için iki ayrı kütüphane yazılmıştır: Single-thread ve Multi-thread versiyonlar. Ancak yalnızca multi-thread kütüphanenin seçilmesi problemi çözmemektedir. Bu multi-thread kütüphanenin kullanılabilmesi için thread’in TLS alanında düzenlemelerinin yapılması gerekmektedir. Bu nedenle trhread’i yaratırken CreateThread API fonksiyonu ile değil _beginthreadex yaratmak gerekir. Bu fonksiyon multi-thread C kütüphanesinde bulunur ve hazırlık işlemlerinden sonra CreateThread API fonksiyonunu çağırır. Zaten AfxBeginThread fonksiyonu da _beginthreadex fonksiyonunu çağırmaktadır.

AfxBeginThread fonksiyonunun ikinci parametresi thread fonksiyonuna geçirilecek olan adrestir. Genellikle programcı bir blok tahsis edip o bloğun adresini geçirir. Ya da bu parametreye sınıf

148

Page 149: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

nesnesinin adresinin başlangıç adresinin geçirilmesine de sık rastlanır. Fonksyonun nStackSize parametresi threadin kullanacağı Stack uzunluğunu belirtir. Bu parametreye 0 değeri girilirse ilgili process’in PE formatındaki default değer alınır. Bu değer 1MB’dir. Fonksiyonun dwFlags parametresi ya 0 olur ya da CREATE_SUSPENDED değeri olur. (0 ise hemen çalışmaya başlar. CREATE_SUSPENDED ise sonradan ResumeThread ile çalıştırılır.) Fonksiyonun son parametresi güvenlik parametresidir. NULL geçilebilir.

CWinThread Class MembersData Membersm_bAutoDelete Specifies whether to destroy the object at thread termination.m_hThread Handle to the current thread.m_nThreadID ID of the current thread.m_pMainWnd Holds a pointer to the application’s main window.m_pActiveWnd Pointer to the main window of the container application when an OLE server is in-place active.ConstructionCWinThread Constructs a CWinThread object.CreateThread Starts execution of a CWinThread object.OperationsGetMainWnd Retrieves a pointer to the main window for the thread.GetThreadPriority Gets the priority of the current thread.PostThreadMessage Posts a message to another CWinThread object.ResumeThread Decrements a thread’s suspend count.SetThreadPriority Sets the priority of the current thread.SuspendThread Increments a thread’s suspend count.OverridablesExitInstance Override to clean up when your thread terminates.InitInstance Override to perform thread instance initialization.OnIdle Override to perform thread-specific idle-time processing.PreTranslateMessage Filters messages before they are dispatched to the Windows functions TranslateMessage and

DispatchMessage.IsIdleMessage Checks for special messages.ProcessWndProcException Intercepts all unhandled exceptions thrown by the thread’s message and command handlers.ProcessMessageFilter Intercepts certain messages before they reach the application.Run Controlling function for threads with a message pump. Override to customize the default message

loop.

Thread fonksiyonu global ya da sınıfın static fonksiyonu olabilir normal üye fonksiyonu olamaz. Bu durumda bir threadi bir sınıfa özgü imiş gibi göstermek için şöyle bir yol izlenir: Thread fonksiyonu sınıfın static üye fonksiyonu yapılır ve sınıf nesnesinin başlangıç adresi thread parametresi olarak geçirilir.

class Sample {public:

static UINT ThreadProc(LPVOID);private:

CWinThread* m_pThread;};

Sample::Sample() {

//...m_pThread = AfxBeginThread(ThreadProc, this); //Sınıf nesnesi adresi

}

UINT Sample::ThreadProc(LPVOID pParam){

Sample* pSample = (Sample*) pParam;// ...

}

new Sample;

AfxBeginThread fonksiyonunun geri dönüş değeri yaratılan threadi kontrol etmekte kullanılan CWinThread nesnesinin adresidir. Şüphesiz AfxBeginThread fonksiyonu kendi içinde CWinThread alanını dinamik olarak tahsis eder ve threadin API düzetindeki HANDLE değerini sınıfın veri eşemanı olarak yazar. CWinTHread sınıfının üye fonksiyonları thread API’lerini çağıran fonksiyonlardır. Bu fonksiyonlar gereken HANDLE değerini sınıfın veri elemanından alırlar.

149

Page 150: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

18.6 Worker Thread’ler Neden Kullanılırlar?Worker threadler arka planda pencereye gereksinim duymayan çeşitli kontrol işlemlerini yapmak için kullanılabilirler. Worker thread’lerin en fazla kullanıldığı durumlar hem mesaj döngüsünün işletilmek istendiği hem de döngü içinde belirli bir amaç için tarama yapıldığı durumlardır.

18.7 Çalışmakta Olan Bir Thread Nasıl Durdurulmalıdır?Bir thread başka bir thread tarafından TerminateThread API fonksiyonu ile sonlandırılabilir. Bu tavsiye edilen bir durum değildir ve son çare olarak uygulanmalıdır. Çünkü thread o anda kritik bir takım işlemleri yapıyor olabilir ve birden kesilmesi probleme yol açabilir.

Diğer bir yöntem AfxEndThread fonksiyonunu kullanmaktır. Bu fonksiyon ExitThread API fonksiyonunu çağırır. ExitThread ise yalnızca kendi threadini sonlandırabilir.

Bir threadi sonlandırmanın en iyi yöntemi thread içinde bir flag değişkenine bakarak bir döngü kurmak ve flag değişkeninin dışarıdan set ederek threadin kendi kendisini sonlandırmasını sağlamaktır.

SINIF ÇALIŞMASI :

Dialog tabalı, aşağıda belirlildiği gibi işlev gören bir uygulama yazınız.

Dialog penceresinin OK, Cancel ve Exit tuşları olmalıdır. OK tuşuna basıldığında bir static kontrol üzerinde bir sayaç çalıştırılmalı, Cancel tuşuna basıldığında sayaç durdurulmalı, tekrar OK tuşuna basıldığında sayaç kaldığı yerden çalışmaya devam etmeli, Exit tuşuna basıldığında uygulama sonlandırılmalıdır. Bu dialog tabanlı uygulamada sayaç ile saydırma işlemi worker thread’e yaptırılmalıdır.

OK tuşuna basıldığında bir worker thred açılmalıdır. Worker thread fonksiyonu dialog sınıfının static bir üye fonksiyonu olmalıdır. Thread fonksiyonuna parametre olarak dialog sınıf nesnesinin adresi geçirilmelidir. Döngünün devamını sağlayan flag değişkeni dialog sınıfının veri elemanı olabilir. Sayaç değeri de dialog sınıfında saklanmalıdır. Cancel tuşuna basıldığında flag set edilmeli ve thread fonksiyonu sonlandırılmalıdır.

18.8 Thread Nesnesinin YokedilmesiAfxBeginThread fonksiyonunun geri verdiği CWinThread adresi fonksiyon tarafından tahsis edilmiştir. Nasıl ve nerede free hale getirilecektir?

İşte otomatik ya da manual free hale getirme mekanizması sağlanmıştır. CWinThread sınıfının public m_bAutoDelete isimli bir veri elemanı vardır. Bu veri elemanı default TRUE değerindedir. Bunun anlamı thread fonksiyonu bittiğinde ya da AfxEndThread uygulandığında tahsis edilen alanın otomatik silineceğidir. Bu eleman thread yaratıldıktan sonra programcı tarafından FALSE değerine çekilirse thread sonlandığında nesne otomatik olarak silinmez.

Bir sınıf kendi kendini silebilir. Sınıfın delete this işlemi yapan bir fonksiyonu olabilir. Ya da destructor dışarıdan çağırılarak yokedilebilir. Bu işlem için tabiki sınıf nesnesinin new ile tanımlanmış olması gerekir.

Herhangi bir sınıf nesnesi için delete pClass yapılmışsa önce destructor çağırılır sonra sınıf nesnesi silinir.

Sleep MFC’de bir üye fonksiyon olarak tekrar yazılmamıştır. API olarak mevcuttur.

void Sleep(DWORD dwMilliseconds)

Bu fonksiyon parametresi ile belirtilen milisaniye kadar threadi çizelge dışı bırakır. Sistemin o anki durumuna göre arzu edilenden çeşitli sapmalar oluşabilir. Özel olarak 0 parametresi geçilirse o andaki quanta kesilir ve çalışma döngüsel öncelikli çizelgelemeye göre sıradaki threade verilir. INFINITE özel değeri threadi tamamen çizelge dışı bırakır. Böyle threadler ancak dışarıdan ResumeThread fonksiyonu uygulayarak çalışmaya devam ettirilirler. Threadin bir

150

Page 151: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

döngüde meşgul bir biçimde dönmesi yerine her döngüde Sleep(0) işle bekletilmesi daha iyi bir tasarımdır.

// thread.cppBOOL CThreadApp::InitInstance(){

AfxEnableControlContainer();………………………….CThreadDlg dlg;m_pMainWnd = &dlg;int nResponse = dlg.DoModal();if (nResponse == IDOK){

// TODO: Place code here to handle when the dialog is// dismissed with OK

}else if (nResponse == IDCANCEL){

// TODO: Place code here to handle when the dialog is// dismissed with Cancel

}

// Since the dialog has been closed, return FALSE so that we exit the// application, rather than start the application's message pump.return FALSE;

}

// threadDlg.cpp : implementation file#include "stdafx.h"#include "thread.h"#include "threadDlg.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[ ] = __FILE__;#endif// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog{public:

CAboutDlg();

// Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };//}}AFX_DATA

// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support//}}AFX_VIRTUAL

// Implementationprotected:

//{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()

};

151

Page 152: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD){

//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT

}

void CAboutDlg::DoDataExchange(CDataExchange* pDX){

CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)//{{AFX_MSG_MAP(CAboutDlg)

// No message handlers//}}AFX_MSG_MAP

END_MESSAGE_MAP()// CThreadDlg dialog

CThreadDlg::CThreadDlg(CWnd* pParent /*=NULL*/): CDialog(CThreadDlg::IDD, pParent)

{//{{AFX_DATA_INIT(CThreadDlg)//}}AFX_DATA_INIT

// Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);flag = 1;m_nCounter = 0;

}

void CThreadDlg::DoDataExchange(CDataExchange* pDX){

CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CThreadDlg)DDX_Control(pDX, IDC_STATIC_THREAD, m_static);//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CThreadDlg, CDialog)//{{AFX_MSG_MAP(CThreadDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON1, OnButton1)//}}AFX_MSG_MAP

END_MESSAGE_MAP()// CThreadDlg message handlers

BOOL CThreadDlg::OnInitDialog(){

CDialog::OnInitDialog();

// Add "About..." menu item to system menu.// IDM_ABOUTBOX must be in the system command range.ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){

CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()){

pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

}}

152

Page 153: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

// Set the icon for this dialog. The framework does this automatically// when the application's main window is not a dialogSetIcon(m_hIcon, TRUE); // Set big iconSetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here

return TRUE; // return TRUE unless you set the focus to a control}

void CThreadDlg::OnSysCommand(UINT nID, LPARAM lParam){

if ((nID & 0xFFF0) == IDM_ABOUTBOX){

CAboutDlg dlgAbout;dlgAbout.DoModal();

}else{

CDialog::OnSysCommand(nID, lParam);}

}

// If you add a minimize button to your dialog, you will need the code below// to draw the icon. For MFC applications using the document/view model,// this is automatically done for you by the framework.

void CThreadDlg::OnPaint() {

if (IsIconic()){

CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icondc.DrawIcon(x, y, m_hIcon);

}else{

CDialog::OnPaint();}

}

// The system calls this to obtain the cursor to display while the user drags// the minimized window.HCURSOR CThreadDlg::OnQueryDragIcon(){

return (HCURSOR) m_hIcon;}

void CThreadDlg::OnOK() {

CWinThread *pWinThread= AfxBeginThread(ThreadFunc, this);flag = 1;

}

UINT CThreadDlg::ThreadFunc(LPVOID pParam){

CThreadDlg *ptr = (CThreadDlg*)pParam;CString str;

153

Page 154: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

for(; ptr->flag == 1;) {str.Format("%d", ptr->m_nCounter);ptr->m_static.SetWindowText(str);::Sleep(300);++ptr->m_nCounter;

}if(ptr->flag == 0)

AfxEndThread(1, TRUE);return 0;

}

void CThreadDlg::OnCancel() {

flag = 0;}

void CThreadDlg::OnButton1() {

// TODO: Add your control notification handler code hereEndDialog(0);

}

2002-03-07 Perşembe

18.9 GUI ThreadleriWin32’de her threadin ayrı bir mesaj kuyruğu vardır. Dolayısıyla CreateWindow fonksiyonuyla bir pencere yaratmışsa mesajları işlemek için bir mesaj döngüsü oluşturmak gerekir. Bilindiği gibi mesaj döngüsü MFC’de CWinThread sınıfının Run üye fonksiyonu ile sağlanmaktadır. MFC’de GUI threadlerinin de bir ana penceresi olduğu için programın ana pnceresinin yaratılması ile benzer işlemler yapılmaktadır. GUI thread yaratmak için AfxBeginThread fonksiyonunun ikinci versiyonu kullanılır. GUI thread aşağıdaki adımlarla yaratılır

1 – CWinThread sınıfından bir sınıf türetilir ve InitInstance sanal fonksiyonu tıpkı program penceresinde olduğu gibi GUI threadin ana penceresini yaratacak biçimde yazılır. GUI threadin penceresi genellikle CFrameWnd sınıfından türetilen bir pencere olur. Bu nedenle GUI threadin ana penceresi için CFrameWnd sınıfından da bir sınıf türetmek gerekir.

2 – CWinThread’den türettiğimiz sınıf AfxBeginThread fonksiyonu tarafından dinamik yaratılacağı için DECLARE_DYNCREATE ve IMPLEMENT_DYNCREATE makrolarını içermelidir. (Class Wizard zaten New Class işlemi yapıldığında taban sınıf olarak CWinThread verildiğinde bunu otomatik bir biçimde yapmaktadır.)

3 – AfxBeginThread fonksiyonu belirlenen parametrelerle çağırılır.

18.10AfxBeginThread Fonksiyonu GUI Thread Yaratmak İçin Ne Yapar?Fonksiyonun prototipi aşağıdaki gibidir.

CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

Fonksiyonun ilk parametresi makroların yerleştirdiği CRuntimeClass türünden static nesnenin adresini alır. Bu parametre RUNTIME_CLASS makrosu ile oluşturulabilir. Örne;

RUNTIME_CLASS(CMyThread)

Fonksiyonun diğer parametreleri ilk versiyonuyla aynı biçimdedir.

AfxBeginThread birinci parametresi ile belirtilen sınıf dinamik olarak yaratır. Elde ettiği adresle InitInstance sanal fonksiyonunu çağırır. Daha sonra da CWinThreadRun fonksiyonunu çağırarak mesaj döngüsüne girer. Tabii AfxBeginThread başarıyla geri döner. Aslında yeni

154

Page 155: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

yaratılan threadde akış InitInstance fonksiyonunun çağırıldığı yer olarak belirlenmiştir. Yani AfxBeginThread fonksiyonu geri dönerken yaratılan thread InitInstance’dan hareketle açıklanan işlemleri yapmaktadır. GUI thread için InitInstance tamamen programın ana penceresini yaratmakta kullandığımız biçim gibi yaratılır.

BOOL CMyThread::InitInstance(){

m_pMainWnd = new CMyThreadWnd();m_pMainWnd->ShowWindow(SW_SHOW);m_pMainWnd->UpdateWindow();return TRUE;}

AfxBeginThread fonksiyonunun geri dönüş değeri fonksiyonun dinamik yarattığı nesnenin adresidir.

18.11GUI Threadler Nasıl Sonlandırılır?GUI threadleri sonlandırmak kullanıcı tarafından doğal yolla yapılabilir. Yani kullanıcı GUI threadin ana penceresini kapatırsa GUI thread mesj döngüsünden çıkacak ve framework tarfından bu aşamada ExitThread uygulanacaktır. Yani GUI threadin sonlandırılması için yine mesaj döngüsünden çıkılması gerekir. Bunun için GUI threadin ana penceresine DestroyWindow uygulanabilir ya da GUI threadin mesaj döngüsünden çıkmak için PostQuitMessage uygulanabilir.

Programın ana penceresinin kapatılması processin bitirilmesine yol açtığı için processin ana penceresini kapattığımızda GUI thread pencereleri de kapanarak program sonlanacaktır. Bu nedenle uygulama penceresinin kpatılması sırasında programcı GUI thread penceresi açık ise önce onu güvenli bir biçimde kapatmak isteyebilir.

Şüphesiz GUI thread penceresi Dialog tabanlı bir pencere de olabilir. Ya da CWnd sınıfından türetilmiş basit bir pencere olabilir.

18.12GUI Thread Penceresi İle İlgili Diğer AçıklamalarGUI thread penceresi ana pencere ile aynı kaynakları kullanabilir. Örneğin yeni bir menü kaynağı tanımlanıp GUI thread penceresinin de menüsünün olması sağlanabilir. Aslında API düzeyinde programın ana penceresi ile GUI thread penceresi arasında bir fark yoktur. Ancak programın ana penceresi WinMain içinde yaratıldığından WinMain bittiğinde process sonlanacağından bitirici bir etkiye sahiptir.

SINIF ÇALIŞMASI :

Aşağıdaki GUI thread uygulamasını yazınız.

1 – Programın ana penceresinin File menüsünde Thread menü elemanı olmalıdır.

2 – File menüsünden thread seçeneği her seçildiğinde yeni bir GUI thread penceresi açılacaktır.

3 – Her açılan thread penceresinin başlık kısmında sırasıyla thread1, thread2... şeklinde yazılar yazacaktır.

4 – Her thread yaratıldığında thread penceresinin WM_CREATE mesajı içinde 1sn.’lik bir timer ve rastgele bir renkten oluşan fırça yaratınız.

5 – Her threadde bu timer mesajında client area boyutları alınacak ve o boyutlar içinde rastgele yerlere önceden belirlenmiş fırça kullanılarak rastgele yarıçaplarda daireler çiziniz.

6 – WM_PAINT mesajı için şekiller yeniden çizilmediğinden ekran görüntüsü silinecektir.

Açıklama;

Wizard kullanılarak uygulama oluşturulur ve menü elemanı yerleştirilir.

155

Page 156: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Class Wizard kullanılarak CWinThread sınıfından bir sınıf türetilir.

CFrameWnd sınıfından bir sınıf türetilir.

Pencere sınıfının WM_CREATE mesajı içinde rastgele renkte fırça ve timer yaratılır.

Pencerenin WM_TIMER mesajı içinde GetDC ile DC alınır, daire çizilir, DeleteDC ile bırakılır.

Menüden thread seçildiğinde AfxBeginThread fonksiyonu çağırılarak thread oluşturulur.

Her yeni thread penceresinde farklı renk çıkartabilmek için başka bir şeye gerek yoktur.

Gerekli başlık dosyalarının gerekli dosyalardan include edilmesine dikkat etmek gereklidir.

Proje threadgui içinde mevcuttur.

// CircleWnd.cpp : implementation file#include "stdafx.h"#include "threadgui.h"#include "CircleWnd.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[ ] = __FILE__;#endifint count = 0;// CCircleWnd

IMPLEMENT_DYNCREATE(CCircleWnd, CFrameWnd)

CCircleWnd::CCircleWnd(){

CString str;

str.Format("Thread%d", g_count);Create(NULL, str, WS_OVERLAPPEDWINDOW,

CRect(CPoint(100+200+(141*count), 300), CSize(140, 150)) );count++;

}

CCircleWnd::~CCircleWnd(){}

BEGIN_MESSAGE_MAP(CCircleWnd, CFrameWnd)//{{AFX_MSG_MAP(CCircleWnd)ON_WM_CREATE()ON_WM_TIMER()//}}AFX_MSG_MAP

END_MESSAGE_MAP()

///////////////////////////////////////////////////////// CCircleWnd message handlers

int CCircleWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

156

Page 157: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

return -1;

SetTimer(g_count, 1000, NULL);srand(time(NULL));m_brush.CreateSolidBrush(RGB(

rand() % 256, rand() % 256, rand() % 256));return 0;

}

void CCircleWnd::OnTimer(UINT nIDEvent) {

CDC *pDC = GetDC();

int width = rand() % 50;CRect rect;GetClientRect(&rect);pDC->SelectObject(m_brush);pDC->Ellipse(CRect(

CPoint(rand() % rect.Width(), rand() % rect.Height()),CSize(width, width)));

pDC->DeleteDC();

CFrameWnd::OnTimer(nIDEvent);}// CircleThread.cpp : implementation file#include "stdafx.h"#include "threadgui.h"#include "CircleThread.h"#include "circlewnd.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////// CCircleThread

IMPLEMENT_DYNCREATE(CCircleThread, CWinThread)

CCircleThread::CCircleThread(){}

CCircleThread::~CCircleThread(){}

BOOL CCircleThread::InitInstance(){

m_pMainWnd = new CCircleWnd();m_pMainWnd->ShowWindow(SW_SHOW);m_pMainWnd->UpdateWindow();

return TRUE;}

int CCircleThread::ExitInstance(){

// TODO: perform any per-thread cleanup herereturn CWinThread::ExitInstance();

}

BEGIN_MESSAGE_MAP(CCircleThread, CWinThread)//{{AFX_MSG_MAP(CCircleThread)// NOTE - the ClassWizard will add and remove mapping macros here.//}}AFX_MSG_MAP

END_MESSAGE_MAP()

157

Page 158: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Pencere başlık yazılarını, her yeni pencere açılışda sayıyı artıran değişken için, global değişken tanımlama yöntemi

threadgui.cpp içine aşağıdaki kodu yaz.int g_count;threadgui.h içine aşağıdaki kodu yazextern int g_count;

2002-03-12 Salı

18.13CWinThread Sınıfının Önemli Public Veri Elemanları ve Üye Fonksiyonları:AfxBeginThread fonksiyonunun geri verdiği CWinThread nesne adresi kullanılarak çalışmakta olan thread üzerinde faydalı işlemler yapabilir. (Bu dinamik tahsis edilmiş nesne default olarak otomatik bir biçimde silinmektedir ancak sınıfın m_bAutoDelete elemanı 0 yapılırsa manuel olarak silmek gerekir. Kernel, thread nesnesi için CloseHandle CWinThread sınıfının bitiş fonksiyonunda çağrılmaktadır.)

CWinThread Class MembersData Membersm_bAutoDelete Specifies whether to destroy the object at thread termination.m_hThread Handle to the current thread.m_nThreadID ID of the current thread.m_pMainWnd Holds a pointer to the application’s main window.m_pActiveWnd Pointer to the main window of the container application when an OLE server is in-place active.ConstructionCWinThread Constructs a CWinThread object.CreateThread Starts execution of a CWinThread object.OperationsGetMainWnd Retrieves a pointer to the main window for the thread.GetThreadPriority Gets the priority of the current thread.PostThreadMessage Posts a message to another CWinThread object.ResumeThread Decrements a thread’s suspend count.SetThreadPriority Sets the priority of the current thread.SuspendThread Increments a thread’s suspend count.OverridablesExitInstance Override to clean up when your thread terminates.InitInstance Override to perform thread instance initialization.OnIdle Override to perform thread-specific idle-time processing.PreTranslateMessage Filters messages before they are dispatched to the Windows functions TranslateMessage and

DispatchMessage.IsIdleMessage Checks for special messages.ProcessWndProcException Intercepts all unhandled exceptions thrown by the thread’s message and command handlers.ProcessMessageFilter Intercepts certain messages before they reach the application.Run Controlling function for threads with a message pump. Override to customize the default message

loop.

18.14CWinThread Sınıfının Önemli Public Veri Elemanları Şunlardır:m_b AutoDelete Otomatik silme flag’i.

m_hThread API thread handle değeri.

m_hThreadID API thread ID

m_pMainWnd Thread’in ana penceresini gösteren gösterici.

18.15Sınıfın Önemli Üye Fonksiyonları Şunlardır:GetMainWnd() Thread’in m_pMainWnd elemanına geri döner.

PostThreadMessage() Thread mesajında kuyruğa pencere belirtmeksizin mesaj bırakmakta kullanılır. (thread’in handle’ını biliyoruz ama ana penceresinin handle’ını bilmiyoruz.)

ResumeThread() Bloke olmuş thread’i yeniden çalıştırmak için kullanılır.

158

Page 159: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

18.16CWinThread Sınıfının Önemli Sanal Fonksiyonları:InitInstance sanal fonksiyonu programın akışı mesaj döngüsüne girmeden ana

pencerenin yaratılması için yazılmalıdır.

ExitInstance, GUI threadlerinde thread’in akışı mesaj döngüsünden çıktığında thread fonksiyonu bitmeden çağrılır.

virtual int CWinThread::ExitInstance(void);

Bu fonksiyon ana program için de sanallık mekanizması altında yazılabilir. İşlevsel olarak InitInstance fonksiyonunun zıt anlamlısıdır. Programın ya da thread’in bitiş işlemleri burada yapılabilir. Aslında thread’in ya da programın son işlemleri ana pencerenin kapatılması sırasında da yapılabilir. Ancak mantıksal açıdan programın ana penceresinin yaratılmadan önce yapılan bir takım işlemlerin bu fonksiyonla geri alması daha uygundur. Uygulamada ExitInstance fonksiyonu seyrek kullanılmaktadır. PreTranslateMessage sanal fonksiyonu mesaji thread’in mesaj kuyruğundan alınıp henüz TranslateMessage ve DispatchMessage API fonksiyonlarına verilmeden önce çağrılmaktadır. Bu fonksiyon mesaj döngüsü içerisinde framework tarafından çağrılmaktadır.

virtual BOOL CWinThread::PreTranslateMessage(MSG *pMsg);

Bu fonksiyon programcı tarafından çeşitli mesajları birinci elden değiştirmek ya da iptal etmek gibi gerekçelerle kullanılmaktadır. Programcı fonksiyondan TRUE ile geri dönerse mesaj dispatch edilir. FALSE ile geri dönerse mesaj dispatch edilmez.

OnIdle fonksiyonu mesaj kuyruğunda mesaj yoksa çağrılır programcı arka plan bazı işlemleri bu fonksiyon bırakabilir ancak kullanımı problemli olabileceğinden fazla tercih edilmemelidir. Programcının, bu fonksiyonu yeniden yazıyorsa CWinThread sınıfının OnIdle fonksiyonunu bilinçli ve şuurlu olarak çağırması gerekir. Zira CWinThread::OnIdle UpdateCommand mesajları ve geçici handle tablolarının silinmesi gibi önemli işlevlere sahiptir. Mesaj döngüsünü oluşturan Run üye fonksiyonu da sanal bir fonksiyondur. Özgün mesaj döngülerinin oluşturulmasında kullanılabilir.

159

Page 160: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

19 MDI İŞLEMLERİ (MULTIPLE DOCUMENT INTERFACE) İŞLEMLERİ:MDI Windows 3.1 ile API düzeyinde sisteme dahil edilmiştir. MDI tamamen aynı işlevlere sahip yani aynı pencere fonksiyonuna sahip alt pencerelerin oluşturulması ile ilgili bir konudur.

CMDIFrameWnd Class MembersConstruction CMDIFrameWnd Constructs a CMDIFrameWnd.Operations MDIActivate Activates a different MDI child window.MDIGetActive Retrieves the currently active MDI child window, along with a flag indicating whether or not the

child is maximized.MDIIconArrange Arranges all minimized document child windows.MDIMaximize Maximizes an MDI child window.MDINext Activates the child window immediately behind the currently active child window and places the

currently active child window behind all other child windows.MDIRestore Restores an MDI child window from maximized or minimized size.MDISetMenu Replaces the menu of an MDI frame window, the Window pop-up menu, or both.MDITile Arranges all child windows in a tiled format.MDICascade Arranges all child windows in a cascaded format.OverridablesCreateClient Creates a Windows MDICLIENT window for this CMDIFrameWnd. Called by the OnCreate

member function of CWnd.GetWindowMenuPopup Returns the Window pop-up menu.

19.1 API Düzeyinde MDI İşlemleri:API düzeyinde MDI sisteminde 3 terim kullanılmaktadır;

Frame window: Programın ana penceresini temsil eder.

Client window: Doküman pencereleri ile frame penceresi arasında arabirim oluşturan penceredir. Bu pencere yaratıldığında frame penceresinin çalışma alanını kaplar.

Document window: client pencerenin alt penceresi olarak yaratılan işlemlerin yaratıldığı pencerelerdir.

Client penceresi frame penceresi tarafından CreateWindow fonksiyonu ile sınıf ismi olarak “MDICLIENT” kullanılarak yaratılır. “MDICLIENT” sınıfı windows’un önceden tanımlanmış bir sınıfıdır. Yani pencere fonksiyonu USER32.DLL modülündedir. Bu sınıfın pencere fonksiyonu arabirim işlemlerini yapmaktadır. Doküman pencereleri programcının belirlediği bir sınıf kullanılarak client pencereye mesaj gönderme yolu ile yaratılır. Yani programcı client pencereyi yaratır onun handle’ını elde eder sonra client pencereye uygun mesajı göndererek client penceresinin doküman penceresini yaratmasını sağlar. Doküman pencereleri client penceresinin alt pencereleri biçimindedir. Doküman pencerelerinin pencere fonksiyonu programcı tarafından yazılır. Aslında programcı doküman pencereleri için bir WNDCLASS sınıfı register ettirir. Client penceresine bu sınıf ismini vererek doküman penceresi yaratmasını ister. Sonuç olarak frame penceresinin ve doküman penceresinin pencere fonksiyonları programcı tarafından yazılır. Normal olarak doküman pencereleri aynı sınıftan yaratılır böylece tüm doküman pencerelerinin pencere fonksiyonu aynı olur hepsi aynı işlemleri yapar.

API düzeyinde doküman pencerelerinin hepsinin pencere fonksiyonu aynı olduğunda her doküman penceresinin ayrı bir data grubunu kullanması nasıl sağlanır? En pratik yöntem pencere fonksiyonunun bir data bloğunun adresi ile işlem yapacak biçimde tasarlanmasıdır. Her doküman penceresi yaratıldığında farklı bir blok yaratılıp fonksiyonun farklı bir bloğu kullanması sağlanabilir. Bunun için pencere handle değerinden hareketle blok adresi tespit edilebilir. Ya da CreateWindow fonksiyonunun son parametresi olan extra data alanları kullanılabilir. (Pencere fonksiyonu içerisinde GetWindowLong ile istenildiği zaman bu değer alınabilir.)

19.2 MFC’de MDI İşlemleri:MFC’de MDI terminolojisi daha değişiktir. MFC API düzeyindeki MDI fonksiyonları kullanılarak yazılmıştır. MFC’de MDI işlemleri manuel olarak yapılabilir. Ancak MDI wizard ile işlemler belirli

160

Page 161: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

bir noktaya wizard’a yaptırılabilmektedir. MFC MDI işlemlerinde 4 pencere söz konusudur. Bu pencerelerin her biri bir sınıf ile temsil edilmiştir.

CMyMDIFrameWnd (bizim türettiğimiz sınıf)

Frame Penceresi: Programın ana penceresidir. MFC’de MDI uygulamaları için ana pencere CFrameWnd sınıfından türetilen sınıf ile değil CMDIFrameWnd sınıfından türetilen sınıf ile yaratılır. CMDIFrameWnd sınıfı da zaten CFrameWnd sınıfından türetilmiştir.

MDI uygulamalarında farklı bir sınıfın kullanılmasının nedeni API düzeyinde de MDI işlemleri için farklı bir yapının kullanılmasıdır. Örneğin API düzeyinde frame penceresine ilişkin pencere fonksiyonunda işlenmeyen mesajlar DefWindowProc tarafından değil DefFrameProc tarafından işletilir. Bunun dışında WM_SIZE gibi kimi mesajlar frame penceresinde işlense bile yine DefFrameProc çağrılmalıdır.

2002-03-14 Perşembe

1- Client Window: Client penceresi MDI uygulamalarında programın ana penceresi yani CMDIFrameWnd sınıfından türetilen sınıfa ilişkin pencere yaratılırken otomatik olarak yaratılmaktadır. MFC uygulamarında normal olarak client pencerenin handle değerini alabilecek doğrudan bir yöntem yoktur. Ancak programcı çeşitli API teknikleri ile client pencerenin handle değerini alabilir. API düzeyinde MDI işlemleri için client pencereye WM_MDIXXX mesajları gönderilir. Ancak MFC’de client pencerenin handle değeri saklanmıştır programcı CMDIFrameWnd sınıfının üye fonksiyonlarını çağırarak işlemlerini yapar. Şüphesiz bu sınıfın üye fonksiyonları ilgili mesajları yollayarak işlemleri yapmaktadır.

2- Document Child Window: Bu pencereler API düzeyindeki doküman pencereleridir. (document sözcüğü MFC’de başka bir anlamda da kullanıldığından bu pencerelere “document window” değil “document child window” demek daha doğrudur.) “document child” pencereler CMDIChildWnd sınıf ile temsil edilir. Bu sınıfta CFrameWnd sınıfından türetilmiştir. Programcı CMDIChildWnd sınıfından bir sınıf türetmeli

CWnd

CFrameWnd

CMDIFrameWnd CMDIChildWnd

CMyMDIFrameWnd CMyMDIChildWnd

Türetilen sınıf DECLARE_DYNCREATE ve IMPLEMENT_DYNCREATE makrolarını içermek zorundadır. Çünkü yeni bir doküman child penceresi yaratabilmek için framework bu türettiğimiz sınıf türünden bir nesneyi dinamik yaratır ve işlemleri yapar. Her document child pencere yaratıldığında ayrı bir dinamik nesne yaratılmaktadır. Böylece programcı türetilen sınıfta çeşitli veri elemanları kullandığında aslında her document child pencere için bu veri elemanların farklı bir kopyasını kullanıyor gibi işlem yapar. Özetle çalışma şu biçimdedir:

Programcı document child penceresi için CMDIChildWnd sınıfından bir sınıf türetir.

Türettiği sınıf için fonksiyonları yazar ve çeşitli veri elemanları tanımlar.

161

Page 162: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Document child pencereler için tek bir sınıf vardır ve fonksiyonlar ortaktır. Ancak bu fonksiyonların kullandığı sınıfın veri elemanları sınıfın farklı kopyalarına ilişkindir.

3- View Window: Bu pencere API düzeyinde yoktur MFC wizard tarafından işlemleri kolaylaştırmak amacı ile düşünülmüştür. MFC her bir document child pencere için onun çalışma alanını kaplayan bir “view” penceresi oluşturur. Bu view penceresi CWnd sınıfından türetilmiş normal bir penceredir. Programcı document child pencereler üzerindeki işlemlerde view penceresini kullanmak zorundadır. Programcı bu view modelini oluşturabilmek için document child pencerenin WM_CREATE mesajında view penceresini yaratmalıdır. View penceresine ilişkin nesne document child penceresine ilişkin sınıfın public veri elemanı olarak tutulmalıdır. Böylelikle her document child pencerenin view nesneleri de birbirinden farklı olacaktır. (Çünkü view nesnesi document child pencere sınıfının veri elemanıdır.)

Bu durumda document özelliği olmayan bir MFC uygulamasında dört sınıf kullanılır.

1 – CWinApp sınıfından türetilmiş uygulamayı temsil eden sınıf

2 – CMDIFrameWnd sınıfından türetilmiş ana pencereyi temsil eden sınıf

3 – CMDIChildWnd sınıfından türetilmiş document child pencereleri temsil eden sınıf

4 – CWnd sınıfından türetilmiş View pencerelerini temsil eden sınıf

View pencerelerine ilişkin nesneler document child pencere sınıfının elemanısdır. Document child pencere sınıfı ise RUNTIME_CLASS makrosu ile dinamik yaratılmaktadır.

19.3 MDI İşlemlerinin Wizard ve Manual Yolla GerçekleştirilmesiMaalesef tasarıma bakıldığında MDI işlemlerinin manual değilde wizard yoluyla oluşturulmasına yönelik bir yapı vardır. Yeni bir document child pencerenin yaratılması için CMDIChildWnd sınıfından türettiğimiz sınıf ismi ile RUNTIME_CLASS makrosu kullanılarak dokümante edilmemiş CMDIFrameWnd sınıfının CreateNewChild fonksiyonu kullanılmaktadır. Bu fonksiyon Visual C++ 7.0 (.NET) sistemine kadar dokümante edilmemiş bir fonksiyondu. Ancak wizard tarafından kullanılmaktadır. Bu fonksiyonun dokümante edilmemiş olması MDI işlemlerinin manual yapılmasının pek de istenmemesindendir. MFC wizard kullanıldığında oluşturulan standart menüden New seçildiğinde çağırılan fonksiyon incelendiğinde document child pencerelerin bu fonksiyon ile yaratıldığı görülmektedir. Bu tasarım mantığına göre yeni bir document child penceresinin yaratılması için menüden manual seçme yapmak gerekir. Ancak Visual C++ 7.0 versiyonunda bu fonksiyon dökümante edildiğinden işlemler programlama yoluyla da yapılabilir.

19.4 MDI Programlarının Genel ÖzellikleriAPI düzeyinde bir MDI uygulamasında Client penceresi otomatik olarak şu işlemleri yapar;

1 – Ctrl + F6 ya da fare click işlemi ile sonraki doküman penceresi aktif hale getirilebilir.

2 – Doküman penceresi maximise yapıldığında doküman pencere başlığı ana pencere başlığına eklenir.

3 – Doküman pencereleri başlık kısmı olan bir alt pencere biçiminde yaratılır. Minimise edildiğinde aşağıda toplanırlar.

4 – Client penceresine mesajlar gönderilerek (MFC’de CMDIFrameWnd sınıfının üye fonksiyonları çağırılarak) Tile ve Cascade işlemleri yapılabilir.

5 – Tüm doküman pencerelerini dolaşan bir fonksiyon yoktur. Bu işlem EnumChildWindows API fonksiyonuyla yapılabilir.

19.5 MFC’de Document Özelliği Olmayan Wizard KullanımıBunun için MFC AppWizard seçilir. Document/View architecture support özelliği kaldırılır ve Multiple Document seçilir. Bu işlemden sonra framework yukarıda açıklanan özellikleri sağlayan sınıfları oluşturarak kodu hazırlar. Wizardın ürettiği kodlar için şu açıklamalar yapılabilir;

162

Page 163: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Wizard yukarıda açıklanan sınıf türetmelerini yapmıştır. İki ayrı menü kaynağı oluştrumuştur. Menülerden biri hiçbir doküman penceresi yaratılmamışken görüntülenir. İkincisi herhangi bir doküman penceresi aktifken görüntülenir.

Wizard View pencere nesnesini document child pencere sınıfının public veri elemanı yapmıştır. Document child pencerenin WM_CREATE mesajında (OnCreate fonksiyonu) view penceresi yaratılmıştır.

Menüden File – New seçildiğinde doküman penceresi yaratılmaktadır. Bu menü seçimi uygulama sınıfında işlenmiştir. (Frame penceresinde işlenmesi daha normal bir durumdur. Bu konu dah ileride ele alınacaktır.)

19-03-2002 Salı

19.6 CMDIFrameWnd SınıfıBu sınıf MDI uygulamalarında ana pencereyi temsil eder. Client pencereyi yarattığı için Client pencereye mesaj gönderilerek yapılan işlemler bu sınıf tarafından yapılır. Sınıfın CreateNewChild fonksiyonu yeni bir doküman penceresi yaratmak için kullanılır. Bu fonksiyon Visual C++ 7.0’a kadar undocumented idi.

CMDIChildWnd* CMDIFrameWnd::CreateNewChild(CRuntimeClass *pClass, UINT nRemove, HMENU hMenu = NULL, HACCEL hAccel = NULL);

Fonksiyonun birinci parametresi CMDIChildWnd sınıfından türettiğimiz sınıfın dinamik olarak yaratılmasında kullanılacak olan RUNTIME_CLASS makrosudur. Fonksiyonun ikinci parametresi string kaynağının ismidir (ID değeridir). Burada belirtilen string document pencerelerinin pencere başlığı olarak kullanılır. Fonksiyonun üçüncü parametresi bir document penceresi açıldığında görüntülenecek menünün HANDLE değeridir. Son parametre document pencereleri için kısayol tuş kaynağıdır.

MDI uygulamalarında genellikle iki menü kullanılır ve bu iki menü dinamik olarak framework tarafından değiştirilmektedir. Bu fonksiyonda belirtilen menü en az bir document penceresi açıksa otomatik görüntülenir. Hiçbir document pencersi açık değilse normal frame penceresine önce normal menü görüntülenecektir. (API düzeyinde dinamik menü değişimi kavramı vardır. Dinamik menü değişimi için Client pencereye WM_MDISETMENU mesajı gönderilir.) MFC wizard iki menüyü otomatik olarak yaratmaktadır. Bunun dışında document penceresinin menü kaynağını ve kısayol tuş kaynağını da oluşturmaktadır.

MDI uygulamalarında menü mesajları programcının istediği herhangi bir sınıfta işlenebilir. Çoğu kez document pencerelerinin view sınıflarında işlemek kolaylık sağlar. MFC’nin message routing özelliği dolayısıyla menü mesajları bir pencereyi temsil etmeyen uygulama (App) sınıfında bile işlenebilmektedir.

Document pencerelerinin yaratılması wizard’ın yaptığı gibi CreateNewChild fonksiyonu yerine CMDIChildWnd sınıfının Create fonksiyonuyla da yapılabilir. Bu fonksiyonla pencere başlığını istediğimiz gibi set edebiliriz. CreateNewChild fonksiyonun geri dönüş değeri yaratılan document penceresinin nesne adresidir.

Görüldüğü gibi CreateNewChild fonksiyonun pencere başlığını set edecek bir parametresi yoktur. Pencere başlığı kaynaktan alınmaktadır. Ancak document pencerelerinin pencere başlığı pencere yaratıldıktan sonra herhangi bir zaman SetWindowText fonksiyonuyla değiştirilebilir. Yaratılır yaratılmaz pencere başlığının değiştirilmesi istenirse CMDIChildWnd sınıfından türettiğimiz sınıfın WM_CREATE mesajı SetWindowText için uygun değildir. Çünkü framework ON_CREATE fonksiyonunun çağırılmasından sonra set işlemini yapmaktadır. Bu işlem için en uygun yer CreateNewChild fonksiyonunu çağırdıktan sonraki satırdır.

163

Page 164: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

19.7 MDIGetActive ve MDIActivate FonksiyonlarıBu fonksiyonlar actif document pencereini elde etmek set etmek için kullanılır.

19.8 MDIMaximize, MDINext FonksiyonlarıMDIMaximize fonksiyonu parametresi ile belirlenen document penceresini maximize yapar. MDINext ise bir sonraki document penceresini aktif hale getirir.

19.9 MDIT ile ve MDICascadeDocument pencereleri için tile ve cascade işlemini yapar. Görüldüğü gibi MDI programlarının menülerinde çok sık rastladığımız Close ve CloseAll gibi işlemler birer fonksiyon olarak yoktur.

Close işlemi document penceresi için DestroyWindow fonksiyonu uygulanarak ya da WM_CLOSE mesajı gönderilerek yapılabilir.

CloseAll gibi bir işlemin yapılabilmesi için bütün document pencerelerinin nesne adreslerinin daha önceden saklanmış olması gerekir. Ancak daha pratik olarak EnumChildWindows gibi fonksiyonlarla yapılabilir.

2002-03-21 Perşembe

164

Page 165: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

20 MFC’DE DEBUG İŞLEMLERİMFC kütüphanesi ve geliştirme sistemi güçlü bir debug mekanizmasına olanak verecek biçimde tasarlanmıştır. Microsoft daha önceki ürünlerinde olduğu gibi Visual C’de de editör sistemine entegre edilmiş bir derleyici kullanmamıştır. Visual C’de derleme işlemi aslında cl.exe isimli komut satır derleyicisi ile yapılmaktadır. Aslında CTRL + F5 tuşlarına basıldığında ya da Build – Compile seçildiğinde editör sistemi cl.exe programını çalıştırarak derlemeyi yapar. cl.exe programı derleme işlemine yönelik pek çok komut satırı parametresi almaktadır. Aslında Project – Settings menüsü açıldığında yapılan belirlemeler editör sistemi tarafından cl.exe programının çağırılmasında kullanılmaktadır. Project Settings’te (yani cl.exe parametrelerinde) önceden tanımlanmış sembolik sabit yaratmak için Preprocessor Definitions isimli bir alan vardır. Bu listedeki sembolik sabitler sanki programın tepesine #define yapılmış gibi kabul edilirler.

Projeyi derlemek için farklı project settings grupları oluşturulabilir. Yani biz A ve B isimli iki farklı settings grubu oluşturabiliriz. Projeyi istediğimiz bir settings grubunu seçerek o belirlemelerle derleyebiliriz. Bir proje yaratıldığında default olarak geliştirme sistemi değişik ayarlamalar içeren debug ve release isimli iki setting grubu oluşturur.

Proje yaratıldığında default olarak debug setting grubu aktiftir. Başka bir setting grubunu aktif hale getirmek için Build – Set Active Configuration seçilir. Project settingslerindeki Settings for o anda hangi settings grubu üzerinde değişiklik yaptığımızı belirtir. Programcı Build –

165

Page 166: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Configuration Menüsüne girerek yeni bir settings grubu tanımlayabilir. Yani settings grubu tanımlanırken olan bir grubun kopyasından çıkartılır ve değişiklikler onun üzerinden yapılır.

20.1 DEBUG ve RELEASE Settings Grubunun AnlamıMFC kütüphanelerinin dinamik ve static biçimlerinin her ikisinin de DEBUG ve RELEASE versiyonları vardır. Yani elimizde iki ayrı MFC kütüphanesi vardır. Bir tanesi DEBUG diğeri RELEASE kütüphaneleridir. Örneğin MFC dinamik release kütüphanesi mfc42.dll isimli tek bir DLL doyasında toplanmıştır. Bu kütüphanenin bir de DEBUG versiyonu vardır. Kütüphanenin DEBUG versiyonunun ismi mfc42d.dll biçimindedir. Projede MFC’nin DEBUG mı yoksa RELEASE kütüphanesimnin mi kullanılacağı Project Settings grubunda belirlenmektedir. DEBUG project settings grubunda MFC’nin debug kütüphanesi, RELEASE settings grubunda release kütüphanesi kullanılacak biçimde seçim yapılmıştır. MFC debug kütüphanesi ASSERT makrolarının koda eklenmesi ile oluşturulmuştur. Yani çeşitli buglar karşısında kütüphane içindeki ASSERT kodlarına takılınabilinir. Doğal olarak DEBUG kütüphanesi RELEASE kütüphanesinden daha büyüktür ve pek çok kontrol kodları içermektedir. DEBUG versiyonu ile RELEASE versiyonu arasındaki arasındaki en önemli farklardan biride DEBUG versiyonunda PE formatına debug bilgileri yerleştirildiği halde release versiyonunda yerleştirilmemesidir. Bilindiği gibi DEBUG altında programın satır satır çalıştırılması ve çalıştırıldıkça kaynak koddaki uygun satırın gösterilmesi debug datalarının derleyici tarafından .OBJ modüle linker tarafından da .EXE modüle yerleştirilmesiyle gerçekleştirilebilir. Debug dataları programın “source level debugging” işlemi için gerekmektedir. Debug dataları PE formatında çok büyük yer kaplamaktadır. Programın release versiyonu debug datalarını içermediğinden daha küçük olur. Tabi kaynak kod seviyesinde debug işlemi yapılamaz. ( Bu durumda ancak Assembler seviyesinde debug edilebilir.)

20.2 ASSERT ve VERIFY MakrolarıASSERT makrosu programın debug versiyonunda kontrol kodu yerleştiren, release versiyonunda kontrol kodunu kaldıran temel bir makrodur. Standart C’de assert makrosu NDEBUG sembolik sabiti ile kullanılmaktadır. Halbuki MFC’de assert yerine ASSERT makrosu tercih edilmektedir. ASSERT makrosu _DEBUG sembolik sabitine duyarlıdır. Eğer _DEBUG sembolik sabiti define edilmiş ise ASSERT kontrolü koda yerleştirilir. define edilmemiş ise kontrol kodları kaldırılır. Yani hiçbir şey yapılmamışsa (default durum – debug mod denmemişse) durum kontrol kodlarının çıkartılmasıdır. MFC’de assert makrosu da kullanılabilir. Ancak bütün kütüphane ASSERT makrosu için tasarlanmıştır. Bu nedenle ASSERT makrosu tercih edilmelidir. DEBUG project settingslerinde _DEBUG sembolik sabiti önceden tanımlanmış sembolik sabit olarak settingse eklenmiştir. Dolayısıyla kontrol kodları programa dahil edilmektedir. ANSI C uyumunu korumak için release settingslerinde NDEBUG sembolik sabiti de tanımlanmıştır. ASSERT makrosunun parantez içi release versiyonunda tamamen koddan çıkarılmaktadır. Dolayısıyla ASSERT parantezinde çağırılan fonksiyonlar programın release versiyonunda çağırılmaz hale gelirler.

VERIFY makrosu tamamen ASSERT makrosu gibidir. Ancak parantez içi işlemler release versiyonunda da yapılır. Her iki makro da release versiyonunda kontrol kodlarını koddan çıkartmaktadır.

20.3 ASSERT_VALID MakrosuBu makronun parametresi CObject sınıfından türemiş bir sınıf nesnesinin adresi olmalıdır. Makro parametresi ile belirtilen adreste geçerli bir nesnenin olup olmadığını kontrol eder. Örneğin bir göstericinin içinde NULL değeri olmasın ancak gösterici tahsis edilmemiş bir alnı gösteriyo olsun ASSERT_VALID makrosu bu durmu anlar. Bu makroda DEBUG sembolik sabitine duyarlıdır. Yani yalnızca programın debug versiyonunda tanımlıdır ve işlemini yapar. ASSERT_VALID prametresi ile belirtilen adreste CObject sınıfından türemiş bir nesnenin olup olmadığını tespit eder. Özellikle üye fonksiyonlar içinde üye fonksiyonların hemen başında üye fonksiyonun geçersiz bir gösterici ile çağırılıp çağırılmadığını tespit etmekte kullanılır.

166

Page 167: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CMyClass::Func(){

ASSERT_VALID(this);//...

}

Şimdi bu üye fonksiyon yanlış bir gösterici ile çağırılmış olsun

pMyClass->Func();

ASSERT_VALID tarafından durum tespit edilecektir. ASSERT_VALID makrosu her üye fonksiyonun başına yerleştirilebilir ancak sınıfın başlangıç ve bitiş fonksiyonlarının içine yerleştirilmemelidir. Aslında ASSERT_VALID makrosu geçerlilik kontrolü için parametre olarak verilen adresi kullanarak CObject sınıfının sanal AssertValid fonksiyonunu çağırmamaktadır. Yani aslında gerçek kontrolü yapan CObject sınıfının AssertValid fonksiyonudur. AssertValid fonksiyonu yalnızca MFC’nin debug kütüphanesinde tanımlanmış bir fonksiyondur. Zaten release versiyonunda ASSERT_VALID makrosu tamamen koddan çıkarılmaktadır.

class CObject {public:

//...#ifdef _DEBUGvirtual void AssertValid();#endif

//...};

AssertValid fonksiyonu türemiş sınıf için programcı tarafından yazılabilir. Bu durumda programcının fonksiyonu çalıştırılacaktır. Programcı eğer türemiş sınıf için bu fonksiyonu yazmadıysa o zaman CObject sınıfınınki çağırılır(Programcı yazarsa yine #ifdef ve #endif arasına yazılmalıdır). CObject::AssertValid geçerlilik kontrolünü yapmaktadır.

Programcı türemiş sınıf için AssertValid fonksiyonunu yazarak kendi sınıfı için de ek bir takım kontroller yapabilir. Tabii fonksiyonun başında CObject::AssertValid fonksiyonunu sanallık mekanizmasını kaldırarak çağırıp adres geçerliliği için kontrolü de yapmalıdır. Örneğin CMyClass sınıfının m_a isimli bir veri elemanı olsun. Bu elemanın değerinin 0 ile 100 aradında olması gereksin. Programcı hem adres geçerliliğini hem de m_a için geçerlilik işlemini CMyClass için AssertValid fonksiyonunu yazarak sınar. AssertValid fonksiyonu programın debug versiyonunda tanımlı olduğuna göre release versiyonunda gereksiz biçimde kodda bulunmasın diye önişlemci kontrolüyle yazılmalıdır.

#ifdef _DEBUGvoid CMyClass::AssertValid(){

CObject::AssertValid(); // Aslında türetmede bir üsttekini // çağırdığımızı düşün

ASSERT(m_a > 0 && m_a < 100);}#endif

Aslında programcı zincir oluşturabilmek için CObject sınıfının değil bir yukarıdaki sınıfın AssertValid fonksiyoınunu çağırmalıdır. (Bu örnek için düşünecek olursak CMyClass’tan türeyen sınıfın AssertValid fonksiyonunda CMyClass::AssertValid fonksiyonu çağırılmalıdır. Constructor içinde sanal fonksiyon çağırılamaz. Yani sanallık mekanizması yoktur. Sanbal fonksiyonu çağırılan nesne henüz yaratılmamış olabilir.)

Başlangıç ve bitiş fonksiyonlarında sanal fonksiyonlar için sanallık mekanizması olmadığından dolayı AssertValid makrosunun başlangıç ve bitiş fonksiyonlarında çağırılmasının bişr önemi yoktur.

2002- 03-28 Perşembe

167

Page 168: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

21 MFC’DE NESNE TUTAN (CONTAİNER) SINIFLARMFC’de CObject sınıfından türetilmiş ya da template olarak yazılmış birkaç nesne tutan (container) sınıf vardır. Template versiyonları tamamen STL sınıflarına benzer. Ancak template olmayanlar CObject sınıfından türetilmiştir. Polmorfik kullanım olanakları vardır. Özellikle Document / View yapılarında seri hale getirme (seralization) işlemlerinde kolaylık sağlar. MFC’de STL’deki vector sınıfına benzer diziler, bağlı listeler, hash tabloları gibi çok kullanılan veri yapıları sınıf haline getirilmiştir. Kuyruk, Stack sistemleri, ikili ağaçlar gibi nesne tutan sınıflara yer verilmemiştir. Bu sınıflar programcı tarafından adapter sınıf olarak yazılabilir. MFC nesne tutan sınıfları iterator kavramını kullanmamaktadır.

21.1 Dizi SınıflarıDizi sınıflarının kullanımı birbirlerine çok benzerdir. CArray template tabanlı bir sınıftır. CUintArray, CByteArray, CWordArray, CDWordArray, CPtrArray, CObArray sınıfları CObject sınıfından türetilmiş normal sınıflardır. CObArray dışındaki sınıflar ayrıntılar dışında tamamen birbirinin aynısıdır. Yalnızca dizi içinde tutulan türleri değişiktir. Örn; CByteArray türünden dizi tanımlarsak BYTE türden bir dizi oluşturmuş olururz. Ancak CWordArray türünden dizi tanımlarsak WORD elemanlar tutmuş oluruz. Diziler STL vector sınıfı gibi otomatik olarak büyütülürler. Tüm dizi sınıflarının yalnızca default başlangıç fonksiyonu vardır. Diziye eleman eklendiğinde tahsisat işlemi STL’de olduğu gibi iki kat blok tahsisatı biçiminde yapılmaz, dizi teker teker büyütülür. Bu ise etkin bir yöntem değildir. Bunun için nesne tanımlandıktan hemen sonra sınıfların SetSize üye fonksiyonları çağırılabilir.

void Class_Name:SetSize(int nNewSize, int nGrowBy = -1);

İlk parametre dizinin başlangıçtaki uzunluğu, ikinci parametresi ise kaç elemanlık bloklar halinde tahsisat yapılacağıdır. Bu fonksiyon genellikle dizi tanımlandıktan hemen sonra çağırılır. Ancak herhangi bir zaman çağırıldığında birinci parametre dizinin o andaki uzunluğundan küçükse bir küçültme işlemi de yapılmaktadır. Örneğin;

CWordArray a;

a.SetSize(1000, 100);

Dizi tanımlandığında henüz dizi için hiçbir yer ayrılmamıştır. Eleman eklenirse yalnızca 1 elemanlık yer tahsis edilerek ekleme yapılır. Ancak daha sonra SetSize fonksiyonu ile dizinin başlanıç uzunluğu 1000 eleman (1000 tane WORD eleman) olarak tespit edilmiştir. Büyütme işlemi 100’er elemanlık alanlar halinde yapılacaktır. Sınıfın GetAt ve SetAt fonksiyonları dizinin bir elemanını elde etmek ya da set etmek amacıyla kullanılır. Örn;

SetAt(100, 5);

Erişilecek indeks değeri dizi uzunluğunu aşarsa programın debug versiyonunda ASSERT işlemi uygulanır. Release veriyonunda herhangi bir kontrol yapılmamaktadır. Ayrıca dizi sınıflarının SetAt ve GetAt fonksiyonlarıyla aynı anlamda olan [ ] operatör fonksiyonları vardır. Sınıfların [ ] operatör fonksiyonları TYPE dizinin türünü anlatmak üzere aşağıdaki prototipe sahiptir.

168

Page 169: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

TYPE& oerator[ ](int index);TYPE oerator[ ](int index) const;

Fonksiyonun birinci versiyonu hem Get hem Set, ikinci versiyonu yalnızca Get işlemi yapar. (İkinci versiyona const nesneler ile çalışabilmek için ihtiyaç var.)

const CByteArray a;a[i] = 10; // OLMAZ. Burada const olan [ ] op. fonk. kullanılır. Compile //aşamasında ERROR olur.

Tabi dizi için başlangıçta bir alan SetSize fonksiyonu ile ayılmamışsa GetAt, SetAt ya da [ ] operatör fonksiyonları DEBUG modunda ASSERT işlemine takılır. Release versiyonunda pointer hatasına yol açar. Sınıfların Add üye fonksiyonları her durumda dizinin sonuna ekleme yapmak için kullanılabilir. Bu fonksiyon dizi için henüz yer ayrılmamışsa ya da ayrılan yer dolmuşsa otomatik tahsisat yapar (ve sona ekler). TYPE tür ismi olmak üzere prototipi şöyledir;

int Add(TYPE val);

Fonksiyonun parametresi eklenecek eleman geri dönüş değeri elemanın yerleştirildiği indeks numarasıdır. Dizi sınıflarının InsertAt fonksiyonu araya ekleme işlemini yapar. Yani tüm elemanlar bir kaydırılır, sayı araya eklenir. Bu fonksiyon da genişletme işlemi yapmaktadır.

void InsertAt(int index, TYPE val, int nCount = 1);

Dizi sınıflarının RemoveAt fonksiyonları tam tersi bir işlem yapmaktadır.

void RemoveAt(int index, int nCount = 1);

Sınıfların RemoveAll fonksiyonu tüm dizi elemanlarını silip tahsis edilen alanları boşaltmaktadır. Zaten bu fonksiyon destructor tarafından otomatik olarak çağırılmaktadır. Bunlar dışında dizi sınıflarının birkaç fonksiyonu daha vardır.

Özetle dizi sınıfının özellikleri şöyledir;

1. Nesne tanımlandığında henüz hiçbir yer ayrılmamıştır. SetSize fonksiyonu çağırılmazsa Add işlemi il her defasında 1 eleman genişletme yapılır.

2. SetSize fonksiyonu ile ilk tahsisat miktarı ve tahsisat blok uzunlukları belirlenebilir.

3. GetAt, SetAt ve [ ] fonksiyonları tahsis edilmemiş alana erişildiğinde debug versiyonunda ASSERTion, release versiyonunda ise pointer hatasına yol açar.

4. Add ve InsertAt fonksiyonları otomatik genişletme yapmaktadır.

5. RemoveAll ya da bitiş fonksiyonu tüm dizi elemanlarını siler.

CObArray sınıfı polimorfik uygulamalar için tercih edilir. Bu sınıf CObject türünden pointerlardan oluşan bir dizi oluşturur. Üye fonksiyonları diğerleri ile aynıdır. Örneğin klasik Shape sınıflarından oluşan Paint programı yazılırken veri yapısı olarak bu sınıf kullanılabilir. Bunun için CShape CObject’ten türetilir. Tabi bunun için CPtrArray sınıfı da kullanılabilir. Ancak sanallığın CObject’ten başlatılması CObject’in sanal fonksiyonlarının da kullanılabileceği anlamına gelir. Gerek CPtrArray gerekse CObArray yalnızca adres tutar. Yani dizi elemanları silindiğinde nesneler silinmez. Yalnızca dizi elamanı olan pointerlar silinir.

CObArray ;

a.Add(new CRectangle(...));a.Add(new CTriangle(...));//...for (int i = 0; i < a.GetSize(); ++i)delete a[i]a.RemoveAll();

169

Page 170: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

21.2 Bağlı Liste SınıflarıDizi sınıfları içsel olarak elemanları ardışıl tutmaktadır. Bu işlem erişimin hızlı olması bakımından avantajlıdır. Ancak eleman silme ve ekleme işlemleri söz konusu olduğunda blok hareketleri oluşur. Bu da bellek ve hız bakımından verimsizliğe yol açar. Bağlı listeler bazı uygulamalarda özellikle sınırı belirsiz dizilerin söz konusu olduğu uygulamalarda avantaj sağlamaktadır. MFC’de Clist isimli bir template bağlı liste sınıfının yanısıra template olmayan normal bağlı liste sınıfları da vardır. Bağlı liste sınıfları şunlardır;

CObList

CPtrList

CStringList

CObList ve CPtrList tıpkı CObArray ve CPtrArray sınıfları gibidir. Yani nesnenin kendisini değil adreslerini bağlı listede tutmaktadır. CStringList ise CString nesne adreslerinden oluşan bir sınıftır. Bu sınıfın ayrıca yazılmasının nedeni Find gibi arama fonksiyonlarının içeriksel yazı karşılaştırması yapmasındandır. Bir bağlı liste sınıfında tipik şu işlemleri yapan fonksiyonlar bulunur;

Başa ve sona eleman ekleyen fonksiyonlar

Araya eleman ekleyen fonksiyonlar

Herhangi bir elemanı silen fonksiyonlar

Herhangi bir elemanı elde eden fonksiyonlar

Arama yapan fonksiyonlar

Bağlı listede dolaşım sağlayan fonksiyonlar

Bağlı liste sınıflarına ilişkin üye fonksiyonlar da hemen hemen birbirinin aynısıdır.

21.3 Bağlı Liste Sınıflarının KullanımıSınıfların başlangıç fonksionlarının genel yapısı şöyledir;

CObListCPtrList (int nBlockSize = 10);CStringList

Fonksiyonun parametresi bağlı listenin genişleme miktarıdır. (Yani eleman eklendiğinde nBlockSize tane düğüm tahsis edilir. Az tahsisat yapmak hedeflenmiştir.)

Bağlı listede her elemana ilişkin POSITION türünden bir değer mevcuttur. POSITION bir adres türüdür. Muhtemelen bağlı listenin düğümünü gösteren bir göstericidir. Bağlı liste düğümünün yapısı dökümante edilmediği için POSITION türünü biz doğrudan değil diğer fonksiyonlara parametre yaparak kullanırız. POSITION türünün hangi türden bir adres belirttiğinin kullanıcı için önemi yoktur. Hatta adres olduğunun bilinmesi bile önemli değildir.

Aslında POSITION boş (dummy) bir pointerdir.

typedef struct tagPOSITION {}*POSITION;içinde veri yok ama böyle bir pointer türü olarak var ve kullanılabilir.

21.4 Bağlı Listeye Eleman Eklenmesi

POSITION AddHead(CObject* pNewElem);POSITION AddTail(CObject* pNewElem);

170

Page 171: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Bağlı liste sınıfları thread safe değildir. O sebeple thread kullanma durumu sözkonusu olursa senkronizasyon yapılmalıdır.

Örneğin WM_MOUSEMOVE mesajında farenin dolaştığı yerleri bağlı liste içinde tutacak olalım. Bu işlem şöyle yapılabilir;

CObList sınıfı kullanılacaksa noktayı tutan CObject sınıfından türetilmiş bir sınıf tanımlanmalıdır.

Her WM_MOUSEMOVE mesajında o andaki koordinat Point sınıfı ile ifade edilip bağlı listeye eklenir.

void OnMouseMove(UINT nFlag, CPoint point){

m_list.AddTail(new CMyPoint(point));}

Burada CMyPoint bizim CObject’ten türettiğimiz ve noktayı temsil eden sınıftır.

2002-04-04 Perşembe

21.5 Bağlı Listenin DolaşılmasıBağlı listeyi dolaşmak için iki fonksiyondan faydalanılır. GetHeadPosititon bağlı listenin ilk elemanına ilişkin POSITION değerini verir. İlk elemana ilişkin POSITION değeri elde edildikten onra GetNext fonksiyonu ile sona kadar yürünür. Sondan başa yürümekte mümkündür. Bunun için GetTailPosition ve GetPrev fonksiyonları kullanılır.

CMyPoint *pMyPoint;

POSITITON pos = list.GetHeadPosition();while(pos != NULL) {

pMyPoint = list.getNext(pos);//...

}

TYPE& GetNext(POSITITON &r);TYPE& GetPrev(POSITITON &r);

SINIF ÇALIŞMASI :Fareyi sürükledikçe çizim yapan ve çizim noktalarını bağlı listede tutarak WM_PAINT mesajında yeniden çizen programı yazınız. Açıklamalar;

Bağlı liste sınıfı olarak CObList, CPtrList ya da template tabanlı olan CList seçilebilir. CObList sınıfı kullanılacaksa CObject sınıfından sınıf türetmek gerekir.

class CMyPoint : public CObject {public:

int m_x;int m_y;CMyPoint(int x, int y){

m_x = x;m_y = y;

}};Bağlı liste için View sınıfında bir veri elemanı tanımlanır.

COblist m_list;WM_MOUSEMOVE mesajında nokta alınarak AddTail fonksiyonuyla listeye eklenir.

WM_PAINT mesajında bağlı liste dolaşılarak çizim yapılır.

171

Page 172: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Bu fonksiyonların dışında bağlı liste sınıflarının başka yararlı fonksiyonları da vardır.

21.6 CMap Sınıflarıİsmi CMap ile başlayan sınıflar hash tablosu kurarak hashing algoritması uygulamaktadır. Hashing sıralı erişim ile rastgele erişimin ortalaması sayılabilecek bir yöntemdir. Özellikle bu yöntem kapasitesi belli bilgileri kolay, hızlı erişmek için kullanılır.

CMap sınıfları bir anahtar bilgi ile başka bir bilgiyi hashing yöntemi ile bulmayı sağlar. Sınıflar XtoY biçiçminde isimlendirilmiştir. X anahtar bilgiyi, Y ise bu anahtar bilgi karşılığında elde edilecek bilgiyi temsil eder. CMap sınıfları şunlardır;

CMap. Template tabanlı genel bir sınıftır. CMapPtrToPtr. CMapStringToObCMapStringToPtrCMapStringToStringCMapWordToObCMapWordToPtr

21.7 CMap Sınıflarının KullanımıCMap sınıflarının kullanımı neredeyse aynıdır. Programcı anahtar bilgi kullanrak başka bir bilgiyi hash tablosuna yerleştirir. Sonra anahtar bilgiyi vererek orjinal bilgiyi geri alır. Bütün sınıfların default başlangıç fonksiyonu vardır. En çok kullanılan sınıfların [ ] operatör fonksiyonlarıdır. [ ] operatör fonksiyonunun parametresi anahtar bilgidir. Geri dönüş değeri hash tablosundaki bilgiye ilişkin referanstır. Bu nedenle çift yönlü kullanımı mümkündür. Örn;

CMapStringToString map;

map[“ali”] = “Eskişehir”;map[“veli”] = “İzmir”;puts(map[“ali”]);

Görüldüğü gibi CMapStringToString sınıfının [ ] operatör fonksiyonu şöyledir.

CString& CMapStringToString::operator[](CString& str);

Sınıfın Lookup fonksiyonu bir değerin tabloda olup olmadığını anlamak için kullanılır. Fonksiyonun iki parametresi vardır. Birinci parametre anahtar bilgi. İkinci parametre bulunan değerin yerleştirileceği referans değeridir. Eğer aranılan bilginin daha önce set edilmemiş olması olasılığı varsa arama böyle yapılmalıdır. Fonksiyonun geri dönüş değeri işlemin başarısını anlatır. Örneğin CMapStringToString için arama şöyle yapılabilir.

CString result;map.Lookup(“ali”, result); // ali’ye karşılık gelen değeri result’a yazar

Arama için [ ] operatör fonksiyonu kullanılırsa ve arama başarısız olursa pointer hatası oluşabilir. MFC’nin CMap sınıfları çakışma durumuna izin vermez. Yani aynı anahtar bilgi ile set işlemi yapılırsa eski bilgi gider yeni bilgi yerleşir. Bu yüzden kullanılan hashing algoritması çok basittir.

172

Page 173: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

22 NESNELERİN DİSKTE SAKLANMASI VE GERİ ALINMASI (OBJECT PERSİSTENCY / SERİALİZATİON)

Bir sınıf nesnesinin içindeki bilgilerin diske yazılıp geri alınması nesne yönelimli programlama tekniğinde gittikçe artan bir önem kazanmıştır. Bu sayede bir sınıf nesnesinin tuttuğu veriler programın belirli bir aşamasında ya da sonunda diske yazılabilir ve daha sonra oradan alınarak tekrara nesne biçiminde kullanılabilir. Örneğin bir çizim işlemini yapan sınıf diske yazılırsa bütün çizim bilgileri diskte saklanmış olur. İstenildiği zaman bütün bilgiler yeniden nesne içine çekilerek kalınan yerden devam edilebilir. Sınıf nesnesini diske yazmak için veri elemanlarının tek tek bir dosyaya yazılması gerekir. Bu işlem basit gibi görünse de bir sınıfın başka bir sınıf türünden veri elemanına sahip olduğu durumlarda ya da bir göstericiye sahip olduğu durumlarda (bu göstericinin gösterdiği yerde de bilgiler vardır) durum karmaşık bir hal almaktadır. Çünkü diske yazma işlemi sırasında sınıfın normal veri elemanlarının, başka bir sınıf türünden veri elemanlarının ve gösterici veri elemanlarının gösterdiği yerdeki bilgilerin de diske yazılması gerekir. Bu işlemlerin yapılması ve geri alınması aynı sırada ve adım adım gerçekleştirilmelidir. Bu nedenle bu işlemlere seri hale getirme işlemi (object serialization) de denilmektedir. Nesnelerin diskte saklanıp geri alınması için CArchive sınıfı ile CObject sınıfının sanal Serialize fonksiyonu kullanılmaktadır.

22.1 CArchive SınıfıCArchive sınıfı tıpkı CFile sınıfı gibi bir dosyaya okuma yazma yapan fonskiyonlara sahiptir. CFile sınıfından farklı olarak seri hale getirme işlemi konusunda faydalı işlevleri vardır. Bir sınıfın veri elemanı olarak başka bir sınıf türünden nesne kullanmak COMPOSITITONdır. Asıl nesne oluşturulursa içteki nesne de oluşturulur, ölürse de ölür. Başka bir kullanım biçimi de önceden bir nesne tanımlanıp diğerinin constructoruna geçirilir. Bu şekilde kullanılır. Yani bir sınıfın diğerini interface’inde kullanması. Bu da AGGREGATION.

Data Members CArchive Class Membersm_pDocument Points to the CDocument object being serialized.ConstructionCArchive Creates a CArchive object.Abort Closes an archive without throwing an exception.Close Flushes unwritten data and disconnects from the CFile.Basic Input/OutputFlush Flushes unwritten data from the archive buffer.operator >> Loads objects and primitive types from the archive.operator << Stores objects and primitive types to the archive.Read Reads raw bytes.Write Writes raw bytes.WriteString Writes a single line of text.ReadString Reads a single line of text.StatusGetFile Gets the CFile object pointer for this archive.GetObjectSchema Called from the Serialize function to determine the version of the object that is being deserialized.SetObjectSchema Sets the object schema stored in the archive object.IsLoading Determines whether the archive is loading.IsStoring Determines whether the archive is storing.IsBufferEmpty Determines whether the buffer has been emptied during a Windows Sockets receive process.Object Input/OutputReadObject Calls an object’s Serialize function for loading.WriteObject Calls an object’s Serialize function for storing.MapObject Places objects in the map that are not serialized to the file, but that are available for subobjects to

reference. SetStoreParams Sets the hash table size and the block size of the map used to identify unique objects during the

serialization process.SetLoadParams Sets the size to which the load array grows. Must be called before any object is loaded or before

MapObject or ReadObject is called.ReadClass Reads a class reference previously stored with WriteClass.WriteClass Writes a reference to the CRuntimeClass to the CArchive.SerializeClass Reads or writes the class reference to the CArchive object depending on the direction of the

CArchive.

CArchive sınıfının kullanılması için daha önce CFile sınıfı türünden bir nesne tanımlanmış olması gerekir. CArchive işlemlerini yapmak için CFile sınıfından faydalanamaktadır. Sınıfın başlangıç fonksiyonu şöyledir;

173

Page 174: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CArchive::CArchive(CFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = NULL);

Fonksiyonun birinci parametresi CFile nesnesinin adresidir. İkinci parametre seri hale getirme işleminin yönünü belirtir. Şu sabitlerden biri olabilir;

CArchive::loadCArchive::storeCArchive::bNoFlashUndelete

Fonksiyonun üçüncü parametresi CArchive sınıfının kullandığı içsel bir buffer uzunluğudur. Son parametre ise kullanılacak bufferın belirlenmesine olanak sağlar. Son iki parametre hız kazancı sağlamak için CArchive sınıfının kullandığı tampon ile ilgilidir.

Bilindiği gibi CFile sınıfının böyle bir tamponlama özelliği yoktur.

2002-04-09 Salı

CArchive sınıfının okuma ve yazma işlemi yapan bir grup << ve >> operatör fonksiyonu vardır. << ve >> operatör fonksiyonları C++’ın tüm doğal türleri için ve CString gibi bazı MFC sınıfları için yazılmıştır. Bu operatör fonksiyonları aslında okuma ve yazma işlemleri için CArchive sınıfının ReadObject ve WriteObject üye fonksiyonlarını kullanırlar. CArchive türünden nesne okuma ya da yazma amaçlı olarak yaratılır. Her ikisini birlikte yapmak amacı ile yaratılamaz. Bu durum CArchive sınıfının başlangıç fonksiyonunda belirlenmektedir. Programcı CArchive türünden bir nesne ele geçirdi ise bu nesnenin okuma amaçlı mı yoksa yazma amaçlı mı oluşturulduğunu sınıfın IsStoring ve IsLoading fonksiyonlarını çağırarak analayabilir.

BOOL IsStoring() const; //yazma amaçlı kullanılıyorBOOL IsLoading() const; //okuma amaçlı kullanılıyor

IsStoring sıfır dışı değere geri dönerse nesne yazma amaçlı, sıfır değerine geri dönerse okuma amaclı yaratılmıştır.

22.2 Nesnelerin Diske Yazılıp Diskten Okunma İşlemlerinin GerçekleştirilmesiBir nesneyi diske yazmak demek o nesnenin doğal türden veri elemanlarını, başka sınıf türünden veri elemanlarını ve bir gösterici veri elemanı varsa göstercinin gösterdiği yerdeki bilgileri diske yazmaktır. Yazma işlemi aslında binary bir dosyaya bilgi yazma işlemidir. Nesne diske yazılırken ve diskten okunurken aynı sıra izlenmelidir. Nesneleri diske yazmak için Document/View mimarisi tarafından da kullanılan CObject sınıfının sanal Serialize fonksiyonu kullanılmaktadır.

virtual void CObject::Serialize(CArchive& ar);

Fonksiyon Document/View mimarisi içinde Polimorfik olark kullanılmaktadır. O nedenle sanaldır. Serialize fonksiyonunu çağıran kod CFile nesnesini yaratmış yani dosyayı açmıştır. CArchive nesnesini de oluşturmuştur ve bu nesne ile Serialize fonksiyonunu çağırmıştır. Serialize fonksiyonu hem nesnenin diske yazılması hem de diskten okunması amacıyla kullanılır. Bu nedenle Serialize fonksiyonunu yazarken önce işlemin yönünü tespit etmek gerekir. Örneğin

1. CMyClass isimli sınıfın iki veri elemanı olsun. Tipik olarak seri hale getirme işlemi şu içimde yapılır.

class CMyClass : public CObject {//...public:

int m_a, m_b;};

174

Page 175: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

void CMyClass::Serialize(CArchive& ar){

if (ar.IsStoring()) {ar << m_a;ar << m_b;

}else {ar >> m_a;ar >> m_b;}}

CMyClass myClass;CFile file;CArchive ar(...);

myClass.Serialize(ar);

2. Bir sınıf başka bir sınıf türünden veri elemanına sahip ise Serialize fonksiyonu içinde o nesne için de Serialize fonksiyonu çağırılır. Tabii eleman olarak kullanılan sınıfın da bir Serialize fonksiyonu yazılmış olmalıdır. Örneğin CMyClass sınıfının daha öncekilere ek olarak bir de CYourClass türünden m_c isimli veri elemanı olsun. CMyClass sınıfının seri hale getirilmesi şöyle olmalıdır.

class CMyClass : public CObject {//...public:

int m_a, m_b;CYourClass m_c;

};

void CMyClass::Serialize(CArchive& ar){

if (ar.IsStoring()) {ar << m_a;ar << m_b;

}else {ar >> m_a;ar >> m_b;}m_c.Serialize(ar); //!if parentezinin dışında bırakılmış.iyi yöntem}

CYourClass sınıfının Serialize fonksiyonu da aynı bu biçimde olduğu gibi yazılmıştır. Yazma ve okuma sırasında sıralama bozukluğu görülmez.

CArchive sınıfının CObject* parametreli bir << operatör fonksiyonu vardır. Bu operatör fonksiyonu sanal Serialize fonksiyonunu çağıracak biçimde yazılmştır.

CArchive& Carchive::operator<<(CObject* pObject){pObject->Serialize(*this); // Zaten CArchive içindeyiz. // onun için *this

return *this;}

ar << &m_c; // CObject* parametreli olanı çağırılır.

Sınıfın CObject parametreli >> operatör fonksiyonu yoktur sadece << operatör fonksiyonu vardır. Aşağıdaki yöntem tavsiye edilmese de normal olarak çalışır.

void CMyClass::Serialize(CArchive& ar){

if (ar.IsStoring()) {ar << m_a;ar << m_b;

175

Page 176: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

ar << m_c}else {ar >> m_a;ar >> m_b;m_c.Serialize(ar);}}

3. Bir sınıf dizi ya da bağlı liste gibi bir nesne tutan sınıf nesnesi içeriyorsa seri hale getirme işlemi sırasında nesne tutan sınıftaki tüm nesnelerin de diske yazılması gerekir. Örneğin CMyClass sınıfı öncekilere ek olarak CObList türünden bir m_list isimli nesne içersin. Bu bağlı liste içinde CMyPoint sınıfı türünden nesne adresleri tutuluyor olsun.

class CMyClass : public CObject {//...public:

int m_a, m_b;CYourClass m_c;CObList m_list;

};

Şimdi Seri hale getirme işlemi sırasında m_a, m_b ve m_c nesnelerinin yanısıra m_list bağlı listesinin tuttuğu tüm CMyPoint nesneleri de seri hale getirilmelidir. İşte MFC’de tüm nesne tutan sınıflar için Serialize fonksiyonu zaten kütüphane içinde yazılmış durumdadır. Eğer nesne tutan sınıf C++’ın doğal türleri için bir sınıfsa bu sınıfların Serialize fonksiyonları içinde tutulan bilgilerin hepsi sırasıyla diske yazılıp diskten okunmuştur. Yok eğer nesne tutan sınıf CObject* türünden adresleri tutuyorsa (CObList, CObArray gibi) bu sınıfların Serialize fonksiyonları bütün veri yapısını dolaşarak bu nesne adresleri ile sanal Serialize fonksiyonlarını çağıracak biçimde yazılmıştır. Yukarıdaki örneğimizde bağlı listeyi seri hale getirmek için yalnızca COblist sınıfının Serialize fonksiyonunu çağırmamız yeterlidir. Bu işlem ile COblist sınıfının Serialize fonksiyonu tek tek tüm CMyPoint nesneleri için CMyPoint sınıfının Serialize fonksiyonunu çağıracaktır. Tabi CMyPoint sınıfının Serialize fonksiyonunuda yazmış olmamız gerekir. Bu durumda yukarıdaki sınıfın seri hale getirilmesi şöyle yapılacaktır.

void CMyClass::Serialize(CArchive& ar){

if (ar.IsStoring()) {ar << m_a;ar << m_b;

}else {ar >> m_a;ar >> m_b;}m_c.Serialize(ar);m_list.Serialize(ar);}

4. Başkaları tarafından yaratılmış bir sınıftan türetme yaptığımızı düşünelim. Türemiş sınıf için Serilaize fonksiyonunu yazmış olalım. Türemiş sınıf taban sınıfların da veri elemanlarını içereceğine göre taban sınıfın veri elemanlarının da seri hale getirilmesi gerekir. Örneğin CMyPoint sınıfı CObject sınıfından türetilmiştir. CMyPoint sınıfının veri elemanlarını seri hale getirirken CObject sınıfının veri elemanlarını da seri hale getirmek gerekeir. Bu işlemi sağlamanın en pratik yolu bir sınıf için Serialize fonksiyonunu yazarken önce onun taban sınıfı için de Serialize fonksiyonu çağırılmalıdır. Böylece türemiş sınıf seri hale getirilmeden önce yukarıya doğru bir zincir ile onun bütün taban sınıfları seri hale getirilmiş olur. Serialize fonksiyonlarının başında taban sınıf için Serialize fonksiyonunun çağırılması alışkanlık haline getirilmelidir. Bu durumda yukarıda ele alınan CMyClass sınıfı için Serialize fonksiyonunun son durumu şöyledir.

void CMyClass::Serialize(CArchive& ar)

176

Page 177: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

{CObject::Serialize(ar);if (ar.IsStoring()) {

ar << m_a;ar << m_b;

}else {

ar >> m_a;ar >> m_b;

}m_c.Serialize(ar);m_list.Serialize(ar);}

Diske yazma işleminde << operatör fonksiyonu ve Serialize fonksiyonunun çağırılması arasında küçük bir fark vardır.

5. Sınıfın bir gösterici elemanının olduğunu ve bunun için daha önce tahsisat yapılmış olduğunu ve bu göstericinin tahsis edilmiş bir alanı gösteridiğini düşünelim. Seri hale getirirken bu göstericinin gösterdiği yerdeki bilgiyi de dikkate almak gerekir. Geri alma işlemi yapılırken gösterici için yeniden tahsisat yapılması gerekir. Örneğin CMyClass sınıfına int türden bir gösterici ekleyelim. Seri hale getirme işlemi şöyle yapılmalıdır.

class CMyClass : public CObject {//...public:

int m_a, m_b;CYourClass m_c;CObList m_list;int* m_pd;

};

void CMyClass::Serialize(CArchive& ar){

CObject::Serialize(ar);if (ar.IsStoring()) {

ar << m_a;ar << m_b;ar << *m_pd;//diske yaziliyor

}else {ar >> m_a;ar >> m_b;m_pd = new int; //önce tahsisat yaptikar >> m_pd; //daha sonra adrese yükledik}m_c.Serialize(ar);m_list.Serialize(ar);}

6. Ancak genellikle sınıfın gösterici elemanı başka bir sınıf türünden gösterici olur. Örneğin CMyClass, CYourClass türünden normal bir veri elemanı değil de bir gösterici veri elemanı içersin.

class CMyClass : public CObject {//...public:

int m_a, m_b;CYourClass* m_pc;CObList m_list;

};

Seri hale getirme işlemi şöyle yapılabilir.

void CMyClass::Serialize(CArchive& ar){

CObject::Serialize(ar);if (ar.IsStoring()) {

177

Page 178: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

ar << m_a;ar << m_b;

}else {ar >> m_a;ar >> m_b;

m_pc = new CYourClass();}m_pc->Serialize(ar);m_list.Serialize(ar);}

Bu işlemin daha iyi bir yapılış biçimi DECLARE_SERIAL ve IMPLEMENT_SERIAL makrolarını kullanmaktır. SERIAL makroları kendi içlerinde DYNCREATE makrolarını içerir. Ancak bu makrolar DYNCREATE makrolarından fazla olarak sınıfa ilginç bir >> operatör fonksiyonu daha eklerler.

int *p;Func(p);

void Func(int** pp){

*pp = ...}

ile

void Func(int*& r){

r = ...}

aynıdır.

Makroların yerleştirdiği >> operatör fonksiyonu şunları yapmaktadır;

CArchive& operator>>(CArchive& ar, CMyClass*& MyClass){ // CMyClass, makro parametresinden geliyor1 – CRuntimeClass sınıfı kullanılarak CMyClass türünden dinamik nesne yaratılır2 – Yaratılan dinamik nesne için Serialize fonksiyonu çağırılıyor. //...}

Taban sınıfa türemiş sınıfın pointerları atanamaz. *base = *derived olur ama **base=**derived olmaz.

Sonuç olarak eğer gösterici veri elemanına ilişkin sınıf (örneğimizde CYourClass sınıfı) DECALRE_SERIAL ve IMPLEMENT_SERIAL makrolarını içeriyorsa bu nesnenin seri hale getirilmesi aşağıdaki gibi yapılabilir. Böyle seri hale getirme tavsiye edilmektedir.

void CMyClass::Serialize(CArchive& ar){

CObject::Serialize(ar);if (ar.IsStoring()) {

ar << m_a;ar << m_b;ar << m_pc;

}else {ar >> m_a;ar >> m_b;ar >> m_pc;}m_list.Serialize(ar);}

178

Page 179: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Burada ar << m_pc işlemi ile CArchive sınıfının CObject* parametreli fonksiyonu çağırılır. O da Serialize fonksiyonunu çağırarak seri hale getirme işlemini yapar. ar >> m_pc işleminde ise SERIAL makrolarının yerleştirdiği operatör fonksiyonu çağırılır. Bu fonksiyon da önce tahsisat yapar sonra sınıfın Serialize fonksiyonunu çağırır.

SERIAL makrolarının kullanımı şöyledir;

DECLARE_SERIAL(class_nam) // Sınıf bildiriminin içineIMPLEMENT_SERIAL(class_name, base_class_name, schema_no);

// Global düzeyde .CPP dosyaya yaz

Buradaki schema_no herhangi bir sayı olabilir. Versiyonlar arasındaki uyumsuzluğu belirlemek amacı ile kullanılmaktadır.

179

Page 180: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

23 DOCUMENT/VIEW MİMARİSİ

Document/View mimarisinin amacı programın verilerinin View sınıfında değilde ayrı bir sınıfta tutulması yani programın verileri ile görüntü işlemlerini farklı sınıflara aktararak algısal ve uygulamaya yönelik kolaylık sağlanmasıdır. Document/View mimarisi seri hale getirme işlemi ile entegre edilmiştir ve kendi içinde pek çok wizard barındırma özelliği dahil edilmiştir.

2002-04-11 Perşembe

180

Page 181: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Document/View bir uygulamanın manual olarak hazırlanması mümkündür ama zordur. Genellikle bu uygulamalar wizard tarafında oluşturulur. Document/View uygulamaları tek dökümanlı olabilir ya da genel olarak MDI işlemleri ile entegre edilmiş bir biçimde olabilir.

23.1 SDI Document/View Uygulaması

Tek döküman (SDI) içeren bir uygulama wizard ile Project – New – MFCAppWizard – Single Document seçilerek ancak Document/View architecture support check box’ı check edilerek oluşturulur. Bu işlemler sonrasında şu sınıflar oluşturulur.

CWinApp sınıfından türetilmiş bir uygulama sınıfı

CFrameWnd sınıfından türetilmiş olan ana pencereye ilişkin olan sınıf

CView sınıfından türetilmiş bir View sınıfı (CView sınıfı da CWnd’den türetilmiştir.) Document/View mimarisi içermeyen uygulamalarda View sınıfı CWnd sınıfından türetilmiş normal bir alt pencere sınıfıdır. Halbuki Document/View mimarisinde View sınıfı CView sınıfından türetilmiş bir sınıftır ve çok geniş bir anlamı vardır.

181

Page 182: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CDocument sınıfından türetilmiş bir doküman sınıfı (CDocument sınıfı bir pencere sınıfı değildir. Doğrudan CCmdTarget’tan türetilmiştir.)

Görüldüğü gibi ana pencereyi kaplayan alt pencere yani View penceresi CView sınıfından türetilen bir sınıfla temsil edilir. View sınıfı ile Document sınıfı arasında içsel bir bağlantı vardır.

Document/View mimarisi Document/View ve ana pencere sınıflarının işbirliğini gerektirir. Bu yüzden programın ana penceresi, View penceresi ve Document penceresi framework tarafından dinamik olarak yaratılmaktadır ve böylelikle bazı ayrıntılı işlemler gözardı edilmektedir.

Tek dokümanlı bir Document/View uygulamasının InitInstance fonksiyonu tipik olarak şöyledir.

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(IDR_MAINFRAME, RUNTIME_CLASS(CMyDocument),RUNTIME_CLASS(CMyFrameWnd), RUNTIME_CLASS(CMyView));

AddDocTemplate(pDocTemplate);

Bu kod parçasının açıklaması şöyledir; Document/View mimarisi arka planda undocumented bir biçimde CDocManager, CSingleDocTemplate, CMultiDocTemplate sınıflarıyla sağlanmaktadır. Document/View mimarisinin ayrıntıları Microsoft tarafından dokümante edilmemiştir. CWinApp sınıfının Document/View mimarisini yöneten CDocManager sınıfı türünden bir private elemanı vardır. Document/View mimarisine ilişkin sınıflar CSingleDocTemplate ya da CMultiDocTemplate sınıflarıyla kontrol edilir. AddDocTemplate CWinApp sınıfının bir üye fonksiyonudur ve yaratılan CSingleDocTemplate ya da CMultiDocTemplate nesnelerinin CWinApp sınıfının bir veri yapısı içinde saklar. Yani Document/View mimarisini yöneten sınıf CWinApp sınıfıdır. Document/View mimarisinin amacı şunlardır;

Uygulamanın verileri ile çizim ve görüntü kısmını mantıksal olarak birbirinden ayırmak.

Uygulamanın verilerini bir dosyaya yazıp, bir dosyadan geri alma işlemini seri hale getirme işlemi ile birleştirerek kolaylaştırmak.

Wizardın sunduğu bazı kolaylıklardan faydalanmak.

Ayrıca programın View sınıfı olarak kullanılan sınıf uygulama wizard ile oluşturulurken değiştirilebilmektedir. Örneğin View sınıfı bir dialog penceresi gibi (CFormView) ya da bir editör gibi (CEditView) gibi davranabilmektedir. Yani Microsoft’un yazdığı CView sınıfından türetilmiş çeşitli uygulamalara taban oluşturacak bazı View sınıfları mevcuttur.

Wizardın oluşturduğu kodda File menüsündeki Open, New, Save gibi menü elemanları seri hale getirme işlemini destekleyecek biçimde wizard tarafından işlenmiştir. Programcının uygulaması bir dosyaya saklama ve bir dosyadan yükleme içeriyorsa programcının bu menü işlemlerine dokunmaması gerekir. Document/View uygulaması için Wizard’ın ürettiği kod gelişmiş bir koddur. Programcı bu kod üzerinde kısmi değişiklikler yaparak uygulamasını oluşturmalıdır.

23.2 View ve Document Sınıflarının KullanılmasıDocument/View mimarisi içermeyen uygulamalarda olduğu gibi programın ana penceresinin çalışma alanı yine View alt penceresi ile kaplanmıştır. Yani programcı fare ve klavye mesajlarını bu pencerede işlemek zorundadır. Document/View mimarisinde programın gerçek verileri Document sınıfında yani Wizard’ın oluşturduğu CDocument sınıfından türetilmiş sınıfta saklanmalıdır. View sınıfı çeşitli veri elemanlarına sahip olabilir. Ancak bu veri elemanları programın diske yazılacak gerçek verileri olmamalıdır. Bu işlemlere aracılık edecek veri elemanları kullanılabilir. Document/View mimarisinde seri hale getirme işlemi Document sınıf ile

182

Page 183: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

ilişkilendirilmiştir. Dolayısıyla veriler View sınıfında tutulursa diske yazıp okumadaki framework tarafından sağlanan kolaylıklardan faydalanılamaz.

Örneğin fare ile click yapılan yerde daireler çizen bir uygulama düşünelim. Amacımız WM_PAINT mesajında tüm dairelerin yeniden çizilmesini sağlamak ve bütün daireleri bir dosyada tutup geri alabilmek olsun. Daireler CObject sınıfından türettiğimiz CCircle gibi bir sınıf ile temsil edilebilir ve tüm daireler bir bağlı listede tutulabilir. Yani programın verileri bu daireler, başka bir deyişle bağlı listedir. Document/View mimarisi olmasaydı biz bu bağlı liste veri elemanını View sınıfında tutardık ve menüden File – Save seçildiğinde bu bağlı listeyi dolaşır tüm daire bilgilerini dosyaya manual olarak yazardık. File – Open işleminde de dosyayı açar bağlı listeyi oluştururduk. Ancak Document/View mimarisinde biz bağlı liste veri elemanını (yani programın verilerini) Document sınıfında tanımlarız ve diske yazıp okuma işlemlerinde framework tarafından sağlanan seri hale getirme işleminden faydalanırız.

23.3 Document/View Mimarisinde WM_PAINT MesajıDocument/View mimarisinde View sınıfı için WM_PAINT mesajı CView sınıfında hook edilmiştir(kancalanmıştır). Çizim işlemini kolaylaştırmak için kancalanan WM_PAINT mesajı içinde bir DC yaratılıp OnDraw sanal fonksiyonu çağırılmıştır. Böylelikle View sınıfında programcı OnPaint fonksiyonunu değil OnDraw fonksiyonunu işlemelidir. Bu sayede DC yaratma işlemi framework tarafından yapılmaktadır.

virtual void OnDraw(CDC* pDC) = 0;

OnDraw fonksiyonunun çağırılıması şu biçimde olmaktadır; Bilindiği gibi framework ilgili mesajı mesaj haritasında arayıp bulamazsa o sınıfın taban sınıflarında da sırasıyla arar. Wizard CView sınfıından türettiği sınıf için ON_WM_PAINT makrosunu mesaj haritasına yazmamıştır. Ancak CView sınıfında CView sınıfının mesaj haritasına bu makro yazılmıştır ve OnPaint fonksiyonu CView sınıfında şu şekilde işlenmiştir;

void CView::OnPaint(){

CPaintDC dc(this);OnPrepareDC(&dc);OnDraw(&dc);

}

Görüldüğü gibi OnDraw fonksiyonu içinde DC’nin bırakılmasına gerek yoktur. OnPaint fonksiyonu CView sınıfından türetilmiş sınıfta da işlenebilir. Ancak bu durumsa framework bu sınıfın mesaj haritasında ON_WM_PAINT makrosunu bulacağından dolayı CView sınıfının OnPaint fonksiyonu çağırılmayacaktır dolayısıyla OnDraw fonksiyonu da çağırılmayacaktır. Tabi OnDraw fonksiyonunu işlemek her bakımdan daha avantajlıdır.

23.4 View Sınıfından Document Sınıfına ErişilmesiDocument sınıflarından View sınıflarına, View sınıfılarından da Document sınıfına erişmek mümkündür. Bunun için CView sınıfının GetDocument fonksiyonu kullanılır.

CDocument* CView::GetDocument() const;

Tabi bu fonksiyon bize Document nesnesinin adresini CDocument sınıfından türetilmiş sınıf türünden değil sanki CDocument nesnesinin adresiymiş gibi verir. Tabi aslında verilen adres türetilmiş nesnenin adresidir. Yani tür dönüştürmesi gerekmektedir. Ancak wizard kolaylık olsun diye view sınıfı için bir public GetDocument fonksiyonu daha yazmıştır. Yani View sınıfında GetDocument fonksiyonunu çağırdığımızda CView sınıfının GetDocument fonksiyonunu değil CView sınıfından türettiğimiz sınıfın GetDocument fonksiyonunu çağırırız. Wizardın yazdığı GetDocument fonksiyonunun geri dönüş değeri CDocument* değil CDocument sınıfından türettiğimiz sınıfa ilişkindir (CMyDocument* gibi). Yani tür dönüştürmesi yapmaya gerek yoktur. Bazen programcılar View sınıfında her fonksiyonda GetDocument fonksiyonunu çağırarak

183

Page 184: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Document sınıfındaki nesneleri elde etmek yerine bu nesnelerin adreslerini işin başında bir kez View sınıfındaki bir gösterici veri elemanına taşımayı tercih etmektedir.

Document/View mimarisindeki işlemlerin özeti şudur; Programın verileri View sınıfında oluşmaktadır. Ancak burada oluşan veriler Document

sınıfına taşınmalı ve orada saklanmalıdır. Çünkü disk ile transfer işlemi Document sınıfı ile ilişkili bir kavramdır.

View sınıfı içinde Document sınıf adresinin ele geçirilmesi GetDocument fonksiyonu ile olmaktadır.

CDocument Class MembersConstructionCDocument Constructs a CDocument object.OperationsAddView Attaches a view to the document.GetDocTemplate Returns a pointer to the document template that describes the type of the document.GetFirstViewPosition Returns the position of the first in the list of views; used to begin iteration.GetNextView Iterates through the list of views associated with the document.GetPathName Returns the path of the document’s data file.GetTitle Returns the document’s title.IsModified Indicates whether the document has been modified since it was last saved.RemoveView Detaches a view from the document.SetModifiedFlag Sets a flag indicating that you have modified the document since it was last saved.SetPathName Sets the path of the data file used by the document.SetTitle Sets the document’s title.UpdateAllViews Notifies all views that document has been modified.OverridablesCanCloseFrame Advanced overridable; called before closing a frame window viewing this document.DeleteContents Called to perform cleanup of the document.OnChangedViewList Called after a view is added to or removed from the document.OnCloseDocument Called to close the document.OnNewDocument Called to create a new document.OnOpenDocument Called to open an existing document.OnSaveDocument Called to save the document to disk.ReportSaveLoadException Advanced overridable; called when an open or save operation cannot be completed because of an

exception. GetFile Returns a pointer to the desired CFile object.ReleaseFile Releases a file to make it available for use by other applications.SaveModified Advanced overridable; called to ask the user whether the document should be saved.PreCloseFrame Called before the frame window is closed.Mail FunctionsOnFileSendMail Sends a mail message with the document attached.OnUpdateFileSendMail Enables the Send Mail command if mail support is present.

SINIF ÇALIŞMASI:View penceresinde click yapıldığında daireler çizen uygulamayı disk kısmı olmadan document view mimarisi içinde yazınız. Açıklamalar

Dairenin bilgileri CObject sınıfından türerilen CCircle sınıfı ile temsil edilecektir. Sınıfın veri elemanları şöyledir;

int m_cx;int m_cy;int m_r;COLORREF m_color;

Ayrıca CCircle sınıfının aşağıdaki gibi bir başlangıç fonksiyonu olmalıdır.

CCircle(int x, int y, int r, COLORREF color);

Sınıfın veri elemanları public bölümde tutulabilir.

Bütün çizilen daireler COblist türünden bir bağlı listede tutulacaktır. Bağlı liste Document sınıfının veri elemanı olmalıdır.

Fare ile click yapıldığında click mesajı View sınıfında işlenmeli hem çizim fare mesajında yapılmalı hem de çizim bilgisi Document sınıfının bağlı listesine eklenmelidir.

184

Page 185: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

View sınıfının WM_PAINT mesajında Document sınıfındaki bağlı liste izlenmeli ve bütün çizimler yeniden yapılmalıdır.

Dinamik tahsis edilen dairelerin program sonlandığında free hale getirilmesi sağlanmalıdır. Bağlı liste Document sınıfının veri elemanı olduğuna göre COblist sınıfının bitiş fonksiyonu bunu zaten otomatik olarak silecektir.

2002-04-17 Çarşamba

23.5 Document / View Yapısında Seri Hale Getrime İşlemleriDocument / View wizard’ın ürettiği kodda File – New, File – Open, File – Save As menü mesajları uygulama sınıfında işlenmiştir. Uygulama sınıfında bu menü mesajları karşılığında sırasıyla CWinApp::OnFileNew ve CWinApp::OnFileOpen fonksiyonları çağırılmıştır. Bu fonksiyonlar da CDocument sınıfının oluşturulan Document nesnesi ile OnNewDocument, OnOpenDocument sanal fonksiyonlarını çağırmaktadır.

File – New seçilince CWinApp::OnFileNew (virtual) CDocument::OnNewDocument

File – Open seçilince CWinApp::OnFileOpen (virtual) CDocument::OnOpenDocument

çağırılır.

Menüden bu seçenekler seçildiğinde önce standart Open ve Save As dialog pencereleri çıkar. File – New seçeneğinde bir şey çıkmaz. Menüden Open ya da New seçildiğinde framework yukarıda belirtilen sanal fonksionları çağırmanın yanı sıra CDocument sınıfının DeleteContents sanal fonksiyonunu da çağırır. Aslında DeleteContents fonksiyonu CDocument sınıfının OnNewDocument ve OnOpenDocument fonksiyonları tarafından çağırılmaktadır. Yani biz CDocument sınıfından türettiğimiz sınıfta bu sanal fonksiyonları yazarsak DeleteContents fonksiyonunun sanal fonksiyonlarını da bilinçli olarak çağırmalıyız.

CDocument::DeleteContents fonksiyonunda o zamana kadar biriktirilmiş olan bütün bilgiler geri boşaltılmalıdır. Örneğin bir bağlı liste varsa bütün elemanları boşaltılmalıdır. Çünkü DeleteContents fonksiyonunun çağırılması bu veri elemanlarına yeni değerlerin yükleneceği anlamına gelmektedir.

Open ve Save menü elemanları seçildiğinde framework tarafından CDocument::Serialize fonksiyonu çağırılmaktadır. Serialize fonksiyonundaki CArchive nesnesi seçilen dosya olacak biçimde framework tarafından oluşturulur. Open işleminde şüphesiz CArchive nesnesinin yönü dosyadan belleğe doğrudur. Save işleminde bunun tam tersidir. File – New seçildiğinde Serialize fonksiyonu çağırılmaz. Open işlemi sırasında önce DeleteContents sonra Serialize fonksiyonu çağırılmaktadır.

özetle;1. File – Open menüsü seçildiğinde sırasıyla önce

CDocument::DeleteContents ve sonra CDocument::Serialize fonksiyonu çağırılmaktadır.

Serialize işleminin yönü dosyadan belleğe doğrudur. 2. Menüden File – New seçildiğinde yalnızca

CDocument::DeleteContents çağırılır. Serialize fonksiynu çağırılmaz.3. File – Save As seçildiğinde yalnızca

CDocument::Serialize fonksiyonu çağırılır. DeleteContents fonksiyonu çağırılmaz.

185

Page 186: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

CDocument::DeleteContents fonksiyonunda ne yapılmalıdır? Öncelikle Document sınıfındaki veri elemanları boşaltılmalı, yapılan işlemler geri alınmalıdır. Tabi Document sınıfının veri elemanları boşaltıldıktan sonra View sınıflarının da bu işlemle birlikte iki şey yapması beklenir.

1. Görüntü tazelemesi yapılır. Aslında View sınıfındaki OnDraw fonksiyonunda biz zaten Document sınıfındaki veri elemanlarına bakarak çizimleri yapmışızdır. O veri elemanları boşaltıldığına göre artık çizim yapılmayacaktır. O halde görüntü tazelemesi için gereken tek şey View penceresi için WM_PAINT mesajının oluşturulmasıdır. O da InvalidateRect fonksiyonuyla yapılabilir.

2. View sınıfında çeşitli yardımcı veri elemanları tutulmuş olabilir. Document sınıfındaki veri elemanlarının silinmesi ile bunların da yeniden uygun ilk değerler alması gerekebilir.

İşte bu işlemler MFC tasarımcıları tarafından şu biçimde kolaylaştırılmıştır;

DeleteContents fonksiyonu, içinde programcı veri elemanlarını sildikten sonra CDocument::UpdateAllViews fonksiyonunu çağırır. CDocument::UpdateAllViews fonksiyonu bütün View’lar için CView::OnUpdate sanal fonksiyonunu çağırır.

Programcı CView::OnUpdate fonksiyonunda View sınıfının veri elemanlarına ilk değer verir ve InvalidateRect fonksiyonunu çağırır.

2002-04-18 Perşembe

CDocument::UpdateAllViews fonksiyounun prototipi şöyledir;

void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL);

Aslında UpdateAllViews fonksiyonu yalnızca Document sınıfından çağırılabilecek bir fonksiyon değildir. Bir Document’e ilişkin birden fazla View olabilmektedir ve bazen bir view sınıfı içinde bu fonksiyon çağırılabilir. Şöyle ki; Bir view üzerinde işlem yaparken zaten o view üzerinde çeşitli güncelleme işlemleri de yapılmış olur ve genellikle programcı Document verilerini oradan değiştirir. Diğer view’ların bu değişiklikten haberdar edilmesi için bu fonksiyonu çağırır. Zaten fonksiyonu çağıran view değişiklikler karşısında kendini düzeltmiştir. Yani OnUpdate fonksiyonunun kendi view sınıfı için çağırılması bazen istenmeyebilir. İşte fonksiyonun birinci parametresi NULL yerine herhangi bir view sınıfının adresi biçiminde geçilirse o sınıf dışındaki bütün view sınıfları için OnUpdate fonksiyonu çağırılır. Örneğin;

UpdateAllViews(this);dersek this ile belirtilen view sınıfı için OnUpdate çağırılmaz.

Birinci parametre NULL geçilirse OnUpdate fonksiyonu tüm view’lar için çağırılır.

Fonksiyonun diğer iki parametresi belirli bir anlamı olmayan parametrelerdir. Programcı bu parametreler yoluyla view sınıfına çeşitli yardımcı bilgileri yollayabilir.

CView::OnUpdate fonksiyonunun prototipi şöyledir;

virtual void CView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);Fonksiyonun parametreleri tamamen UpdateAllViews fonksiyonuna geçirilen parametrelerdir.

23.6 CView::OnInitialUpdate FonksiyonuBu fonksiyon CView sınıfının sanal bir fonksiyonudur. Document/View yapısı ilk kurulduğunda yani View Document sınıfı ile ilişkilendirildiğinde yalnızca bir kez çağırılır. Bu fonksiyon tıpkı OnInitDialog fonksiyonunda olduğu gibi View sınıfı için ilk çağırılan fonksiyondur. Sanal bir fonksiyon olduğu için View sınıfından türettiğimiz sınıf için bu fonksiyonu çağırırsak bizimki çağırılacaktır. (Zaten türemiş sınıf için wizard bu fonksiyonu yazmaktadır.) Biz bu fonksiyonu yazıyorsak taban sınıf olan CView sınıfının OnInitialUpdate fonksiyonunu bilinçli olarak çağırmalıyız. CView sınıfnının OnInitialUpdate fonksiyonu default olarak OnUpdate sanal

186

Page 187: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

fonksiyonunu çağırmaktadır. Yani OnUpdate fonksiyonu Document/View mimarisi içeren bir program ilk çalıştırıldığında her view için bu yolla çağırılmaktadır. OnInitialUpdate fonksiyonu ile türetilen view sınıfının başlangıç fonksiyonları işlevsel olarak aynı önemde midir? Hayır. Başlangıç fonksiyonu içinde henüz view Document sınıfı ile ilişkilendirilmemiş olduğu için GetDocument fonksiyonunu kullanamayız.

ÖDEV :Aşağıda açıklanan Paint benzeri çizim programı yazınız.

1. Program bir toolbar üzerinde çizgi, daire, dörtgen şekillerini barındırsın

2. Kullanıcının toolbara tıklaması ve sürükle bırak tekniği ile çizim yapılacaktır.

3. Şekillerin renkleri toolbar’a eklenmiş bir renk butonu ile tespit edilecektir. Bu renk elips ve kare için iç bölge rengi, çizgi için çizgi rengi anlamına gelecektir.

4. Elips ve dikdörtgenin içine, çizginin ise üzerine tıklandığında şekiller seçilecektir. Seçilen şekiller klavyede DEL tuşuna basılarak menü yoluyla silinebilecektir. Şeklin seçildiğini anlatabilmek için şeklin belirli yerlerine küçük kutucuklar konulmalıdır.

5. Program tamamen nesneye yönelimli bir sistemle tasarlanacaktır. CObject sınıfından türetilmiş CShape isimli bir sınıf diğer şekillere taban sınıflık yapacaktır. CShape sınıfının en az iki sanal fonksiyonu olmalıdır. Örn;

virtual void Draw(CDC* pDC, int x, int y);virtual BOOL IsInside(int x, int y);

6. Şekil sınıfları için Serialize fonksiyonu yazılmalıdır. Şekil sınıflarının hepsi SERIAL_ makrolarını içermelidir.

7. Program SDI olarak tasarlanacaktır.

8. Document sınıfında tüm şekilleri tutmak için COblist türünden bir bağlı liste veri elemanı alınacaktır. Bu bağlı listede heterojen şekillerin tutulduğu unutulmamalıdır.

9. Şekil sınıfları için kendi şekillerini tutacak veri elemanları alınmalıdır. Bu elemanlar serialize işlemi ile seri hale getirilmelidir. Her şekil sınıfı için Draw ve IsInside fonksiyonları yazılmalıdır. View sınıfının OnDraw fonksiyonu içinde Document sınıfındaki bağlı listeye erişilmeli ve bağlı listedeki elemanlar CShape* türüne dönüştürülüp Draw sanal fonksiyonları çağırılmalıdır.

10. View sınıfının fare tıklama mesajında Document sınıfındaki bağlı listeden faydalanılarak IsInside sanal fonksiyonları çağırılmalı ve noktanın bir şeklin içinde olup olmadığı tespit edilmelidir. Seçme işlemi için CShape sınıfına yeni bir sanal fonksiyon eklenmesi iyi bir çözümdür. Çünkü seçilen şekillerde nasıl kutucuklar çıkartılacağı şekillere özgüdür.

virtual void CShape::Select(void);11. Daha önce seçilmiş olan şeklin seçilmiş olma durumunun kalkması için de ayrı bir sanal

fonksiyon kullanılabilir. Tabi seçilmiş olan şeklin Document sınıfında bir biçimde belirlenmiş olmalıdır. Bu veri elemanı View sınıfına da yerleştirilebilir.

12. Document sınıfının DeleteContents fonksiyonu UpdateAllViews fonksiyonunu çağırır. View sınıfının OnUpdate fonksiyonunda gereken Reset işlemleri yapılır ve InvalidateRect uygulanır.

13. Toplam sistemin seri hale getirilmesi için yalnızca Document sınıfının Serialize fonksiyonunda bağlı liste için Serialize fonksiyonunun çağırılması yeterlidir. Zira COblist sınıfının Serialize fonksiyonu bütün bağlı liste elemanları için kendi Serialize fonksiyonlarını çağırmaktadır.

14. Şekil silme işlemlerinde silinen şekil bağlı listeden çıkartılırsa ve InvalidateRect uygulanırsa görüntü doğal olarak tazelenir.

187

Page 188: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

23.7 CDocument::SetModifiedFlag FonksiyonuDaha önce View üzerinde bir işlem yapıldıysa File – New ya da File – Open seçildiğinde son yapılan işlemlerin kaybedilmesi söz konusu olur. İşte bu fonksiyon böylesi bir durumda son yapılan işlemlerin kaydedilmesi ile ilgilidir. CDocument sınıfında private bir veri elemanı Document verileri üzerinde bir güncelleme yapılıp yapılmadığını tutar. Bu veri elemanının set ya da reset etmek için SetModifiedFlag fonksiyonu kullanılmaktadır.

void CDocument::SetModifiedFlag(BOOL bModified = TRUE);

Document nesnesi yaratıldığında flag default olarak FALSE değerindedir. Yani Document sınıfının veri elemanları güncellenmemiş durumdadır. Programcı Document sınıfı üzerinde bir güncelleme yaptığında bu fonksiyonu TRUE değeri ile çağırarak Docuıment verilerinin güncellendiğini belirtir. Bundan sonra File – New ve File – Open seçildiğinde framework otomatik olarak bu flag’e bakacak ve bir uyarı dialog penceresi çıkaracaktır. Bu dialog penceresinde kaydedilmemiş verilerin olduğu ve bunların kaydedilip edilmeyeceği sorulmaktadır.

Eğer kullanıcı burada keydedilsin seçeneğini seçerse framework Open ya da New işleminden önce bellekten diske Serialize işlemi yapacaktır.

SetModifiedFlag fonksiyonu nerelerde çağırılmalıdır? Her güncelleme yapıldğında TRUE parametresi ile güncellemenin yapıldığı yerde, kaydetme işlemi yapıldığında framework tarafından otomatik olarak FALSE haline getirilir.

23.8 Özel View Sınıflarıyla İşlemlerNormal olarak View sınıfı wizard tarafından CView sınıfından türetilmiş bir sınıf biçiminde alınır. MFC’de bir takım işlemlere kolayalık sağlamak amacıyla CView sınıfından türetilmiş bir grup özel view sınıfı tanımlanmıştır. Wizard işleminin son aşamasında wizard View sınıfının hangi sınıftan türetileceğini sormaktadır. Bu sınıf default olarak CView sınıfıdır. (Wizard’da yapmadıysak sonra kodlarda taban sınıfı elle değiştirebiliriz.)

23.9 FormView İşlemleriFormView kullanabilmek için view sınıfının CView sınıfından değil CFormView sınıfından türetilmesi gerekir. FormView uygulamasında view penceresi normal bir alt pencere değil modeless bir dialog penceresidir. Bu modeless diallog penceresi frame penceresinin çalışma alanını tamamen kaplamış durumdadır. (Modal olsa mesaj işleme gibi başka işlemler yapılamaz öylece kalırdı.) Frame penceresinin modeless bir dialog pencere ile örtülmüş olması şu kullanım olanaklarını getirir;

Bu modeless dialog penceresi için bir dialog kaynağı oluşturulmuştur. Bu durum bu dialog penceresi üzerine kolaylıkla kontrol yerleştirebileceğimiz anlamına gelir.

Çalışma alanı bir modeless dialog penceresi görünümünde olduğu için dialog pencerelerine özgü framework işlemleri devrededir. Örneğin DDX/DDV mekanizması kullanılabilir. Yani

188

Page 189: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

kontroller class wizardda veri elemanlarıyla eşleştirilip transfer için UpdateData fonksiyonu kullanılabilir.

Tıpkı dilog pencerelerinde olduğu gibi yaratılan dialog penceresi için OnInit fonksiyonu yazılabilir. Yine FormView sınıfı için OnInitialUpdate fonksiyonları aynı anlamda kullanılır.

SINIF ÇALIŞMASI :Birden fazla kişinin bilgilerini alıp görüntüleyen FormView uygulamasını yazınız. Açıklamalar;

1. Kişi bilgileri ad, soyad ve numaradan oluşmaktadır ve bu alanlar EditBox biçiminde FormView üzerine yerleştirilmelidir.

2. FormView üzerine şu PushButton’lar yerleştirilmelidir: İleri, Geri, Temizle ve Kaydet.

3. Şahıs bilgileri için CObject sınıfından türetilmiş bir CPerson sınıfı tanımlanmalı ve bu sınıf için SERIAL makroları yerleştirilmelidir. Bu sınıfın veri elemanları kişinin adı, soyadı ve numarası bilgilerini tutan nesneler olmalıdır. (CString’in kendi Serialize fonksiyonu vardır) Bu sınıf için Serialize fonksiyonları yazılmalıdır.

4. Yine Document sınıfında COblist türünden bütün kayıtları saklamak için bir bağlı liste elemanı tutulmalıdır. Toplam sistemin seri hale getirilmesi için bu veri elemanı ile Serialize fonksiyonunun çağırılması yeterlidir.

5. FormView sınıfında DDX/DDV işlemleri için ilişkilendirmekte kullanılacak veri elemanları alınır. Kayıt işlemi dinamik bir CPerson nesnesinin alınarak Document sınıfındaki bağlı listeye eklenmesi işlemidir.

6. İleri – Geri işlemleri için bağlı listedeki aktif POSITION bilgisinin tutulması gerekir. Bağlı liste için GetNext ve GetPrev fonksiyonları kullanılabilir.

7. Diğer ayarlamalar yapılmalıdır. DeleteContents işleminde dinamik nesnelerin boşaltılması ve bağlı listenin tümden boşaltılması unutulmamalıdır.

2002-04-30 Salı

8. FormView dialogpenceresi oluştrulur.

9. CPerson sınıfı CObject sınfından türetilir. Bu sınıf için SERIAL makroları yazılır. Kişinin adı ve soyadı CString türünden veri elemanlarında no’su ise int türünden bir veri elemanında saklanabilir. Ayrıca CPerson sınıfı için de Serialize fonksiyonu yazılmalıdır.

10. Document sınıfında COblist türünden bir veri elemanı alınmalıdır ve document sınıfının Serialize fonksiyonu bağlı listeyi seri hale getirecek şekilde yazılmalıdır. Ayrıca listede seçilen aktif elemanı tutan POSITION türünden bir veri elemanı alınmalıdır.

11. Document sınıfnın DeleteContents fonksiyonu UpdateAllViews fonksiyonunu çağıracak biçimde yazılacaktır. Document sınıfına bir Person ekleyecek üye fonksiyon eklenmesi uygun olur. Tabi CPerson sınıfının uygun bir başlangıç fonksiyonu yazılmalıdır.

12. FormView sınıfında dialog penceresi kontrolleri DDX nesneleri ile ilişkilendirilmelşdir. Dialog penceresindeki bilgiler UpdateData fonksiyonu ile alınacak ve document sınıfındaki bağlı listeye eklenecektir.

13. FormView sınıfında OnUpdate fonksiyonu dialog penceresi kontrollerini boşaltmalıdır.

14. Document verilerinde herhangi bir değişiklik yapıldığında SetModifiedFlag fonksiyonu ile durum belirlenmelidir.

23.10ScrollView İşlemleriBilindiği gibi API düzeyinde pencerenin doğal scroll çubukları ya da kontrol biçimindeki scroll çubukları WM_HSCROLL ve WM_VSCROLL mesajlarını pencereye göndermektedir. Scroll işlemleri için programcı bu mesajları ele işler. Önce scrool çubukları üzerinde hangi işlemin yapıldığına bakar. Sonra scroll yürütecini (thumb) konumlandırır ve pencere içindeki görüntüyü uygun bir biçimde değiştirir. Görüldüğü gibi scroll işlemleri programcı tarafından yapılması

189

Page 190: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

gereken işlemlerdir. Scroll çubukları programcı tarafından SetScrollSize API fonksiyonuyla belirli bir uzunluk değeri ile belirlenir. Mesajlar yürütecin konumunu bu değerle orantılayarak vermektedir. (Biz bu değeri 100 vermişsek ve yürüteci ortaya getirirsek bize 50 biçiminde bir değer verilir.) En basit scroll işlemleri DC alanı sanki genişmiş gibi çizim yapılıp SetWindowOrg API fonksiyonu ile pencere orjininin değiştirilmesi yoluyla sağlanmaktadır. ScrollView isimli view sınıfı yukarıda anlatılan yöntemle yani SetWindowOrg fonksiyonunu kullanarak görüntünün scroll edilmesini kendisi sağlamaktadır. ScrollView kullanırken programcı önce scroll çubuklarının büyüklüğünü belirler. Sonra sanki DC alanı çok büyükmüş gibi yalnızca görünen kısma değil OnDraw fonksiyonu içinde her yere çizimi yapar. Sonra scroll çubukları kaydırıldığında scroll mesajları ScrollView sınıfı tarafından işlenir ve SetWindowOrg fonksiyonu ile DC’nin başlangıçta verilen uzunluğa bağlı orantısal bölümü görüntüye sokulur.

23.11ScrollView Kontrolünün KullanımıCSrollView kontrolünde önce view sınıfının OnInitialUpdate fonksiyonunda SetScrollSizes fonksiyonu ile scroll çubuğunun uzunluğu ve click parametreleri (arada bir yere ve oka click yapılınca ilerleme miktarları) belirlenir. Sonra OnDraw fonksiyonunda DC alanı sanki fonksiyonda belirlenmiş scroll çubuğu kadarmış gibi çizim yapılır.

void SetScrollSizes(int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault );Fonksiyonun ilk parametresi kullanılacak mapping mode’dur. (OnLButtonDown, Up gibi fonksiyonlara gönderilen koordinatlar piksel cinsindendir. Mapping mode ne olursa olsun değişmez. Mapping mode DC parametresidir. Ancak mesajlara geçirilen koordinat bilgileri ise pencerenin sol üst köşesine göre piksel olarak gönderilmektedir.) Fonksiyonun ikinci parametresinde yatay ve düşey scroll çubuklarının uzunlukları verilir. Fonksiyonun üçüncü ve dördüncü parametreleri yürüteç aralarına ve scroll oklarına click yapıldığındaki artım miktarlarıdır. Wizard OnInitialUpdate fonksiyonu içinde bu fonksiyon çağırılmış biçimde kod üretmektedir.

SINIF ÇALIŞMASI :Bir ScrollView uygulaması oluşturunuz. OnDraw fonksiyonu içinde TextOut fonksiyonu ile satır satır birden bine kadar sayıları yazınız. Bir satırın yüksekliğini GetTextMetrics fonksiyonuyla alınız(height ve linespacing’i toplayarak bir satırın yüksekliği bulunabilir). Düşey scroll çubuğunun uzunluğunu satır yüksekliği * 1000 olarak alınız. Mapping mode MM_TEXT olarak alınacaktır. Yazılan proje Scroll içinde mevcuttur.

void CMyScrollView::OnDraw(CDC* pDC){

CScrollDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCString str;

for(int i = 1; i < 1001; ++i){str.Format("%d", i);pDC->TextOut(0, m_lineHeight * (i - 1), str);

}}

void CMyScrollView::OnInitialUpdate(){

CScrollView::OnInitialUpdate();

CDC *pDC = GetDC();TEXTMETRIC textMetrics;pDC->GetTextMetrics(&textMetrics);

190

Page 191: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

m_lineHeight = (textMetrics.tmHeight + textMetrics.tmExternalLeading);m_sizeTotal.cx = m_sizeTotal.cy = m_lineHeight * 1000;RECT rect;GetClientRect(&rect);SetScrollSizes(MM_TEXT, m_sizeTotal );

// CSize(rect.bottom - rect.top, rect.right - rect.left), // CSize(m_lineHeight, m_lineHeight)

}void CMyScrollView::OnSize(UINT nType, int cx, int cy) {

CScrollView::OnSize(nType, cx, cy);

// TODO: Add your message handler code hereif(m_sizeTotal.cx > 0) {

RECT rect;GetClientRect(&rect);SetScrollSizes(MM_TEXT, m_sizeTotal, CSize(cx, cy), CSize(m_lineHeight, m_lineHeight));

}}Bilindiği gibi fare mesajlarında geçirilen koordinat parametreleri mapping mode ve Window orjini ile ilgili değildir. Bu mesajlardaki koordinatlar her zaman çalışma alanı orjinli ve piksel koordinatlardır. SetScrollSizes fonksiyonunda belirtilen mapping mode OnPrepareDC sanal fonksiyonu tarafından hazırlanmaktadır. ScrollView uygulamalarında OnDraw fonksiyonlarının dışında çizim yapılacaksa (örneğin WM_MOUSEMOVE mesajında) CClientDC sınıfı ile DC alındıktan sonra SetScrollSizes fonksiyonunda belirtilen mapping mode’a geçilebilmesi için OnPrepareDC’nin çağırılması gerekir. Scroll edilmiş bir pencerede çalışma alanı orjinli noktanın mapping mode ve pencere orjini dikkate alınarak dönüştürülmesi DPToLP(device units into logical units) API fonksiyonu ile yapılmaktadır. Bu fonksion CDC sınıfının üye fonksiyonu biçiminde MFC’de bulunmaktadır. Sonuç olarak OnDraw fonksiyonunun dışında alınan bir noktanın yarattığımız bir DC’deki yeri bu fonksiyona sokularak tespit edilmelidir.

23.12CEditView Aslında herhangi kontrol bir view haline getirilebilir. Bunun için CView sınıfından türetilmiş CCtrlView sınıfı kullanılır. Bir kontrolü view olarak kullanmak için CCtrlView sınıfından bir sınıf türetmek ve bu sınıf içinde kontrolü yaratmak gerekir. Kontrolün doküman penceresinin çalışma alanını kaplaması otomatik olarak yapılmaktadır.

CEditView ve CRichEditView kontrolleri de CCtrlView sınıfından türetilmiş bu çeşit kontrollerdir. Bir kontrole ilişkin view oluşturmak için şunlar yapılmalıdır;

1. CCtrlView sınıfından bir sınıf türetilir. Bu sınıfın DYNCREATE makrolarını içermesi gerekir.

2. Türettiğimiz sınıfın başlangıç fonksiyonunda : syntax’ı ile taban sınıf olan CCtrlView sınıfının başlangıç fonksiyonu çağırılır. CCtrlView sınıfının başlangıç fonksiyonu yaratılacak olan kontrolün sınıf ismini parametre olarak almaktadır.

3. OnInitialUpdate fonksiyonunda view daha görüntülenmeden önce kontrol üzerinde ilk bir takım işlemler yapılabilir.

CEditView ve CRichEditView yukarıda anlatılan biçimde yazılarak framework içine yerleştirilmiştir. Wizard’dan view sınıfı olarak CEditView seçildiğinde CCtrlView sınıfından türetilmiş olan CEditView sınıfından bir sınıf türetir.

CWnd CView CCtrlView CEditView WizardSınıfı

Sonuç olarak CEDitView kullanılarak bir Document/View uygulaması oluşturulursa Document penceresinin çalışma alanı bir Edit kontrolü ile kaplanmış olur. Wizard’ın ürettiği kodda CDocument s ınıfından türetilen sınıfın Serialize fonksiyonu içinde CEditView sınfının SerializeRaw fonksiyonu çağırılmıştır. SerializeRaw fonksiyonu Edit kontrolü iindeki bilgiyi diske yazıp okumak için tasarlanmıştır. Sonuç olarak CEditView uygulaması adeta bir text editör

191

Page 192: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

oluşturmaktadır. Programcı bir text editör oluşturmak isterse bu view sınıfından hareket ederek işlemlerini yapabilir.

CEditView sınıfının Find ve Replace gibi işlemler için çeşitli üye fonksyonları vardır. Örneğin sınıfın SetTabStops fonksiyonu tab aralığını belirlemek için kullanılabilir. CEditView sınıfının GetEditCtrl isimli üye fonksiyonu çalışma alanını kaplayan nesneye ilişkin CEdit nesnesini verir.

CEdit& CEditView::GetEditCtrl()const;

192

Page 193: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

24 MDI DOCUMENT/VIEW UYGULAMALARIMFC’de View kavramı içeren dört tür wizard vardır.

1. Document/View mimarisi içermeyen single document uygulamalar. Bu uygulamalarda CFrameWnd sınıfından türetilmiş bir frame sınıfı bir de CWnd sınfından türetilmiş bir View sınıfı vardır. (Herşey View’da yapılır.)

2. Document/View mimarisi içermeyen MDI uygulamaları. Bu uygulamalarda CMDIFrameWnd sınıfından türetilmiş bir frame sınıfı, Document pencerelerini temsil eden CMDIChildWnd sınıfından türetilmiş bir sınıf bir de CWnd sınıfından türetilmiş bir View sınıfı vardır. Bu uygulamalarda her document penceresi yaratıldığında dinamik olarak yeni bir CMDIChildWnd ve CView nesneleri yaratılmaktadır. Dolayısıyla bu tür uygulamalarda biz View sınıfı içinde bir veri elemanı aldığımız zaman her document penceresi içinde bunun farklı kopyaları üzerinde çalışıyor oluruz.

3. Document/View mimarisi içeren single document uygulamalar. Bu uygulamalarda CDocument sınıfından türetilmiş bir document sınıfı, CView sınıfından türetilmiş bir view sınıfı vardır. Yine frame penceresi CFrameWnd sınıfından türetilmiş bir sınıfla temsil edilir. Bu uygulamlarda programın verileri document sınıfında saklanarak seri hale getirme özelliğinden faydalanılır.

4. Document/View mimarisi içeren MDI uygulamaları. Bum tür uygulamlarda hem Document/View mimarisi uygulanmaktadır hem de MDI özelliği kullanılmaktadır. Bu tür uygulamalar framework’un en geniş kullanıldığı uygulamalardır. Document/View mimarisi içeren MDI uygulamlarında şu sınıflar söz konusudur:

CMDIFrameWnd sınıfından türetilmiş bir frame sınıfı

Document pencerelerini temsil eden CMDIChildWnd sınfından türetilmiş bir sınıf.

Her Document penceresinin çalışma alanını kaplayan CView sınıfından türetiliş bir sınıf.

CDocument sınıfından türetilmiş Document sınıfı.

Bu tür uygulamalarda yeni bir Document penceresi yaratıldığında dinamik olarak şu sınıf nesneleri yaratılmaktadır.

1. CMDIChildWnd sınıfından türetilmiş sınıf türünden,

2. Cview sınıfından türetilmiş sınıf türünden

3. CDocument sınıfından türetilmiş sınıf türünden

Bu tür uygulamalarda her doküman penceresi için ayrı bir Viewe Document nesnesi yaratıldığı için ayrı veriler üzerinde işlemler yapılmaktadır. Aslında bu tür uygulamlara Document/View mimarisi içeren single document uyglamlarında farklı değildir. Bu tür uygulamaların önemli noktaları şunlardır;

Her yeni document penceresi yaratıldığında (Open ya da New seçeneği ile) o document penceresinin View pencersi için OnInitialUpdate fonksiyonu çağırılır.

DeleteContents fonksiyonu program çalıştırıldığında default olark açılan yeni document penceresi için (ilk document zaten File – New ile aynı biçimde açılır), File – New seçildiğinde, File – Open ile yeni bir document yaratıldığında, document penceresi kapatıldığında, program sonlandığında her bir document penceresi için otomatik olarak çağırılmaktadır.

MDI uygulamalarında Serialize fonksiyonu File – Open, File – Save, File – Save As seçildiğinde çağırılır.

Strateji yine aynıdır yani document sınıfının DeleteContens fonksiyonu içinde UpdateAllViews uygulanır. Bu fonksiyon view sınıfları için OnUpdate fonksiyonlarının çağırılmasına sebep olur.

193

Page 194: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

OnUpdate içinde de pencere için InvalidateRect uygulanır. (CView sınıfının OnUpdate fonksiyonu tüm çalışma alanını InvalidateRect yapmaktadır.)

SINIF ÇALIŞMASI :Çalışma alanına click yapıldığında belirlenmiş bir yarıçapta ve renkte daireler çizen uygulamayı Document/View mimarisini kullanarak MDI biçiminde yazınız. Açıklamalar;

1. CObject sınıfından CCircle sınıfı türetilir. Bu sınıf için SERIALIZE makroları yazılır. Sınıfın sadece merke zkoordinatlarını tutan veri elemanlarının olması yeterlidir.

2. CCircle için Serialize fonksiyonu yazılır.

3. Document sınıfında bir bağlı liste alınır ve document sınıfı için Serialize fonksiyonu yazılır.

4. Document sınfında DeleteContents fonksiyonu içinde bağlı liste boşaltılır ve UpdateAllViews fonksiyonu çağırılır.

5. View sınfının OnUpdate fonksiyonu içinde InvalidateRect uygulanır ya da taban sınıfın OnUpdate fonksiyonu çağırılır.

6. View sınıfında WM_LBUTTONDOWN mesajı işlenir. Daire çizilerek document sınıfının bağlı listesie eklenir.

7. View sınıfının OnDraw fonksiyonu içinde document sınıfındaki bağlı liste izlenerek tüm daireler çizilir. (mdicircle projesi içinde)

void CMdicircleView::OnDraw(CDC* pDC){

CMdicircleDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);POSITION pos = pDoc->m_olCircle.GetHeadPosition();

CCircle *cr;while (pos) {

cr = (CCircle *)pDoc->m_olCircle.GetNext(pos);pDC->Ellipse(cr->m_cx - 10,

cr->m_cy -10, cr->m_cx + 10, cr->m_cy + 10);}

}void CMdicircleView::OnLButtonDown(UINT nFlags, CPoint point) {

CMdicircleDoc *pDoc = GetDocument();

CCircle *circle = new CCircle();circle->m_cx = point.x;circle->m_cy = point.y;

194

Page 195: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

pDoc->m_olCircle.AddTail(circle);

CDC *pDC = GetDC();pDC->Ellipse(point.x - 10, point.y - 10, point.x + 10, point.y + 10);pDoc->SetModifiedFlag();CView::OnLButtonDown(nFlags, point);

}void CMdicircleDoc::DeleteContents() {

POSITION pos = m_olCircle.GetHeadPosition();

while (pos) delete (CCircle *)m_olCircle.GetNext(pos);

m_olCircle.RemoveAll();

UpdateAllViews(NULL);CDocument::DeleteContents();

}// Circle.h: interface for the CCircle class.class CCircle : public CObject {

DECLARE_SERIAL(CCircle)public:

void Serialize(CArchive &ar);int m_cy;int m_cx;CCircle();virtual ~CCircle();

};// Circle.cppIMPLEMENT_SERIAL(CCircle, CObject, VERSIONABLE_SCHEMA | 2 )void CCircle::Serialize(CArchive &ar){

if (ar.IsStoring())ar << m_cx << m_cy;

elsear >> m_cx >> m_cy;

}

07.05.2002 Salı

24.1 ProgressBar Kontrolü:ProgressBar Win32 ile birlikte eklenmiş olan gelişkin bir kontroldür. Diğer gelişkin kontrollerde olduğu gibi ProgressBar kontrolü de normal olarak CreateWindow fonksiyonu ile yaratılabilir. MFC’de ProgressBar kontrolü CProgressCtrl sınıfı ile temsil edilmiştir. ProgressBar bir dialog penceresi olarak da kullanılabilmektedir. (Bir kontrolün dialog penceresi kontrolü olması otomatik olarak dialog penceresi tarafından yaratıldığı anlamına gelir.)

ProgressBar kontrolü özellikle başlatılmış bir olayın ilerlemesini temsil etmek amacı ile tercih edilmektedir. CProgressCtrl sınıfının Create fonksiyonu şöyledir;

BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );

Pencere biçimi olarak WS_CHILD ve WS_VISIBLE kullanılmalıdır. Bunların dışında PBS_VERTICAL ve PBS_SMOOTH pencere biçimleri de kullanılabilir. Default olarak ProgressBar yatay ve parçalı ilerlemeye sahiptir. Bu pencere biçimleri düşey ve / veya sürekli ilerleme sağlamak için kullanılmaktadır.

ProgressBar için tıpkı scroll çubuklarında olduğu gibi minimum ve maksimum bir aralık belirlenir. Aralık belirlemesi yapılmazsa minimum 0 maximum 100 default değerlerdir. Aralık belirleme işlemi sınıfın SetRange ya da SetRange32 fonksiyonları ile yapılır. Eğer ProgressBar dialog kontrolü olarak yaratılmışsa WM_INITDIALOG mesajında bu fonksiyonlar ile sınır belirlemesi yapılabilir. Aralık belirtildikten sonra sınıfın SetPos fonksiyonu ile kontrolün içi istenilen bir pozisyona kadar doldurulabilir.

195

Page 196: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

for (int i = 0; i < MAX; ++i) {m_progressBar.SetPos(i);::Sleep(100);

}

Sınıf Çalışması:Dialog tabanlı bir uygulama yazınız. Dialog penceresinin içerisine bir ProgressBar yerleştiriniz. “Ok” ve “Cancel” tuşunun dışında bir “Start” tuşu ekleyiniz. Start tuşuna basıldığında ProgressBar’ı küçük bir sleep faktörü uygulayarak yavaş yavaş ilerletiniz.

Açıklamalar:

Kontrol GetDlgItem fonksiyonu ile ID’si verilerek alınmak yerine DDX / DDV mekanizması ile CProgressCtrl türünden bir sınıf nesnesi ile ilişkilendirilebilir.

Sınıfın OffsetPos fonksiyonu parametresi ile belirtlen yerden doldurum yapar. İlerlemesinin bir üçüncü yolu sınıfın SetStep fonksiyonu ile bir adım aralığının belirlenmesi ve döngü içerisinde StepIt fonksiyonunun çağrılmasıdır.

m_progressBar.SetStep(10);

for (int i = 0; i < MAX; ++i) {m_progressBar.StepIt();::Sleep(100);

}

ProgressBar arka planda bir takım işlemlerin devam ettiğini göstermek amacı ile kullanılır. Eğer bir thread mekanizması kurulmazsa devam etmekte olan ProgressBar işlemini kesmek mümkün olmaz. Bu nedenle ProgressBar işlemleri genellikle threadler ile yapılmaktadır.

Bu tür kontroller ile multithread uygulama oluştururken “deadlock” durumununa dikkat edilmelidir. Deadlock durumu özellikle thread’i yaratan thread’in yarattığı thread’in sonlanmasını beklerken diğer thread’in de bekleyen thread’e SendMessage ile mesaj gönderdiği karmaşık durumlarda oluşur. Prensip olarak bir thread’in başka bir thread’in yarattığı pencereye SendMessage ile mesaj göndermesi durumundan kaçınılmalıdır. SendMessage yerine PostMessage kullanılması çoğu kez problemi çözer. Yani ProgressBar işlemlerini yapmak üzere yaratılmış thread ProgressBar işlemini ProgressBar’ı yaratan thread’e bırakmalıdır. Yaratılan thread her adımda yanlızca ProgressBar’ı yaratan thread’e PostMessage ile bir WM_USER mesajı gönderebilir ve böylece ProgressBar’ın ilerletilmesini ProgressBar’ı yaratan thread’i yapabilir.

Sınıf Çalışması :ProgressBar işlemlerini yapan thread’li uygulamayı yapan thread’li uygulamayı aşağıda belirtildiği gibi oluşturunuz.

Program ana pencere içerecek. Menüden seçim yapıldığında bir dialog penceresi açılacaktır.

Dialog penceresinin üzerinde “Ok”, “Start” ve “Stop” tuşları ve bir ProgressBar kontrolü bulunacaktır.

Start tuşuna basıldığında bir worker thread yaratılacak ve ProgressBar ilerlemeye başlayacaktır.

Stop tuşuna basıldığında ProgressBar hareketi duracaktır.

196

Page 197: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Ok tuşuna basılınca dialog penceresi kapanacaktır.

Açıklamalar:Start tuşuna basıldığında bir flag set edilerek worker thread yaratılacaktır.

Worker thread içerisinde bir döngü olacak bu döngü her dönüşte PostMessage ile ana thread’e ProgressBar’ın konumunu belirten WM_USER mesajı göndericek.

Stop tuşuna basıldığında flag reset edilecek ve worker thread’in kendisini sonlandırması sağlanacaktır.

“Ok” tuşuna basıldığında flag reset edilecek her ne kadar problem oluşturmayacak olsa da WaitForSingleObject ile thread’in bitmesini beklemekte fayda vardır.

void CProgresDlg::OnButton1() {

if( !m_bStop ) return;m_pMyThread = AfxBeginThread( MyThreadProc, ( LPVOID ) this );m_bStop = FALSE;SetButtonsState();

}

LRESULT CProgresDlg::OnProgressArttir(WPARAM pos , LPARAM){

int k = (int)pos;m_progressCtrl.SetPos( k );

return TRUE;}

UINT CProgresDlg::MyThreadProc( LPVOID pParam ){

CProgresDlg * pDlg = ( CProgresDlg * ) pParam;ASSERT( pDlg );

for( int i = 0; i < 101; i++ ){

pDlg->PostMessage( WM_PROGRESS_ARTTIR, (WPARAM)i );::Sleep(50);if( pDlg->m_bStop ) return FALSE;

}pDlg->m_bStop = TRUE;pDlg->SetButtonsState();return TRUE;

}

void CProgresDlg::OnDestroy() {

m_bStop = TRUE;WaitForSingleObject( m_pMyThread->m_hThread, INFINITE );

CDialog::OnDestroy();

}

void CProgresDlg::OnButton2() {

m_bStop = TRUE;SetButtonsState();

}

void CProgresDlg::SetButtonsState(){

GetDlgItem( IDC_BUTTON1 )->EnableWindow( m_bStop );GetDlgItem( IDC_BUTTON2 )->EnableWindow( !m_bStop );

197

Page 198: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

GetDlgItem( IDOK )->EnableWindow( m_bStop );GetDlgItem( IDCANCEL )->EnableWindow( m_bStop );

}

24.2 Slider (TrackBar) Kontrolü:Slider özellikle video ya da müzik çalan programlarda çalınan medyada yer izlemesi yapmak amacı ile kullanılmaktadır. Aslında bu kontrol görüntü ve kullanım bakımından ScrollBar kontrolüne çok benzer ancak görüntü ve işlevsellik bakımından farklılıklar gösterir. Slider bağımsız olarak yaratılabileceği gibi bir dilaog kontrolü olarak da yaratılabilir. Slider işlemleri CSliderCtrl sınıfı ile temsil edilmektedir. Sınıfın Create üye fonksiyonu kontrolü yaratır. Create üye fonksiyonu diğer kontrol sınıflarında olduğu gibidir. Pencere yaratılırken WS_CHILD | WS_VISIBLE pencere biçimlerinin yanı sıra TBS_XXX biçiminde kontrole özgü pencere biçimleri de kullanılır. TBS_HORZ ve TBS_VERT yatay ya da düşey olma durumunu belirler. TBS_BOTTOM, TBS_TAB, TBS_RIGHT, TBS_LEFT, TBS_BOTH çiziklerin nasıl görüntüleneceğini belirtir. TBS_AUTOTICKS her bir birime bir çizik olacak biçimde çizikleri otomatik yerleştirir. Çizikler manuel olarak döngü içerisinde sınıfın SetTic üye fonksiyonuyla da set edilebilmektedir. Sliderda da bir aralık belirlemesi söz konusudur. Aralık belirlenmezse 0-100 arası default değer alır. Yürüteç aralarına click yapıldığında ya da klavye de ok tuşlarına basıldığında ne kadar ilerleme sağlanacağı sınıfın SetPageSize ve SetLineSize üye fonksiyonları ile belirlenir. Bu değerler dialog uygulamalarında WM_INITDIALOG mesajında belirlenebilir.

Slider tamamen scroll çubuklarında olduğu gibi WM_HSCROLL ve WM_VSCROLL mesajlarını üst pencereye göndermektedir. Bu mesajlar tamamen scroll çubuklarında olduğu gibi isimlendirilmiştir ancak SB_ yerine TB_ önekleri getirilmiştir. Herhangi bir zaman yürütecin konumu sınıfın GetPos fonksiyonu ile alınabilir. SetPos fonksiyonu ile set edilebilir. Dialog uygulamalarında Slider int türden bir nesne ya da CSliderCtrl sınıfı türünden bir nesne ile ilişkilendirilebilir. int nesne yürütecin konumunu temsil eder. Sınıfın SetTicFreq fonksiyonu n aralıkta bir çizik atmakta kullanılabilir.

Sınıf Çalışması:Dialog tabanlı bir uygulama yaratınız üzerine bir slider kontrolü yerleştiriniz. Kontrolün yukarısına bir static kontrol alınız. Yürüteci hareket ettirdikçe slider’ın durumunu SetWindowText fonksiyonu ile static kontrolde gösteriniz.

//sliderDlg.cpp

BOOL CSliderDlg::OnInitDialog(){

CDialog::OnInitDialog();m_slider.SetRange(0,1000);

return TRUE; // return TRUE unless you set the focus to a control}

void CSliderDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {

int i;switch (nSBCode) {case TB_THUMBTRACK:

i = m_slider.GetPos();m_static.Format("%d", i);

198

Page 199: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

UpdateData(FALSE);

}CDialog::OnHScroll(nSBCode, nPos, pScrollBar);

}

2002-05-09 Perşembe

24.3 Spinner KontrolüWin16 sistemlerinde spinner kontrolü standart olarak yoktu. Bu kontrol de Win32 sistemleri ile birlikte standart olarak eklenmiştir. Bu kontrol CSpinButtonCtrl sınıfı ile temsil edilir. Aslında spin kontrolü yalnızca ok şekillerinin bulunduğu bir kontroldür. Ancak tek başına kullanılmaz bir pencereye bağlanarak kullanılır. (Spinner kontrolü kendisine bağlı olan pencerenin içindeki rakamları arttırıp azaltmakta kullanılan bir kontroldür.) Spinner kontrolünün oklarına click yapıldığında rakamları, kendisine bağlı olan pencereye SetWindowText uygulayarak gösterir. Spinner kontrolüne tipik olarak edit kontrolü bağlanmaktadır. Spin kontrolü sınıfın Create fonksiyonu ile yaratılabilir ya da bir dialog kontrolü olarak görüntülenebilir.

BOOL CSpinButtonCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);

Pencere biçimi WS_CHILD | WS_VISIBLE’ın yanında UDS_XXX biçiminde spin kontrolüne ilişkin pencere biçimlerini de içerebilir. (UDS : UpDownStyle)UDS_HORZ Spin kontrolünün oklarını yatay yapar.UDS_WRAP Kontrol maksimum değerine gelince otomatik başlangıç değrine döner.UDS_ARROWKEYS Klavye odağı spin kontrolüne geçtiğinde klavye oklarının

kullanımına olanak sağlarUDS_AUTOBUDDY Özellikle dialog pencerelerinde kullanılır. Otomatik olarak Z order

(tab order) sırasına göre bir önceki pencere ile ilişkilendirmeyi sağlar.

UDS_ALIGNRIGHTUDS_ALIGNLEFT

Spin kontrolünün ilişkilendirileceği pencereye göre hizalama biçimini belirtir

UDS_SETBUDDYINT Bu pencere biçimi ok tuşalrına basıldığında otomatik olarak rakamların ilişkilendirilen pencerede çıkmasını sağlar. Eğer bu pencere biçimi eklenmezse rakamlar WM_NOTIFY mesajından faydalanılarak manual çıkartılır.

Construction CSpinButtonCtrl Class Members

CSpinButtonCtrl Constructs a CSpinButtonCtrl object.Create Creates a spin button control and attaches it to a CSpinButtonCtrl object.

AttributesSetAccel Sets the acceleration for a spin button control.GetAccel Retrieves acceleration information for a spin button control.SetBase Sets the base for a spin button control.GetBase Retrieves the current base for a spin button control.SetBuddy Sets the buddy window for a spin button control.GetBuddy Retrieves a pointer to the current buddy window.SetPos Sets the current position for the control.GetPos Retrieves the current position of a spin button control.SetRange Sets the upper and lower limits (range) for a spin button control.GetRange Retrieves the upper and lower limits (range) for a spin button control.SetRange32 Sets the 32-bit range for a spin button control.GetRange32 Retrieves the 32-bit range for a spin button control.

Spin kontrolü yaratıldıktan sonra sıra bir pencere ile ilişkilendirmeye gelir. İlişkilendirme sınıfın SetBuddy fonksiyonuyla yapılır.

CWnd* CSpinButtonCtrl::SetBuddy(CWnd* pWnd);

Tabi daha önce ilişkilendirilecek pencerenin yaratılması gerekir. Spin kontrol bir pencere ile ilişkilendirildiğinde otomatik olarak spin kontrolü pencerenin olduğu yere taşınır ve spin kontrol

199

Page 200: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

pencerenin alanı içinde görüntülenir. Eğer hizalama işlemi yapılmamışsa spin kontrolle ilişkilendirilen pencere yanyana getirilmez.

SINIF ÇALIŞMASI :Ana pencerenin üzerine bir edit kontrolü ve bir spin kontrolü yerleştiriniz. Edit kontrolünü spin kontrolü ile ilişkilendiriniz.

CRect’in en pratik kullanımlarından biri

CRect(CPoint(...), CSize(...))

biçimindedir. Böylece CSize ile belirlenen genişlik ve uzunluk hep korunur.

// spinnerView.h : interface of the CSpinnerView class

class CSpinnerView : public CView{public:

CEdit m_edit;CSpinButtonCtrl m_spinner;

// spinnerView.cppvoid CSpinnerView::OnInitialUpdate() {

CView::OnInitialUpdate();

m_edit.Create(WS_BORDER | WS_VISIBLE | WS_CHILD | ES_MULTILINE, CRect(CPoint(10,10), CSize(100,50)), this, 1);

m_spinner.Create(WS_VISIBLE | WS_CHILD | UDS_AUTOBUDDY | UDS_SETBUDDYINT | UDS_ALIGNLEFT,CRect(CPoint(30,30), CSize(30,30)), this, 2);

UDACCEL accel[] = { {0,5}, {2,10} };m_spinner.SetAccel(2, accel);

m_spinner.SetRange(0, 10000);m_spinner.SetBuddy(&m_edit);

}

Spinner’in min. ve max. değerleri default olarak 0 ve 100 biçimindedir. Sınıfın SetRange ya da SetRange32 fonksiyonları ile bu değerler ayarlanabilir. (Min. ve max. değerlerini yer değiştirerek hangi ok tuşuna basılınca arttırılacağı belirlenebilir.) Spin kontrolün asıl amacı belirlenen değeri almaktır. Sınıfın GetPos onksiyonu o anda spin kontrolünün değerini almakta, SetPos fonksiyonu da değer yerleştirmektedir.

Spin kontrolü genellikle dialog pencereleri üzerinde kullanılır. Bu durumda UDS_AUTOBUDDY pencere biçimi seçilmelidir. Spin kontrolü her zaman tab order sırasına öre her zaman bir önceki kontrolle ilişkilendirilmektedir.

SINIF ÇALIŞMASI :Bir dialog penceresi üzerine edit ve spin kontrollerini yerleştiriniz ve birbirine bağlayınız. OK tuşuna basıldığında spin kontrolünün değerini DialogBox ile gösteriniz. (OnInitDialog’da SetPos yapılırsa spin kontrolünün ilk değeri verilmiş olur ve uygulamanın başlangıcında o değer ile görüntülenir.)

Artım miktarının ayarlanması SetAccel fonksiyonu ile yapılmaktadır.

BOOL CSpinButtonCtrl::SetAccel(int nAccel, UDACCEL* pAccel);

UDACCEL her iki elemanı UINT olan bir yapıdır. Yani fonksiyon bizden UDACCEL isimli bir yapı dizisini içini doldurmamızı ve bu dizinin uzunluğu ile başlangıç adresini parametre olark

200

Page 201: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

aktarmamızı ister. UDACCEL yapısının birinci elemanı saniye cinsinden zamanı, ikinci elemanı artım miktarını göstermektedir. Örneğin

UDACCEL accel = {{0, 5}, {5, 10}};m_spin.SetAccel(2, accel);

Burada ilk 5 saniyeye kadar artırım 5’er 5’er sonra 10’ar 0’ar yapılmaktadır.

Spin kontrolü kullanılarak ondalıklı biçimde arttırma işlemi Spin kontrolünün NOTIFY mesjlarından faydalanarak programlama yoluyla yapılmaktadır.

24.4 IP KontrolüIP kontrolü çok basit bir kontroldür. Tek yaptığı şey 4 byte’lık IP adresini bir edit kontrolü içine almaktır. Kontrol pencerenin içinde 3 nokta oluşturur ve girişleri bu noktaların arasına yapar. İşlemler CIPAddressCtrl sınıfı ile temsil edilmiştir. Sınıfın SetAddress ve GetAddress fonksiyonları kontrolün içindeki değeri set etmek ve almak için, ClearAddress fonksiyonu içini silmek için IsBlank fonksiyonu herhangi bir adres girilip girilmediğini tespit etmek için kullanılır. Kontrol 4 bölgeden oluşmaktadır. Bölgeler 0, 1, 2, 3 biçiminde indekslenmiştir. SetFieldRange fonksiyonu ile istenilen bir bölge için min. ve max. değerleri belirlenebilir. Giriş eğer bu değerleri geçerse otomatik olarak min. ve max. değerlerine çekilir. Construction CIPAddressCtrl Class Members

CIPAddressCtrl Constructs a CIPAddressCtrl object.Create Creates an IP Address Control and attaches it to a CIPAddressCtrl object.AttributesIsBlank Determines if all fields in the IP Address Control are empty.ClearAddress Clears the contents of the IP Address Control. GetAddress Retrieves the address values for all four fields in the IP Address Control. SetAddress Sets the address values for all four fields in the IP Address Control. SetFieldFocus Sets the keyboard focus to the specified field in the IP Address Control. SetFieldRange Sets the range in the specified field in the IP Address Control

SINIF ÇALIŞMASI :Dialog penceresine bir IP kontrolü yerleştiriniz ve OK tuşuna basıldığında IP değerini görüntüleyiniz.

IP kontrolü ClassWizard aracılığıyla sınıf nesnesi ile ilişkilendirilebilmektdir. (MFC’de bir bug sonucu SetAddress ve GetAddress fonksiyonları CIPAddressCtrl’nin üye fonksiyonu olarak görünmüyor ama fonksiyonlar mevcut)

void CSpinner1Dlg::OnOK() {

BYTE ip1, ip2, ip3, ip4;CString str;

m_ipadress.GetAddress(ip1,ip2,ip3,ip4);

str.Format("%d.%d.%d.%d", ip1, ip2, ip3, ip4);MessageBox(str);

CDialog::OnOK();}

201

Page 202: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

24.5 AVI KontrolüBu kontrol .AVI uzantılı video klipleri oynatmak için kullanılır. Default olarak kontrol kendi içinde bir thread açarak .AVI formatını oynatmaktadır. Kontrol CAnimateCtrl sınıfı ile temsil eilmiştir. (Bu sınıf CWnd sınıfından türetilmiştir.) Soınıfın Create üye fonksiyonu ile bir pencere yaratılır, Open üye fonksiyonu ile parametresinde belirtilen AVI dosyası açılır ve kullanıma hazır hale getirilir. Sınıfın Play fonksiyonu ile klip yaratılan pencerede oynatılmaya başlanır. Play fonksiyonu kendi içinde thread açarak oynatmayı o thread’e bırakır. Stop üye fonksiyonu ile oynatma durdurulabilir. Sınıfın bitiş fonksiyonu açılan .AVI dosyasını otomatik olarak kapatmamaktadır. Kapatma işlemi Cose üye fonksiyonu ile yapılır. (MFC’de bu kontrol Animate olark görünmektedir.) Create fonksiyonunda WS_CHILD | WS_VISIBLE pencere biçimlerinin yanı sıra ACS_AUTOPLAY, ACS_CENTER, ACS_TRANSPARENT pencere biçimleri de kullanılabilir. Construction

CAnimateCtrl Constructs a CAnimateCtrl object.InitializationCreate Creates an animation control and attaches it to a CAnimateCtrl object.OperationsOpen Opens an AVI clip from a file or resource and displays the first frame. Play Plays the AVI clip without sound.Seek Displays a selected single frame of the AVI clip.Stop Stops playing the AVI clip.Close Closes the AVI clip that was previously opened

Sınıfın Play üye fonksiyonu şöyledir.

BOOL CAnimateCtrl::Play(UINT nFrom, UINT nTo, UINT nRepeat);

.AVI formatı frame’lerden oluşmaktadır. Fonksiyonun ilk iki parametresi hangi frame aralığının oynatılacağını belirtir. Bitiş frame’i değer ikinci parametrede –1 girilirse baştan sona oynatılır. Fonksiyonun on parmetresi kaç kere oynatılacağını belirlemede kullanılır. –1 değeri sürekli oynatma anlamındadır. Sürekli oynatma durumunda durdurma işlemi için Stop üye fonksiyonu kullanılmalıdır.

Windows’ta şöyle bir durum sözkonusudur. Biz bazı bilgileri EXE dosyanın içine gömmek istersek o bilgileri içeren dosyayı custom resource olarak tanımlayıp Windows EXE’sinin içine gömebiliriz. Open fonksiyounun ikinci biçimi işte bu şekilde bir EXE resource’u alarak çalışır. Yani AVI’yi EXE dosyanın içine gömebiliriz. .RC dosyaya elle

MYAVI AVI FileName

biçiminde de yazılabilir. Ya da resource Import ile AVI dosya import’ta edilebilir.

Sınıfın Open üye fonksiyonu şöyledir;

BOOL CAnimateCtrl::Open(LPCSTR lpszFileName);BOOL CAnimateCtrl::Open(UINT nID);

AVI kontrolü dialog penceresi kontrolü olarak da kullanılabilmektedir. Genellikle dilog pencersi açılır açılmaz görüntü başlar, kapatılınca sona erdirilir.

SINIF ÇALIŞMASI :AVI oynatan dialog tabanlı bir uygulama yazınız.

Kaynakta AVI kontrolü belirtilir ve CAnimateCtrl sınıfı türünden bir nesne ile ilişkilendirilir.

WM_INITDIALOG mesajında Open üye fonksiyonu ile .AVI dosyası açılır ve Play üye fonksiyonu ile oynatma başlatılır.

OK ya da Cancel tuşlarına basıldığında Stop üye fonksiyonu ile görüntü durdurulup Close ile kapatılır.

202

Page 203: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

// avikontrolDlg.cpp : implementation fileBOOL CAvikontrolDlg::OnInitDialog(){

CDialog::OnInitDialog();m_avikontrol.Open("Findfile.avi");return TRUE; // return TRUE unless you set the focus to a control

}void CAvikontrolDlg::OnCancel() {

m_avikontrol.Close();CDialog::OnCancel();

}

void CAvikontrolDlg::OnButtonStart() {

m_avikontrol.Play(0, -1,-1);}

void CAvikontrolDlg::OnButtonStop() {

m_avikontrol.Stop();}2002-05-16 Perşembe

24.6 Kontrol Sınıflarından TüretmeEdit kontrolünün istenildiği gibi değiştirilebilmesi, ListBox kontrolünün isteğe uygun biçimde davranış göstermesi gibi işlemler API düzeyinde pencere fonksiyonunun kancalanması ile (hooking – window subclassing) ile yapılmaktadır. Ancak MFC’de zaten pencere fonksiyonunun kancalanması framework tarafından yapılmıştır. Yani framework mesaj haritasında çağırılacak fonksiyon bulamazsa taban sınıfın mesaj haritalarını inceler orada da çağırılacak fonksiyon bulamazsa arka planda DefWindowProc API fonksiyonunu çağırır. Kontrol sınıflarında kontrollerin gerçek pencere fonksiyonlarının çağırılması kontrol sınıflarının üye fonksiyonlarını çağırmakla yapılır. Örneğin biz EditBox kontrolünü değiştireceksek CEdit sınıfından bir sınıf türetiriz. O sınıf için araya girme anlamında ilgili mesaj fonksiyonunu yazarız. Eğer EditBox kontrolünün orijinal pencere fonksiyonunu da çağırak istiyorsak taban sınıfın yani CEdit sınıfının aynı isimli fonksiyonunu çağırırız.

SINIF ÇALIŞMASI :Dialog tabanlı bir uygulamaya bir EditBox bir Add ve bir OK tuşu ekleyiniz. CListBox sınıfından bir sınıf türeterek o sınıf için AddString üye fonksiyonunu yazınız. Ancak bu üye fonksiyon içinde ListBox elemanlarının sayısını kontrol ediniz. En fazla 10 tane eleman eklenmesini sağlayınız.

SINIF ÇALIŞMASI :Ana pencerede bir EditBox kontrolü yaratınız. Bu EditBox kontrolünün yalnızca sayısal girişlere izin vermesini sağlayınız. Açılmalar;

CEdit sınıfından bir sınıf türetilir ve o sınıf için mesaj haritası kurulur. (Bu işlem wizard’dan kolaylıkla yapılabilir.)

Ana pencerenin WM_CREATE mesajında EditBox kontrolü türetilen sınıf nesnesi kullanılarak yaratılır.

203

Page 204: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Türetilen sınıf için WM_CHAR mesajı işlenir. Bu mesajda basılan tuş kontrol edilerek duruma göre yazması ya da yazmaması sağlanır. Yazmaması için taban sınıfın aynı isimli fonksiyonu çağırılmaz.

204

Page 205: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

int CEditTuretmeView::OnCreate(LPCREATESTRUCT lpCreateStruct) {

if (CView::OnCreate(lpCreateStruct) == -1)return -1;

m_pEdit = new CMyEdit;ASSERT( m_pEdit );

m_pEdit->Create( WS_CHILD | WS_VISIBLE |WS_BORDER,CRect( CPoint( 10, 10), CSize( 100, 30 )),this, 3);

return 0;}

void CMyEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) {

if( ( nChar >= 48 ) && ( nChar <= 58 ) ) CEdit::OnChar(nChar, nRepCnt, nFlags);

else AfxMessageBox("Yalnızca Rakam girebilirsin");}

24.7 ImageList KontrolüBir konuya ilişkin birden fazla bitmap görüntü ile çalışılacağı zaman bu işlemi görüntü ve çizim bakımından kolaylaştıran bir kontroldür. MFC’de CImageList sınıfı ile temsil edilir. Örneğin satranç taşlarının herbiri ImageList kontrolünde belirtilebilir. ImageList aslında tek bir .BMP dosyasından hareketle oluşturulur. Tıpkı toolbar kontrolünde olduğu gibi BMP içinde eşit genişlikte bölgeler tanımlanır. Programcı her bölgenin genişliği aynı olacak biçimde ayarlamayı yapmalıdır. Kontrol istenilen bölgeyi ekrana çizen Draw fonksiyonuna sahip olduğu için çok kullanışlıdır. ImageList API düzeyinde desteklenmeyen MFC sisteminin bir düzenlemesidir. ImageList için önce CImageList türünden bir nesne tanımlanır. Sonra sınıfın Create üye fonksiyonu çağırılır. Create üye fonksiyonu bitmap kaynağının ismini, bölge genişlik ve yüksekliklerini parametre olarak alır. Sınıfın beş tane Create fonksiyonu vardır. En tipik fonksiyon şudur;

BOOL CImageList::Create(int cx, int cy, UINT nFlag, int nInitial, int nGrow);

BOOL CImageList::Create(UINT nBitmapID, int cx, int nGrow, COLORREF crMask);nFlags ParametresiValue Meaning ILC_COLOR Use the default behavior if none of the other ILC_COLOR* flags is specified. Typically, the default is

ILC_COLOR4; but for older display drivers, the default is ILC_COLORDDB. ILC_COLOR4 Use a 4-bit (16 color) device-independent bitmap (DIB) section as the bitmap for the image list. ILC_COLOR8 Use an 8-bit DIB section. The colors used for the color table are the same colors as the halftone palette. ILC_COLOR16 Use a 16-bit (32/64k color) DIB section. ILC_COLOR24 Use a 24-bit DIB section. ILC_COLOR32 Use a 32-bit DIB section. ILC_COLORDDB Use a device-dependent bitmap. ILC_MASK Uses a mask. The image list contains two bitmaps, one of which is a monochrome bitmap used as a mask.

If this value is not included, the image list contains only one bitmap. Fonksiyondaki nBitmapID bitmap kaynağının ismidir. cx parametresi bir bölgenin genişliğini belirtir. nGrow parametresi büyütme miktarıdır. 1 olarak alınabilir. Fonksiyonun crMask parametresi CLR_NONE yapılabilir. Bu parametre zeminin mask edilmesi ile ilgilidir. Create fonksiyonu ile nesne yaratıldıktan sonra istenilen bölge Draw fonksiyonu ile çizilir.

BOOL CImageList::Draw(CDC* pDc, int nImage, POINT pt, UINT nStyle);

UINT nStyleValue MeaningILD_BLEND25, ILD_FOCUS Draws the image, blending 25 percent with the system highlight color. This value has no effect if

the image list does not contain a mask.ILD_BLEND50, ILD_SELECTED, ILD_BLEND

Draws the image, blending 50 percent with the system highlight color. This value has no effect if the image list does not contain a mask.

ILD_MASK Draws the mask.ILD_NORMAL Draws the image using the background color for the image list. If the background color is the

CLR_NONE value, the image is drawn transparently using the mask.ILD_TRANSPARENT Draws the image transparently using the mask, regardless of the background color.

205

Page 206: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

Fonksiyonun birinci parametresi DC, ikinci parametresi çizilecek bölge (bitmap’in eş parçalarından biri), üçüncüparametresi sol üst köşenin koordinatları, dördüncü parametresi zemin renklendirmesine ilişkin ILD_NORMAL ya da ILD_TRANSPARENT olabilir.

SINIF ÇALIŞMASI :Bir ImageList oluşturup çalışma alanını belirlenen bölgelerle doldurunuz. (MyImage projesi)

İmagelist oluşturulacak bmp aşağıdadır.(Create ile yaratılıp, Draw ile çizilmiştir)

// MyImageDlg.cpp : implementation file#include "stdafx.h"#include "MyImage.h"#include "MyImageDlg.h"

#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif

#define MY_TIMER 5// CMyImageDlg dialog

CMyImageDlg::CMyImageDlg(CWnd* pParent /*=NULL*/): CDialog(CMyImageDlg::IDD, pParent)

{//{{AFX_DATA_INIT(CMyImageDlg)

// NOTE: the ClassWizard will add member initialization here//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

if( !m_imageList.Create( IDB_BITMAP1, 53, 1, CLR_NONE ) ){

AfxMessageBox("Create Hatası");return;

}

m_x = 0;m_y = 0;

}void CMyImageDlg::OnButton1() {

CDC * pDC = GetDC();ASSERT( pDC );

static int k = 0;

m_imageList.Draw( pDC, k, CPoint(m_x, m_y), ILD_TRANSPARENT );k++;if( k == 7 ) k = 0;

Data Members CImageList Class Membersm_hImageList A handle containing the image list attached to this object.

206

Page 207: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

ConstructionCImageList Constructs a CImageList object.Create Initializes an image list and attaches it to a CImageList object.AttributesGetSafeHandle Retrieves m_hImageList.operator HIMAGELIST Returns the HIMAGELIST attached to the CImageList.FromHandle Returns a pointer to a CImageList object when given a handle to a device context. If a CImageList

object is not attached to the handle, a temporary CImageList object is created and attached.FromHandlePermanent Returns a pointer to a CImageList object when given a handle to an image list. If a CImageList object

is not attached to the handle, NULL is returned.DeleteTempMap Called by the CWinApp idle-time handler to delete any temporary CImageList object created by

FromHandle. GetImageCount Retrieves the number of images in an image list.SetBkColor Sets the background color for an image list.GetBkColor Retrieves the current background color for an image list.GetImageInfo Retrieves information about an image.OperationsAttach Attaches an image list to a CImageList object.Detach Detaches an image list object from a CImageList object and returns a handle to an image list.DeleteImageList Deletes an image list.SetImageCount Resets the count of images in an image list.Add Adds an image or images to an image list.Remove Removes an image from an image list.Replace Replaces an image in an image list with a new image.ExtractIcon Creates an icon based on an image and mask in an image list.Draw Draws the image that is being dragged during a drag-and-drop operation.SetOverlayImage Adds the zero-based index of an image to the list of images to be used as overlay masks.Copy Copies an image within a CImageList object.DrawIndirect Draws an image from an image list. SetDragCursorImage Creates a new drag image.GetDragImage Gets the temporary image list that is used for dragging.Read Reads an image list from an archive.Write Writes an image list to an archive.BeginDrag Begins dragging an image.DragEnter Locks updates during a drag operation and displays the drag image at a specified position.EndDrag Ends a drag operation.DragLeave Unlocks the window and hides the drag image so that the window can be updated.DragMove Moves the image that is being dragged during a drag-and-drop operation.DragShowNolock Shows or hides the drag image during a drag operation, without locking the window.

24.8 CComboBoxEx KontrolüElemanları hem şekil hem de yazı olan ComboBox kontrolüdür. Dialog penceresi elemanı olarak da kullanılbilmektedir. CComboBoxEx sınıfı CComboBox sınıfından türetilmiştir. Kontrol Create üye fonksiyonu ile yaratılır sınıfın SetImageList fonksiyon ile daha önce yaratılmış bir ImageList nesnesi sınıfa bağlanır. Sonra sınıfın InsertItem fonksiyonu ile elemanlar eklenir. CComboBox sınıfın taban sınıfı olduğu için CComboBox sınıfının fonksiyonları ile işlemler yürütülür.

BOOL CComboBoxEx::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);ComboBox yaratıldıktan sonra belirlenen bir ImageList nesnesi ComboBox ile ilişkilendirilir.

CImageList* CComboBoxEx::SetImageList(CImageList* pImageList);

int CComboBoxEx::InsertItem(const COMBOBOXEXITEM* pCBItem);COMBOBOXEXITEM yapısı doldurulur. Yapının mask elemanı tipik olarak CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_TEXT olarak set edilir. iItem elemanı insert edilecek ComboBox elemanını belirtmektedir. pszText elemanın yazısını belirtir. iImage elemanı ImageList’teki offset numarasıdır. iSelectedImage eleman seçildiğinde hangi ImageList elemanının görüntüleneceğini belirtir.

SINIF ÇALIŞMASI :Dialog tabanlı bir uygulama yazınız. Üzerine bir ComboBoxEx kontrolü yerleştiriniz. ABCDE yazılarıyla belirtilen ImageList görüntülerini kullanarak eleman insert ediniz. Bir eleman seçildiğinde de hani elemanın seçilmiş olduğunu yazınız. // DerivedListDlg.cppBOOL CDerivedListDlg::OnInitDialog()

207

Page 208: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

{CDialog::OnInitDialog();………………………..m_ctlcombolist.SetImageList(&m_Image);COMBOBOXEXITEM c;c.iImage = 1;c.pszText = "deneme";c.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_TEXT;char buf[512];for (int i = 0; i < 4; ++i) {

c.iImage = i;c.pszText = itoa(i, buf, 10);c.iItem = i;c.iSelectedImage = i + 4;m_ctlcombolist.InsertItem(&c);

}

return TRUE; // return TRUE unless you set the focus to a control}2002-05-28 Salı

208

Page 209: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

25 MFC EXCEPTION MEKANİZMASI

CException Class MembersCException Constructs a CException object.Delete Deletes a CException object.GetErrorMessage Retrieves the message describing an exception.ReportError Reports an error message in a message box to the user.

Genellikle sınıf kütüphanelereinde Exception işlemleri için bir sınıf sistemi kullanılır. Bunun iki sebebi vardır.

Bir türetme şeması içinde bir gruba ilişkin exception taban sınıfta yakalanabilir. Bütün exceptionları yakalamak için en tepedeki taban sınıf kullanılabilir.

Exception sınıfları hatanın nedenini tespit etmeye yarayacak pekçok veri elemanları ve üye fonksiyonlar içerebilir. Exception oluştuğunda sınıf nesnesi incelenerek analizler yapılabilir.

Bir sınıf nesnesi ile throw edileceği zaman üç seçenek sözkonusu olur.

throw ifadesinin parametresi sınıf nesnesinin kendisidir ve catch parametresi de catch parametresinin kendisidir.

1. Burada geçici bölge ve catch parametresi için copy constructor çağırılacaktır. C++’ın kuralına göre derleyici önce throw parametresi ile aynı türde static ömürlü (global düzeyde) geçici bir bölge tahsis eder. Bu static nesne yoluyla catch parametresine aktarım yapılır.

2. throw parametresi sınıf nesnesidir ancak cath’in parametresi referanstır. Bu durumda geçici bölge için kopya başlangıç fonksiyonu çağırılır. catch parametresi geçici bölgenin adresini tutar.

209

Page 210: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

3. throw parametresi sınıf nesnesinin adresidir. Bu durumda geçici bölge de gösterici olur. Dolayısıyla catch parametresi de gösterici olmalıdır. Burada iki şeye dikkat edilmelidir. throw nesnesi için tahsisat heap üzerinde dinamik olarak yapılmalıdır. İkincisi exception nesnesinin silinmesi catch bloğu içinde programcı tarafından yapılmalıdır. Bu teknik tercih edilen ve en etkin olan tekniktir.

MFC’de de sınıf nesnesinin adresi ile throw etme tekniği kullanılmıştır. MFC’de exception işlemleri için CException sınıfından türetilmiş olan bir sınıf sistemi kullanılmaktadır. Framework her zaman dinamik tahsis edilen nesnenin adresi ile throw ettiği için catch parametresi olarak her zaman bir gösterici yazılmalıdır.

C++’ta bir nesne kendi kendini yokedebilir. Örn;

X::Delete(){

//...this->~X(); // Destructor’u çağır

delete this; // Nesneyi yoket}Tabi bu noktadan sonra artık sınıfın hiçbir veri elemanı kullanılmamalıdır.

MFC’de catch bloğu içinde exception nesnesini silmek için doğrudan delete oparatörünü kullanmak yerine CException sınıfının Delete fonksiyonunu çağırmak gerekir. Çünkü bazen framework heap’te tahis ettiği dinamik nesnenin adresi ile değil global bir nesnenin adresi ile throw etmektedir. Delete fonksiyonu kendi içinde bu durmu sorgulayıp (heap check yaparak) ona göre uygun silme işlemini yapar.

Programcıisterse keni projesi için CException sınıfından sınıf türeterek yeni exception sınıfları tanımlayabilir ve işlemlerini genel eğilime uygun bir biçimde devam ettirebilir.

catch içinde sadece throw yazılırsa o catch’e gelen nesne aynen gönderilir. Daha dışta bir catch varsa oraya gönderilir.

210

Page 211: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

26 MFC ODBC İŞLEMLERİ

26.1 Veritabanlarına Erişim ve Veritabanı Yönetim Sistemleri

CDatabase Class MembersData Membersm_hdbc Open Database Connectivity (ODBC) connection handle to a data source. Type HDBC.ConstructionCDatabase Constructs a CDatabase object. You must initialize the object by calling OpenEx or Open.Open Establishes a connection to a data source (through an ODBC driver).OpenEx Establishes a connection to a data source (through an ODBC driver).Close Closes the data source connection.Database AttributesGetConnect Returns the ODBC connect string used to connect the CDatabase object to a data source.IsOpen Returns nonzero if the CDatabase object is currently connected to a data source.GetDatabaseName Returns the name of the database currently in use.CanUpdate Returns nonzero if the CDatabase object is updatable (not read-only).CanTransact Returns nonzero if the data source supports transactions.SetLoginTimeout Sets the number of seconds after which a data source connection attempt will time out.SetQueryTimeout Sets the number of seconds after which database query operations will time out. Affects all

subsequent recordset Open, AddNew, Edit, and Delete calls.GetBookmarkPersistence Identifies the operations through which bookmarks persist on recordset objects.GetCursorCommitBehavior Identifies the effect of committing a transaction on an open recordset object.GetCursorRollbackBehavior Identifies the effect of rolling back a transaction on an open recordset object.Database OperationsBeginTrans Starts a “transaction” — a series of reversible calls to the AddNew, Edit, Delete, and Update

member functions of class CRecordset — on the connected data source. The data source must support transactions for BeginTrans to have any effect.

BindParameters Allows you to bind parameters before calling CDatabase::ExecuteSQL.CommitTrans Completes a transaction begun by BeginTrans. Commands in the transaction that alter the

data source are carried out.Rollback Reverses changes made during the current transaction. The data source returns to its

previous state, as defined at the BeginTrans call, unaltered. Cancel Cancels an asynchronous operation or a process from a second thread.ExecuteSQL Executes an SQL statement. No data records are returned.Database OverridablesOnSetOptions Called by the framework to set standard connection options. The default implementation sets

the query timeout value. You can establish these options ahead of time by calling SetQueryTimeout.

Belirli formatta bilgilerin bulunduğu dosyalara veri tabanı denir. Veri tabanı işlemleri aslında aşağı seviyede algoritmik yöntemler kullanılarak yapılmaktadır. Popüler pek çok veri tabanında kullanılan en yaygın algoritmik yöntem B-Tree yöntemidir. Veri tabanlarına doğrudan erişmek ya da aşağı seviyeli kütüphaneler kullanarak erişmek hem zordur hem de bu tür erişimlerde veri dosyasının aşağı seviyeli özellikleri kullanıldığından veri dosyasındaki değişiklikler programcıyı büyük ölçüde etkiler. Veri dosyasındaki değişikliklerden ya da veri formatının çeşitliliğinden daha önce yazılmış olan kodların etkilenmemesi için ara bir katman düşünülmüştür. Bu ara katmanı sağlayan paketlere VTYS( veri tabanı yönetim sistemleri - Database Management Systems) denir. VTYS kullanıldığında genellikle artık işlemler yüksek seviyeli programlama dilleri ile değil bu paketlerin sunduğu araçlarla yapılır. Örneğin bu paketlerin çoğunda ekran tasarlamak, rapor hazırlamak ya da sorulama yapmak için araçlar bulunur. Veri tabanı programcıları genellikle kısmen ya da tamamen bu araçları kullanarak işlemlerini yaparlar. VTYS’lerin ortak olarak kullandığı SQL denilen çok yüksek seviyeli bir sorgulama dili de tanımlanmıştır. SQL standart bir yorumlama dilidir. SQL cümlecikleri VTYS’ler tarafından yorumlanır ve asıl işlem aşağı seviyeli C fonksiyonları ile arka planda yapılmaktadır.

211

Page 212: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

SQL VTYS Aşağı seviyeli fonksiyonlar Veri dosyaları

Orta seviyel ya da yüksek seviyeli programlama dillerinden VTYS’lere erişmek nasıl olur?

Eğer erişim bu veri tabanı yönetim sistemlerini kendi sürücüleri kullanılarak yapılırsa yazılan kodlar VTYS’ye bağımlı olur. İşte yazılan kodların VTYS’den de bağımsız olabilmesi için daha yüksek bir katman gerekmektedir. Microsoft ODBC (Open Database Connectivity) denilen katmanı bu nedenle tasarlamıştır. ODBC işlemleri ismine ODBC API’leri denilen fonksiyonlar ile aşağı seviyeli biçimde yapılabilir. ODBC API’leri HDBC türünden bir HANDLE alanı ile çalışır. ODBC işlemleri MFC’de CDatabase sınıfı ile temsil edilmiştir. Sınıfın HDBC türünden public veri elemanı ODBC bağlantısının HANDLE değerini tutar.

26.2 ODBC Sisteminin ÇalışmasıProgramcı ODBC kullanarak istediği bir veri tabanı yönetim sistemi ile bağlantı sağlar. Sonra standart API fonksiyonlarıyla SQL cümlecikleri gönderir. ODBC bu sorgulamaları VTYS’ye gönderir. Gerçek sorgulamayaı VTYS yapar. Sonuçları ODBC yoluyla programcıya iletir. ODBC VTYS’lerin ODBC sürücüleri ile bağlantı kurmaktadır. ODBC bir ilişkisel veri tabanı sistemidir. İlişkisel veri tabanları tablolardan oluşur. Tablolar da alan denilen sütunlardan ve kayıt denilen satırlardan oluşmaktadır. Programcı bir tabloda sorgulama yaparak çeşitli kayıtları bulabilir. Buradaki bilgilerden faydalanarak başka tablolara geçebilir. Tablolardaki sorgulama yapılan sütunlara anahtar alanlar denir. Sorgulama için tipik SELECT komutu

SELECT <sutunlar> FROM <tablo> WHERE <koşul>MFC’de ODBC işlemleri için CRecordset sınıfı kullanılır.

26.3 CRecordset Sınıfının KullanımıCRecordset sınıfının kullanımı oldukça kolaydır. Zaten wizard bu işlemlerin çoğunu programcı için yapar. Ana noktalar şunlardır;

1. Programcı CRecordset sınıfından bir sınıf türetir ve türettiği sınıfa sorgulama sonucundaki bilgilerin yerleştirileceği veri elemanlarını ekler. Örneğin bir tablodaki sorgulamadan Ad, Soyad ve No bilgileri elde edilecekse programcı bu bilgileri tutacak veri elemanları tanımlar. (Wizard CRecordset sınıfından bir sınıf türetileceği zaman veritabanının hangi tablosunun kullanılacağını sorar. O tablonun alanlarını inceleyerek sınıfın veri elemanlarını kendisi oluşturur.)

2. Programcı CRecordset sınıfının sanal DoFieldExchange fonksiyonunu yazar. Bu fonksiyon kayıtlar arasında ilerleme yapılırken framework tarafından çağırırlır. Bu fonksiyonun içinde RFX_ ile başlayan her veri elemanı için aktarım fonksiyonları çağırırlır. Veri elemanları ile kayıtlar arasındaki aktarım bu fonksiyonlar tarafından yapılmaktadır. (Tıpkı DoDataExcahange ve DDX_ fonksiyonlarında olduğu gibi) Wizard bu işlemi de kendisi otomatik olarak yapmaktadır. Yani CRecordset sınıfından bir sınıf türettiğimizde wizard DoFieldExcahange fonksiyonunu yazar ve fonksiyon içine RFX_ fonksiyonlarını yerleştirir.

Artık programcı sorgulama işlemini başlatabilir.

1. SELECT sorgulama cümlesinin koşul belirten WHERE kısmı CRecordset sınıfının m_strFilter elemanına yerleştirilir. (m_strFilter = “Name = ‘Kaan’”; Kaan’ın tek tırnak ile verildiğine dikkat!)

2. SELECT cümlesinin ORDER BY kısmı sınıfın m_strSort elemanıan yerleştirilir. Örn; m_strSort = “Name ASC”;

3. Bunlardan sonra önce CRecordset sınıfının Open üye fonksiyonu çağırılarak VTYS ile bağlantı sağlanır. Sonra döngü içinde MoveNext, MovePrev gibi fonksiyonlarla koşulu sağlayan tüm kayılar sırası ile lede edilir. Sorgulamanın sonuna gelinip gelinmediği sınıfın IsEOF fonksiyonu ile kontrol edilmelidir.

CMyRecordset set;

212

Page 213: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

if (!set.Open())returnwhile (!set.IsEOF()) {

//...set.MoveNext();

}set.Close();

4. CRecordset sınıfının koşulu sağlayan kayıtlar arasında gezinmeyi sağlayan çeşitli üye fonksiyonları verdır. Sorgulama bitince bağlantı Close üye fonksiyonu ile kapatılmalıdır.

26.4 Veri Kaynağının YaratılmasıODBC ile sorgulama işlemlerine başlamadan önce işletim sistemi seviyesinde bir veri kaynağının yaratılması gerekir. Veri kaynağının yaratılması aslında hangi VTYS ile hangi veritabanına erişileceğini belirlenmesi demektir. Aslında sistem bu belirlemeyi registry dosyasında saklamaktadır. Veri kaynağının yaratılması Kontrol Panel – ODBC menüsünden manual olarak yapılabildiği gibi ODBC API’leri ile programlama yoluyla da yapılabilmektdir. (Örneğin bir kurulum programı bu şekilde programlama yoluyla veri kaynağı yaratıp işlemlerini yapabilir.) Veri kaynağı yaratılırken bir isim verilir. Bu isim veri kaynağını temsil eder ve CRecordset sınıfında belirtilerek işlemler yürütülür. Tabi wizard CRecordset sınıfından sınıf türetirken hangi veri kaynağının kullanılacağını görsel bir biçimde sormakta ve belirleme işlemini kendisi yapmaktadır.

Örneğin bir Access veritabanı dosyasından bir sorgulama yapılacak olsun;

Kontrol Panel’den Access veritabanı ve .mdb dosyası seçilerek veri kaynağı oluşturulur.

MFC uygulaması kurulur.

CRecordset sınıfından bir sınıf wizard yoluyla türetilir.Wizard bu aşamada hangi veri kaynağını kullanacağımızı ve o veri tabanının hangi tablolarını kullanacağımızı sorar.

Wizard belirlenen tablodaki alanlar için uygun veri elemanlarını tanımlar ve DoFieldExchange fonksiyonunu uygun bir biçimde yazar.

Örneğin bir butona basınca koşulu sağlayan kayıtlar bir ListBox’a yerleştirilecek olsun. m_strFilter ve m_strSort elemanları uygun bir biçimde doldurulur ve yukarıda belirtilen döngü yoluyla kayıtlar tek tek ele geçirilir ve ListBox’a yerleştirilir.

2002-05-30 Perşembe

SINIF ÇALIŞMASI :Bir Access veritabanını kullanarak veri kaynağı oluşturunuz. Bir dialog penceresi üzerinde bir tuşa basıldığında veritaba içindeki kayıtları bir ListBox’a yerleştiriniz. Açıklamalar;

Program dialog tabanlı oluşturulacaktır. Dialog penceresi üzerinde ListBox, OK ve Get tuşları bulunacaktır.

Kontrol Panel – ODBC seçeneğinden bir Access veri kaynağı oluşturulur.

CRecordset sınıfından Class Wizard kullanılarak bir sınıf türetilir. Bu türetme sırasında Class Wizard hangi veri kaynağı ve tablonun kullanılacağını sorar.

Class Wizard seçilen veritabanındaki tabloya bakarak tablonun alanlarına ilişkin veri elemanları oluşturur ve bu veri elemanları için DoFieldExchange fonksiyonunu yazar. Eğer bazı sütunlar istenmiyorsa ClassWizard - Member Variables’dan ilgili veri elemanı silinir. Böylece Class Wizard iki yerden de silmeyi yapar.

Dialog penceresinde tuşa basıldığında önce CRecordset nesnesi kullanılarak Open işlemi yapılır. Sonra döngü içerisinde MoveNext fonksiyonlarıyla ilerlenir ve her kayıt listbox’a atanır.

213

Page 214: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

MFC’de veritabanı uygulama geliştirmek için New Project’te Database Support ekranında “Header Files Only” seçeneği işaretlenmelidir. Dialog tabanlı olursa bazı header dosyalar include edilmediği için veritabanı uygulaması sorunlu olmaktadır. // MyDialog.cppvoid CMyDialog::OnButton() {

CString str;CSet mySet;

// mySet.m_strFilter="PostaKodu = '98122'";mySet.Open();mySet.AddNew();mySet.m_Soyad = "Deneme";mySet.Update();mySet.Requery();

while(!mySet.IsEOF()){ str = mySet.m_Soyad + " " + mySet.m_Ad_; m_list.AddString(str); mySet.MoveNext();}

mySet.Close();}

Bütün ODBC ve DAO işlemlerinde Exception Handling mekanizması kullanılmıştır. Yani tüm veritabanı işlemlerinde bir problem oluştuğunda CDBException sınıfı ile throw edilir. Bu durumda veritabanı işlemlerinde try-catch bloğu kullanılmalıdır.

try {}

214

Page 215: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

catch(CDBException* pDBException) {MessageBox(pDBException->m_strError);pDBException->Delete();

}

26.5 CRecordset Sınıfının Önemli Üye fonksiyonlarıIsEOF fonksiyonu son kaydın okunmasından dolayı kayıt göstericisinin EOF durumunu belirtir. Son kayıt okunduktan sonra IsEOF sıfır dışı değer verir. İlk kayıttan MovePrev fonksiyonu ile ilk kayıttan bir geri gidilmeye çalışılırsa IsBOF sıfır dışı bir değer verir. Delete fonksiyonu o anda konumlandırılmış olan kaydı siler. Update fonksiyonu o an konumlanılmış olan kaydı siler. Kayıt eklemek için önce AddNew fonksiyonu çağırılarak hazırlık yapılmalıdır. Sonra veri elemanları doldurulup Update fonksiyonu çağırılmalıdır. Kayıt ekleme ve güncelleme işlemlerinden sonra sorgulamanın tazelenmesi için Requery fonksiyonunun çağırılması gerekebilir.

Sınıfın GetDefaultSQL sanal fonksiyonu bir CString nesnesine geri döner. Aslında mekanizma şöyledir; Open ve Requery fonksiyonları SELECT cümlesini oluşturmak için önce bu fonksiyonu çağırılar. Buradan aldıkları yazıya m_strFilter ve m_strSort veri elemanlarının içindekileri WHERE ve ORDER BY kısımları olarak SELECT cümlesine eklerler. Yani aslında bu iki veri elemanını boş tutup tüm SELECT cümlesini bu sanal fonksiyonla da belirleyebiliriz. (Hem veri elemanlarını hem de string’i değiştirirsek iki tane WHERE ya da ORDER BY belirlemesi olması gibi bir durum ortaya çıkabilir.)

26.6 CRecordView İşlemleriCRecordView Document/View mimarisinin bir View mimarisidir. Bu sınıf CFormView sınıfından türetilmiştir. CRecordView seçildiğinde wizard şunları yapar;

Wizard belirlenen tabloya uygun CRecordset sınıfını türetir.

Türettiği CRecordset sınıfı türünden bir nesneyi Document sınfının veri elemanı yapar.

View sınıfında bir gösterici tutar. OnInitialUpdate fonksiyonunda veri elemanının adresini bu göstericiye yazar.

Bu işlemden sonra programcı şunları yapmalıdır.

CRecordView sınıfının dialog penceresine alanlara ilişkin kontrolleri yerleştirir.

Bu kontrolleri Class Wizard – Member Variables menüsünü kullanarak Recordset göstericisi yardımıyla recordsetin elemanlarıyla ilişkilendirir.

Artık öyle bir mekanizma kurulmuş olur ki yukarıdaki toolbarda ileri geri işlemlerinde kayıtlar otomatik olarak hareket eder. Şüphesiz aslında toolbar tuşlarına basıldığında bu işlemler framework tarafından Document sınıfındaki nesne kullanılarak yapılır. Kayıtlar üzerinde yapılan değişiklikler otomatik update edilmektedir. Eğer programcı bu default özellikleri beğenmezse CRecordView sınıfının sanal OnMove fonksiyonunu işlemelidir.

SINIF ÇALIŞMASI :Bir Access veritabanının önemli elemanlarını CRecordView uygulaması ile view’ın dialog penceresi içinde gösteriniz.

ÖNEMLİ NOT :Wizard kullanılırken database seçeneğinde “Header files only” seçilmeyip “Database View without file support” seçilirse wizard otomatik olarak view sınıfını CRecordView almaktadır.

2002-06-04 Salı

215

Page 216: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

27 MFC’DE DLL KULLANIMIVisual C sisteminde DLL yazmak için API ve MFC için iki ayrı DLL wizard’ı vardır. API DLL wizard’ında __declspec işlemleri için bir giriş yapılmıştır ve örnek bazı fonksiyonlar tanımlanmıştır. DLL wizard’da DLL derlemesi için gereken makro Project Settings’te belirtilmiştir.

27.1 SINIFLARIN DLL’LERDE KULLANILMASIBir DLL içinde bir class olması durumunda ne yapılacaktır?

Bir sınıfın yalnızca belirli üye fonksiyonları dllexport yada dllimport olabilir. Böylece DLL’e yerleştirilen bir sınıf dışarıdan kullanılırken yalnızca bu fonksiyonlar çağrılabilir. #ifdef DLLBUILD#define DLLPROC __declspec(dllexport)#else#define DLLPROC __declspec(dllimport)#endif

class X {public:DLLPROC void Func();

//....};class anahtar sözcüğü ile sınıf isminin arasına dllexport ya da dllimport bildirimi yapılabilir. Bu durumda sınıfın bütün üye fonksiyonları bu işleme tabii tutulmuş olur.

class __declspec(dllexport) X {public:DLLPROC void Func();

//....};SINIF ÇALIŞMASI :DLL API Wizard kullanarak bir sınıf tasarlayın. Başka bir uygulamadan bu DLL’i kullanarak bu sınıf türünden nesne tanımlayıp üye fonksiyonları çağırınız. //APIdll.h/*The following ifdef block is the standard way of creating macros which make exporting from a DLL simpler. All files within this DLL are compiled with the APIDLL_EXPORTS symbol defined on the command line. this symbol should not be defined on any project that uses this DLL. This way any other project whose source files include this file see APIDLL_API functions as being imported from a DLL, wheras this DLL sees symbols defined with this macro as being exported.*/#ifdef APIDLL_EXPORTS#define APIDLL_API __declspec(dllexport)#else#define APIDLL_API __declspec(dllimport)#endif

// This class is exported from the APIdll.dllclass APIDLL_API CAPIdll {private:

int n;public:

CAPIdll(void);CAPIdll(int k);void Disp(void);void Increment(void);// TODO: add your methods here.

};

extern APIDLL_API int nAPIdll;

APIDLL_API int fnAPIdll(void);

216

Page 217: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

// APIdll.cpp : Defines the entry point for the DLL application.#include "stdafx.h"#include "APIdll.h"#include "iostream.h"

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved

){ switch (ul_reason_for_call)

{case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:

break; } return TRUE;}// This is an example of an exported variableAPIDLL_API int nAPIdll=0;

// This is an example of an exported function.APIDLL_API int fnAPIdll(void){

return 42;}

// This is the constructor of a class that has been exported.// see APIdll.h for the class definitionCAPIdll::CAPIdll(){

return; }CAPIdll::CAPIdll(int k){

n = k;}

void CAPIdll::Disp(void){

cout<<n<<"\n";}

void CAPIdll::Increment(void){

++n;}dll I kullanan kod aşağıdadır. APIdllAppliction pr//APIdllAplication.cpp#include "APIdll.h"

void main(void){

CAPIdll sample(99);sample.Disp();sample.Increment();sample.Disp();

}

27.2 AFX_EXT_CLASS MakrosuMFC kütüphanesinde AFX_EXT_CLASS makrosu duruma göre dllexport ya da dllimport olmaktadır.

Eğer _AFXDLL ve _AFXEXT define edilmişse bu makro __declspec(dllexport)

217

Page 218: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

eğer _AFXDLL define edilmiş _AFXEXT define edilmemişse bu makro __declspec(dllimport) biçiminde işlem görür.

Biz MFC’de bir DLL sınıfı yazarken sınıfa doğrudan dllexport ya da dllimport bildirimi yapmak yerine AFX_EXT_CLASS makrosunu kullanırız. Class wizard proje türüne göre _AFXDLL ya da _AFXEXT makrolarını define eder ya da etmez. Örneğin MFC .EXE ve .DLL uygulamalarında _AFXDLL define edilmiş ancak _AFXEXT define edilmemiştir. Yani bu durumda AFX_EXT_CLASS makrosu dllimport biçimindedir.

27.3 MFC DLL Wizard’ın KullanımıMFC DLL wizard seçildiğinde üç seçenek sorulur; birinci seçenek MFC kütüphanesinin static olarak DLL’e eklenmesini gerektirir ki pek kullanışlı değildir. İkinci seçenek default olan seçenektir. Bu seçenekte AFX_EXT_CLASS makrosu kullanılmamalıdır. Çünkü _AFXDLL define edilmiş fakat _AFXEXT define edilmemiştir. Dolayısıyla AFX_EXT_CLASS dllimport anlamına gelir. Üçüncü seçenek seçilirse (extension DLL denir) AFX_EXT_CLASS kullanılabilir. Çünkü _AFXDLL ve _AFXEXT birlikte define edilmiştir.

MFC DLL’leri tıpkı .EXE’ler gibi CWinApp sınıfından türetilmiş bir sınıfla başlatılırlar. Yani aslında DllMain fonksiyonu global sınıf nesnesi yoluyla DLL sınıfının InitInstance fonksiyonunu çağırmaktadır. Şüphesiz DLL’lerde InitInstance fonksiyonu DllMain fonksiyonu gibi kullanılmalıdır.

27.4 DLL’lerin MFC Uygulamalarında KullanımıMFC uygulamalarında DLL’lere genellikle kaynaklar ve çeşitli paylaşılan sınıflar yerleştirilir. Örneğin MFC sınıflarını kullanarak yazılmış olan bir sınıf DLL’e yerleştirilebilir.

27.5 DLL’lerdeki Kaynakları KullanmaDLL’ler de PE formatına uygundur. Yani onlar da kaynak içerebilir. Hatta bazı uygulamalarda kaynakların çoğu DLL’lere yerleştirilip DLL yalnızca kaynak tutucu olarak bile kullanılabilmektedir.

Bilindiği gibi API düzeyinde bir kaynak kullanabilmek için önce kaynağı yüklemek gerekir. Yükleme işlemi de LoadXXX fonksiyonları ile yapılmaktadır. Bu fonksiyonlar birinci

218

Page 219: MFCeng.harran.edu.tr/~nbesli/SP/MFC.doc  · Web viewCRect sınıfı dikdörtgensel koordinat işlemlerini yapan yararlı ve sık kullanılan ... Menü kaynağında her menü elemanının

parametresinde modülün (EXE ya da DLL) belleğe yüklenme adresini isterler. Biz API düzeyinde bir DLL’i kullanacakken önce DLL’in yüklenme adresini bilmemiz gerekir. DLL’in yükleme adresi DLL LoadLibrary ile yüklenmişse fonksiyonun geri dönüş değeri olarak, HMODULE LoadLibrary( LPCTSTR lpFileName // file name of module);normal yolla yüklenmişse GetModuleHandle fonksiyonunun geri dönüş değeri olarak elde edilmektedir. HMODULE GetModuleHandle( LPCTSTR lpModuleName // module name);

MFC’de kaynak yükleyen fonksiyonlar CWinApp sınıfnının üye fonksiyonlarıdır. Bu fonksiyonlar modülün yüklenme adresini parametre olarak almamaktadır. MFC kendi içinde static bir değişkenden bu değeri almaktadır ve bu değer default olarak EXE modülünün başlangıç adresi olan HINSTANCE değeridir. MFC’de DLL’den kaynak yüklemek için önce kaynak yüklemesi için kullanılan modül adresini AfxSetResourceHandle fonksiyonuyla set etmek gerekir. void AfxSetResourceHandle( HINSTANCE hInstResource );

Tabi bu işlemden sonra .EXE modülünün kaynakları kullanılacaksa eski değerinin set edilmesi gerekir.

SINIF ÇALIŞMASI :Bir DLL oluşturarak DLL’e bir icon kaynağı ekleyiniz. Bu icon’u başka bir uygulamadan WM_PAINT mesajında çizerek kullanınız.

219