BG MVC Model View Controller eğitim serisi yayında...

Ana page > Programlama > Windows API Programlama > Modal

Modal

► Diyalog Kutuları

Modal diyalog kutusu hakkında

Programın çalışmaya devam etmesi ve kullanıcının ana program penceresi ile işlem yapabilmesi için, kullanıcının modal diyalog kutusu ile ilgili işlemleri gerçekleştirip kutuyu kapatması veya iptal etmesi gerekir. Uygulamalar modal diyalog kutularını bir menü seçeneği tıklandığında ek bilgi elde etmek üzere kullanırlar.

Modal diyalog kutuları DialogBox() fonksiyonu ile oluşturulur.

Modal diyalog kutusu açık kaldığı sürece, kullanıcının ana program penceresi ile işlem yapabilmesi mümkün değildir.

Modal diyalog kutusu, bir pencere menüsü, bir başlık çubuğu ve kalın bir sınır çizgisi olan bir açılır penceredir. Bu özellikleri içermesi içn modal diyalog kutusu WS_POPUP, WS_SYSMENU, WS_CAPTION, ve DS_MODALFRAME özellikleri ile tanımlanmalıdır. Diyalog kutusu kendi kendisini devre dışı bırakmasına neden olacak WS_CHILD özelliği ile tanımlanmamalıdır.

Modal diyalog kutusu oluşturma işlemleri

Diyalog kutularını oluşturmak için öncelikle programı oluşturan proje altında bir resource dosyası ve bununla birlikte çalışan bir başlık dosyası tanımlamak gerekir.

Resource dosyası bir Windows uygulamasının .exe uzantılı dosyasına eklenmek üzere oluşturulan bir ikili sistem veri dosyasıdır. Uygulamalar, resource dosyaları .exe dosyalara direk olarak kopya ederek veya derledikten sonra ekleyebilirler.

Windows uygulamalarına resource içeriği eklemek için:

  • .rc uzantılı bir resource dosyası (metin dosyası) oluşturulur.
  • Resource dosya içinde gerekli bildirimler yapılır.
  • Resource dosya içindeki makroların bildirimlerinin yer aldığı bir başlık dosyası oluşturulur.
  • .rc dosyası derlenerek .res uzantılı bir dosya (ikili dosya) oluşturulur.
  • .res dosyası uygulamanın .exe dosyasına eklenir.
  • .exe dosyası çalıştırıldıktan sonra, gerek duyduğunda resource içinde yer alan bildirimleri kullanır.

Şimdiye kadar kullandığımız proje içine aşağıda gösterildiği şekilde resource.rc ve resource.h adlı 2 adet dosya eklemeye çalışalım:

resource.rc dosyası oluşturma

1. Code::Blocks IDE içinde proje açık iken aşağıdaki resimde gösterilen File-New-Empty File menü seçeneğine tıklayın:

2. Karşınıza gelen pencereden "Evet" butonuna basın.

3. Kayıt türü bölümünden "Windows resource files" seçeneğini seçin:

4. Dosya adı bölümüne "resource.rc" ifadesini yazın:

5. Karşınıza gelen pencereden "OK" butonuna basın.

6. Code::Blocks IDE içinde projenin görünümü aşağıdaki resimde gösterildiği hale gelir:

resource.h başlık dosyası oluşturma

Bu işlem için bir önceki dosyayı oluşturmak için gösterilen aşamaların aynısı gerçekleştirilir. Sadece, 4 ncü safhada farklı işlem yapılır.

4. Kayıt türü bölümünden "All files(*.*) seçeneğini seçin, Dosya adı bölümüne "resource.h" ifadesini yazın:

Proje dosyaları ve yapısı

Artık, projede aşağıda gösterilen 3 adet dosya vardır:

  • main.c
  • resource.rc
  • resource.h

Projemize diyalog kutularını ve diğer bildirimleri ekleyebiliriz.

Modal diyalog kutusu oluşturma fonksiyonları ve çalışma yöntemi

Uygulamalar bir modal diyalog kutusu oluşturmak için aşağıdaki fonksiyonlardan birini kullanır:

DialogBox(): Bu fonksiyon, bir resource dosyası içinde yer alan bir diyalog kutusu şablonunun adını veya tanımlayıcısını kullanarak bir modal diyalog kutusu oluşturur.

DialogBoxIndirect(): Bu fonksiyon, bir diyalog kutusu şablonunu içeren bir bellek nesnesinin Handle değerini kullanarak bir modal diyalog kutusu oluşturur.

