Pesan Jendela (Mulai menggunakan Win32 dan C++)

Aplikasi GUI harus menanggapi peristiwa dari pengguna dan dari sistem operasi.

  • Peristiwa dari pengguna mencakup semua cara seseorang dapat berinteraksi dengan program Anda: klik mouse, goresan kunci, gerakan layar sentuh, dan sebagainya.
  • Peristiwa dari sistem operasi mencakup apa pun yang "di luar" program yang dapat memengaruhi bagaimana program berperilaku. Misalnya, pengguna mungkin mencolokkan perangkat keras baru, atau Windows mungkin memasuki status berdaya rendah (tidur atau hibernasi).

Peristiwa ini dapat terjadi kapan saja saat program berjalan, dalam hampir semua urutan. Bagaimana Anda menyusun program yang alur eksekusinya tidak dapat diprediksi terlebih dahulu?

Untuk mengatasi masalah ini, Windows menggunakan model yang meneruskan pesan. Sistem operasi berkomunikasi dengan jendela aplikasi Anda dengan meneruskan pesan ke dalamnya. Pesan hanyalah kode numerik yang menunjuk peristiwa tertentu. Misalnya, jika pengguna menekan tombol mouse kiri, jendela menerima pesan yang memiliki kode pesan berikut.

#define WM_LBUTTONDOWN    0x0201

Beberapa pesan memiliki data yang terkait dengannya. Misalnya, pesan WM_LBUTTONDOWN menyertakan koordinat x dan koordinat y kursor mouse.

Untuk meneruskan pesan ke jendela, sistem operasi memanggil prosedur jendela yang terdaftar untuk jendela tersebut. (Dan sekarang Anda tahu untuk apa prosedur jendela.)

Perulangan Pesan

Aplikasi akan menerima ribuan pesan saat dijalankan. (Pertimbangkan bahwa setiap penekanan tombol dan klik tombol mouse menghasilkan pesan.) Selain itu, aplikasi dapat memiliki beberapa jendela, masing-masing dengan prosedur jendelanya sendiri. Bagaimana program menerima semua pesan ini dan mengirimkannya ke prosedur jendela yang benar? Aplikasi memerlukan perulangan untuk mengambil pesan dan mengirimkannya ke jendela yang benar.

Untuk setiap utas yang membuat jendela, sistem operasi membuat antrean untuk pesan jendela. Antrean ini menyimpan pesan untuk semua jendela yang dibuat pada utas tersebut. Antrean itu sendiri disembunyikan dari program Anda. Anda tidak dapat memanipulasi antrean secara langsung. Namun, Anda dapat menarik pesan dari antrean dengan memanggil fungsi GetMessage .

MSG msg;
GetMessage(&msg, NULL, 0, 0);

Fungsi ini menghapus pesan pertama dari kepala antrean. Jika antrean kosong, fungsi akan memblokir hingga pesan lain diantrekan. Fakta bahwa blok GetMessage tidak akan membuat program Anda tidak responsif. Jika tidak ada pesan, tidak ada yang bisa dilakukan program. Jika Anda harus melakukan pemrosesan latar belakang, Anda dapat membuat utas tambahan yang terus berjalan saat GetMessage menunggu pesan lain. (Lihat Menghindari Hambatan dalam Prosedur Jendela Anda.)

Parameter pertama GetMessage adalah alamat struktur MSG . Jika fungsi berhasil, fungsi akan mengisi struktur MSG dengan informasi tentang pesan. Ini termasuk jendela target dan kode pesan. Tiga parameter lainnya memungkinkan Anda memfilter pesan mana yang Anda dapatkan dari antrean. Dalam hampir semua kasus, Anda akan mengatur parameter ini ke nol.

Meskipun struktur MSG berisi informasi tentang pesan, Anda hampir tidak akan pernah memeriksa struktur ini secara langsung. Sebagai gantinya, Anda akan meneruskannya langsung ke dua fungsi lainnya.

TranslateMessage(&msg); 
DispatchMessage(&msg);