Modal bir diyalog kutusu oluşturulduğunda, sistem kutuyu aktif pencere olarak belirler. Diyalog kutusu mesaj işlem fonksiyonu EndDialog() fonksiyonunu çağırana veya sistem başka bir uygulamanın penceresini aktif hale getirene kadar, diyalog kutusu aktif olarak kalır. Diyalog kutusu kapatılmadığı sürece diyalog kutusunu barındıran ana program penceresi aktif hale gelmez.

Modal diyalog kutusu devreye girdiğinde, diyalog kutusu mesaj işlem fonksiyonu kullanıcı tarafından yapılan girişlere gerekli işlemleri yapmak üzere devreye girer. Diyalog kutusu mesaj işlem fonksiyonu, program ana pencere mesaj işlem fonksiyonuna benzer, ancak aşağıda gösterilen özelliklerde farklılıklar gösterir:

  • Diyalog kutusu DefWindowProc() fonksiyonunu çağırmaz. Bunun yerine, mesajlara işlem yaptığında TRUE, yapmadığında ise FALSE bir değer geri verir.
  • Sistem, diyalog kutusu mesaj işlem fonksiyonuna WM_CREATE mesajı yollamaz. Bunun yerine, diyalog kutusunu oluşturduğunda, WM_INITDIALOG mesajı gönderir.

Bütün diyalog kutusu mesaj işlem fonksiyonlarının genel yapısı aşağıdaki şekildedir:


BOOL CALLBACK DlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
  switch (message) 
  { 
     // Diğer mesajlar
 
     default: 
       return FALSE; 
  } 
}

Modal diyalog kutusu ekleme

Şimdi, programımıza bir modal diyalog kutusu eklemeye çalışalım:

resource.rc


#include "resource.h"

IDD_VERIBOX DIALOG 70, 10, 200, 60
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Ana Başlık Değiştirme"
FONT 8, "MS Sans Serif"
BEGIN
    EDITTEXT IDC_EDIT, 10, 10, 180, 14
    DEFPUSHBUTTON "&OK", IDOK, 30, 35, 50, 14
    PUSHBUTTON "&Cancel", IDCANCEL, 120, 35, 50, 14
END

IDR_MENU MENU
BEGIN
    POPUP "&İşlemler"
    BEGIN
        MENUITEM "&Başlık değiştirme", IDM_BASLIK_DEG
        MENUITEM "&Çıkış", IDM_CIKIS
    END
END

.rc uzantılı bir resource metin dosyasında kullanılan ifadeler 3 gruba ayrılır:

  • Kaynaklar: Resource dosya içinde tanımlanacak kaynağın türünü belirler. ACCELERATORS, BITMAP, DIALOG, FONT, ICON, MENU, POPUP ifadeleri kaynak tanımlamalarından bazılarıdır.
  • Kontrollar: Resource dosya içinde tanımlanan kaynaklar içinde kullanılacak kontrolların bildirimini yapmak için kullanılırlar. CHECKBOX, COMBOBOX, DEFPUSHBUTTON, EDITTEXT, GROUPBOX, ICON, LISTBOX, PUSHBUTTON, RADIOBUTTON ifadeleri kontrol tanımlamaları için kullanılan ifadelerden bazılarıdır.
  • Deyimler: Resource dosyası ve resource dosyası içinde tanımlı diyalog kutuları özellikleri ile menü seçenekleri tanımlamak için kullanılırlar. CAPTION, FONT, MENU, MENUITEM, STYLE ifadeleri bu deyimlerden bazılarıdır.

resource.rc dosyasında, IDD_VERIBOX tanımlayıcısı ve DIALOG ifadesi ile bir adet diyalog kutusu ve IDR_MENU tanımlayıcısı ve MENU ifadesi ile bir adet menü tanımlanmıştır. Daha önce, menü tanımlamalarını direk olarak main.c dosyası içinde tanımlamıştık.

Diyalog kutusu içinde, STYLE, CAPTION ve FONT ifadeleri ile diyalog özellikleri, EDITTEXT, DEFPUSHBUTTON ve PUSHBUTTON ifadeleri ile diyalog kutusu içinde bir adet EDIT ve 2 adet BUTTON kontrolu bildirimi yapılmıştır.

Menü tanımlaması içinde, POPUP ifadesi ile açılır bir menü ve bu menü altında MENUITEM ifadeleri ile 2 adet menü seçeneği tanımlanmıştır.

DIALOG, EDITTEXT, DEFPUSHBUTTON ve PUSHBUTTON ifadeleri ile birlikte kullanılan 4 sayının ilki x koordinat, ikincisi y koordinat, üçüncüsü genişlik ve dördüncüsü yükseklik değerlerini göstermektedir. Değerler piksel değil FONT ifadesi ile birlikte kullanılan büyüklük değerine bağlı olarak değişen büyüklüklerdir.