Fungsi TranslateMessage terkait dengan input keyboard. Ini menerjemahkan penekanan tombol (kunci ke bawah, kunci ke atas) menjadi karakter. Anda tidak benar-benar harus tahu cara kerja fungsi ini; ingatlah untuk menyebutnya sebelum DispatchMessage. Tautan ke dokumentasi MSDN akan memberi Anda informasi lebih lanjut, jika Anda penasaran.

Fungsi DispatchMessage memberi tahu sistem operasi untuk memanggil prosedur jendela jendela yang merupakan target pesan. Dengan kata lain, sistem operasi mencari handel jendela di tabel jendelanya, menemukan penunjuk fungsi yang terkait dengan jendela, dan memanggil fungsi.

Misalnya, pengguna menekan tombol mouse kiri. Ini menyebabkan rantai peristiwa:

  1. Sistem operasi menempatkan pesan WM_LBUTTONDOWN pada antrean pesan.
  2. Program Anda memanggil fungsi GetMessage .
  3. GetMessage menarik pesan WM_LBUTTONDOWN dari antrean dan mengisi struktur MSG .
  4. Program Anda memanggil fungsi TranslateMessage dan DispatchMessage .
  5. Di dalam DispatchMessage, sistem operasi memanggil prosedur jendela Anda.
  6. Prosedur jendela Anda dapat merespons pesan atau mengabaikannya.

Saat prosedur jendela kembali, prosedur akan kembali ke DispatchMessage. Ini kembali ke perulangan pesan untuk pesan berikutnya. Selama program Anda berjalan, pesan akan terus tiba di antrean. Oleh karena itu, Anda harus memiliki perulangan yang terus menarik pesan dari antrean dan mengirimkannya. Anda dapat menganggap perulangan sebagai melakukan hal berikut:

// WARNING: Don't actually write your loop this way.

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

Seperti yang tertulis, tentu saja, perulangan ini tidak akan pernah berakhir. Di sinilah nilai pengembalian untuk fungsi GetMessage masuk. Biasanya, GetMessage mengembalikan nilai bukan nol. Ketika Anda ingin keluar dari aplikasi dan keluar dari perulangan pesan, panggil fungsi PostQuitMessage .

        PostQuitMessage(0);

Fungsi PostQuitMessage menempatkan pesan WM_QUIT pada antrean pesan. WM_QUIT adalah pesan khusus: Ini menyebabkan GetMessage mengembalikan nol, menandakan akhir perulangan pesan. Berikut adalah perulangan pesan yang direvisi.

// Correct.

MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

Selama GetMessage mengembalikan nilai bukan nol, ekspresi dalam perulangan sementara mengevaluasi ke true. Setelah Anda memanggil PostQuitMessage, ekspresi menjadi false dan program keluar dari perulangan. (Salah satu hasil menarik dari perilaku ini adalah bahwa prosedur jendela Anda tidak pernah menerima pesan WM_QUIT . Oleh karena itu, Anda tidak perlu memiliki pernyataan kasus untuk pesan ini dalam prosedur jendela Anda.)

Pertanyaan jelas berikutnya adalah kapan harus memanggil PostQuitMessage. Kita akan kembali ke pertanyaan ini dalam topik Menutup Jendela, tetapi pertama-tama kita harus menulis prosedur jendela kita.

Pesan yang Diposting versus Pesan Terkirim

Bagian sebelumnya berbicara tentang pesan yang masuk ke antrean. Terkadang, sistem operasi akan memanggil prosedur jendela secara langsung, melewati antrean.

Terminologi untuk perbedaan ini dapat membingungkan:

  • Memposting pesan berarti pesan masuk ke antrean pesan, dan dikirim melalui perulangan pesan (GetMessage dan DispatchMessage).
  • Mengirim pesan berarti pesan melewati antrean, dan sistem operasi memanggil prosedur jendela secara langsung.

Untuk saat ini, perbedaannya tidak terlalu penting. Prosedur jendela menangani semua pesan. Namun, beberapa pesan melewati antrean dan langsung masuk ke prosedur jendela Anda. Namun, itu dapat membuat perbedaan jika aplikasi Anda berkomunikasi antar jendela. Anda dapat menemukan diskusi yang lebih menyeluruh tentang masalah ini dalam topik Tentang Pesan dan Antrean Pesan.

Berikutnya

Menulis Prosedur Jendela