resource.h


#include <windows.h>

#define IDD_VERIBOX 301
#define IDR_MENU 401

#define IDC_STATIC01 101
#define IDC_EDIT 201
#define IDM_BASLIK_DEG 11
#define IDM_CIKIS 12

Resource dosya kullanımı ile birlikte, önceden main.c dosyası içindeki makroların tanımı artık resource.h dosyası içinde yapılmaktadır. Ayrıca, resource.rc dosyası içinde kullanılan makroların tanımları da burada yapılmaktadır.

main.c

Aşağıdaki ilk 2 satır programın başına global değerler olarak eklenir. Son satır ise, WinMain() fonksiyonu içindeki pencere sınıf bildiriminin menüsünü belirlemek üzere eklenir.


#include "resource.h"

char cdizi[200];

wincl.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); /* Menünün ana pencereye atanması */

WindowProcedure() fonksiyonu içinde renkli olarak gösterilen satırlar ile WM_COMMAND mesajına işlem yapılarak IDM_BASLIK_DEG menü seçeneği ile modal bir diyalog kutusu oluşturulur.

Ayrıca, modal diyalog kutusuna gelen mesajlara işlem yapmak üzere, WndProcDlg() isimli mesaj işlem fonksiyonu oluşturulur.


LRESULT CALLBACK WindowProcedure (HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
  switch (message)
  { 
    case WM_CREATE:

         hwndStatic01 = CreateWindowEx(0, "STATIC", "Statik kontrol",
                                WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 180, 500, 20,
                                hwnd, (HMENU) IDC_STATIC01, NULL, NULL);
	
         break;

    case WM_COMMAND:

         switch(LOWORD(wParam)) {
             case IDM_BASLIK_DEG:
                 if (DialogBox(ghInst, MAKEINTRESOURCE(IDD_VERIBOX), hwnd,
                              (DLGPROC)WndProcDlg)==IDOK) {
                     SetWindowText(hwnd, cdizi); 
                     SetWindowText(hwndStatic01, "Pencere başlığı değiştirildi.");
                 }
                 else {
                     SetWindowText(hwndStatic01, "Başlık değiştirme iptal edildi.");
                 } 
                 break;			 
              case IDM_CIKIS:
                 SendMessage(hwnd, WM_CLOSE, 0, 0);
                 break;
         }
		   
         break;
		  
    case WM_DESTROY:
         PostQuitMessage (0);
         break;
		 
    default:                 
         return DefWindowProc (hwnd, message, wParam, lParam);
  }

  return 0;
}

BOOL CALLBACK WndProcDlg(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
  switch (message) 
  { 
     case WM_INITDIALOG:
          SetWindowText(hwndStatic01, "Diyalog penceresi oluşturuldu."); 
          break;
     case WM_COMMAND: 
          switch (LOWORD(wParam)) { 
             case IDOK: 
                if (!GetDlgItemText(hwndDlg, IDC_EDIT, cdizi, 200)) *cdizi=0; 
 
             case IDCANCEL: 
                EndDialog(hwndDlg, wParam); 
                return TRUE; 
          } 
          break;
  } 
  return FALSE; 
}

Bildirimi winuser.h dosyası içinde yapılan ve bir tamsayı değeri resource tipinde bir değere çeviren MAKEINTRESOURCE makrosunun tanımı aşağıdaki ilk satırda genel yapısı ise ikinci satırda verilmiştir:

#define MAKEINTRESOURCE(i) (LPSTR)((DWORD)((WORD)(i)))

LPTSTR MAKEINTRESOURCE (WORD wInteger);

wInteger parametresi çevirilecek değeri gösterir.

Program derleme safhasında resource.rc dosyası derlenerek elde edilen resource.res dosyası .exe dosyaya eklenir.

Program çalıştığında:

  • Program ana penceresi oluşturulmadan önce, MAKEINTRESOURCE(IDR_MENU) komutu ile resource dosya içinde bildirimi yapılan menü ana pencereye atanır.
  • Program penceresi oluşturulur oluşturulmaz WM_CREATE mesajı mesaj işlem fonksiyonuna gönderilir. switch yapısının bu seçeneği altında CreateWindowEx() fonksiyonu ile bir adet Static kontrol oluşturulur.
  • IDM_BASLIK_DEG menü seçeneği tıklandığında, modal bir diyalog kutusu oluşturulur. Eğer diyalog kutusundaki Edit kontrolu içine bir karakter dizisi girilir ve OK tuşuna basılırsa, girilen karakter dizisi program ana pencere başlığı yerine yazılır.
  • Ayrıca, diyalog kutusu oluşturulduğunda WM_INITDIALOG mesajı ve diyalog kutusu ile yapılan işlem mesajları WndProcDlg() fonksiyonuna gönderlir. İşlemlerle ilgili bilgiler Static kontrol penceresine yazılır.

Program kaynak dosyaları

Programın çalışan en son halinde yer alan dosyalar aşağıdadır:

resource.rc


#include "resource.h"

IDD_VERIBOX DIALOG 70, 10, 200, 60
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Ana Başlık Değiştirme"
FONT 8, "MS Sans Serif"
BEGIN
    EDITTEXT IDC_EDIT, 10, 10, 180, 14
    DEFPUSHBUTTON "&OK", IDOK, 30, 35, 50, 14
    PUSHBUTTON "&Cancel", IDCANCEL, 120, 35, 50, 14
END

IDR_MENU MENU
BEGIN
    POPUP "&İşlemler"
    BEGIN
        MENUITEM "&Başlık değiştirme", IDM_BASLIK_DEG
        MENUITEM "&Çıkış", IDM_CIKIS
    END
END

resource.h


#include <windows.h>

#define IDD_VERIBOX 301
#define IDR_MENU 401

#define IDC_STATIC01 101
#define IDC_EDIT 201
#define IDM_BASLIK_DEG 11
#define IDM_CIKIS 12

main.c


#include <windows.h>
#include "resource.h"

LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK WndProcDlg(HWND, UINT, WPARAM, LPARAM);

char szClassName[ ] = "WinAPIWindowsApp";
HINSTANCE ghInst;
char cdizi[200];

HWND hwndStatic01;

int WINAPI WinMain (HINSTANCE hThisInstance, 
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)
{
  HWND hwndMain;         
  MSG messages;      
  WNDCLASSEX wincl;  
  
  ghInst = hThisInstance;

  wincl.hInstance = hThisInstance;
  wincl.lpszClassName = szClassName;
  wincl.lpfnWndProc = WindowProcedure;
  wincl.style = CS_DBLCLKS;           
  wincl.cbSize = sizeof (WNDCLASSEX);

  wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
  wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
  wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
  wincl.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
  wincl.cbClsExtra = 0; 
  wincl.cbWndExtra = 0; 
  wincl.hbrBackground = GetSysColorBrush(COLOR_3DFACE);

  if (!RegisterClassEx (&wincl)) return 0;

  hwndMain = CreateWindowEx (0, szClassName, "WinAPI Temel Program", 
                WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 
                544, 375, HWND_DESKTOP, NULL, hThisInstance, NULL);
						 
  if (!hwndMain) return 0;

  ShowWindow (hwndMain, nCmdShow);
  UpdateWindow(hwndMain);

  while (GetMessage (&messages, NULL, 0, 0) > 0) {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
  }	
	
  return messages.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
  switch (message)
  { 
    case WM_CREATE:

         hwndStatic01 = CreateWindowEx(0, "STATIC", "Statik kontrol",
                                WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 180, 500, 20,
                                hwnd, (HMENU) IDC_STATIC01, NULL, NULL);
	
         break;

    case WM_COMMAND:

         switch(LOWORD(wParam)) {
             case IDM_BASLIK_DEG:
                 if (DialogBox(ghInst, MAKEINTRESOURCE(IDD_VERIBOX), hwnd,
                              (DLGPROC)WndProcDlg)==IDOK) {
                     SetWindowText(hwnd, cdizi); 
                     SetWindowText(hwndStatic01, "Pencere başlığı değiştirildi.");
                 }
                 else {
                     SetWindowText(hwndStatic01, "Başlık değiştirme iptal edildi.");
                 } 
                 break;			 
             case IDM_CIKIS:
                 SendMessage(hwnd, WM_CLOSE, 0, 0);
                 break;
         }
		   
         break;
		  
    case WM_DESTROY:
         PostQuitMessage (0);
         break;
		 
    default:                 
         return DefWindowProc (hwnd, message, wParam, lParam);
  }

  return 0;
}

BOOL CALLBACK WndProcDlg(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
  switch (message) 
  { 
     case WM_INITDIALOG:
          SetWindowText(hwndStatic01, "Diyalog penceresi oluşturuldu."); 
          break;
     case WM_COMMAND: 
          switch (LOWORD(wParam)) { 
             case IDOK: 
                if (!GetDlgItemText(hwndDlg, IDC_EDIT, cdizi, 200)) *cdizi=0; 
 
             case IDCANCEL: 
                EndDialog(hwndDlg, wParam); 
                return TRUE; 
          } 
          break;
  } 
  return FALSE; 
}

Program ekran görüntüleri

Program çalıştığında karşınıza gelecek ekran görüntüsü aşağıdadır: