Bagikan melalui


TN006: Peta Pesan

Catatan ini menjelaskan fasilitas peta pesan MFC.

Masalah

Microsoft Windows menerapkan fungsi virtual di kelas jendela yang menggunakan fasilitas olahpesannya. Karena banyaknya pesan yang terlibat, menyediakan fungsi virtual terpisah untuk setiap pesan Windows akan membuat vtable yang sangat besar.

Karena jumlah pesan Windows yang ditentukan sistem berubah dari waktu ke waktu, dan karena aplikasi dapat menentukan pesan Windows mereka sendiri, peta pesan memberikan tingkat tidak langsung yang mencegah perubahan antarmuka merusak kode yang ada.

Gambaran Umum

MFC menyediakan alternatif untuk pernyataan pengalihan yang digunakan dalam program tradisional berbasis Windows untuk menangani pesan yang dikirim ke jendela. Pemetaan dari pesan ke metode dapat ditentukan sehingga ketika pesan diterima oleh jendela, metode yang sesuai dipanggil secara otomatis. Fasilitas peta pesan ini dirancang untuk menyerupai fungsi virtual tetapi memiliki manfaat tambahan yang tidak dimungkinkan dengan fungsi virtual C++.

Menentukan Peta Pesan

Makro DECLARE_MESSAGE_MAP mendeklarasikan tiga anggota untuk kelas.

  • Array privat entri AFX_MSGMAP_ENTRY yang disebut _messageEntries.

  • Struktur AFX_MSGMAP yang dilindungi yang disebut messageMap yang menunjuk ke array _messageEntries .

  • Fungsi virtual terproteksi yang disebut GetMessageMap yang mengembalikan alamat messageMap.

Makro ini harus dimasukkan ke dalam deklarasi kelas apa pun menggunakan peta pesan. Berdasarkan konvensi, itu adalah di akhir deklarasi kelas. Contohnya:

class CMyWnd : public CMyParentWndClass
{
    // my stuff...

protected:
    //{{AFX_MSG(CMyWnd)
    afx_msg void OnPaint();
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

Ini adalah format yang dihasilkan oleh AppWizard dan ClassWizard saat mereka membuat kelas baru. Tanda kurung //{{ dan //}} diperlukan untuk ClassWizard.

Tabel peta pesan ditentukan dengan menggunakan sekumpulan makro yang diperluas ke entri peta pesan. Tabel dimulai dengan panggilan makro BEGIN_MESSAGE_MAP , yang menentukan kelas yang ditangani oleh peta pesan ini dan kelas induk tempat pesan yang tidak tertangani diteruskan. Tabel diakhir dengan panggilan makro END_MESSAGE_MAP .

Di antara kedua panggilan makro ini adalah entri untuk setiap pesan yang akan ditangani oleh peta pesan ini. Setiap pesan Windows standar memiliki makro formulir ON_WM_MESSAGE_NAME yang menghasilkan entri untuk pesan tersebut.

Tanda tangan fungsi standar telah didefinisikan untuk membuka kemasan parameter setiap pesan Windows dan memberikan keamanan jenis. Tanda tangan ini dapat ditemukan dalam file Afxwin.h dalam deklarasi CWnd. Masing-masing ditandai dengan kata kunci afx_msg untuk identifikasi yang mudah.

Catatan

ClassWizard mengharuskan Anda menggunakan kata kunci afx_msg dalam deklarasi handler peta pesan Anda.

Tanda tangan fungsi ini diturunkan dengan menggunakan konvensi sederhana. Nama fungsi selalu dimulai dengan "On". Ini diikuti dengan nama pesan Windows dengan "WM_" dihapus dan huruf pertama dari setiap kata yang dikapitalisasi. Urutan parameter adalah wParam diikuti oleh LOWORD(lParam) kemudian HIWORD(lParam). Parameter yang tidak digunakan tidak diteruskan. Setiap handel yang dibungkus oleh kelas MFC dikonversi ke penunjuk ke objek MFC yang sesuai. Contoh berikut menunjukkan cara menangani pesan WM_PAINT dan menyebabkan CMyWnd::OnPaint fungsi dipanggil:

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
    //{{AFX_MSG_MAP(CMyWnd)
    ON_WM_PAINT()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

Tabel peta pesan harus ditentukan di luar cakupan definisi fungsi atau kelas apa pun. Ini tidak boleh dimasukkan ke dalam blok "C" ekstern.

Catatan

ClassWizard akan mengubah entri peta pesan yang terjadi antara tanda kurung komentar //{{ dan //}}.

Pesan Windows yang Ditentukan Pengguna

Pesan yang ditentukan pengguna dapat disertakan dalam peta pesan dengan menggunakan makro ON_MESSAGE . Makro ini menerima nomor pesan dan metode formulir:

    // inside the class declaration
    afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);

    #define WM_MYMESSAGE (WM_USER + 100)

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
    ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()

Dalam contoh ini, kami membuat handler untuk pesan kustom yang memiliki ID pesan Windows yang berasal dari basis WM_USER standar untuk pesan yang ditentukan pengguna. Contoh berikut menunjukkan cara memanggil handler ini:

CWnd* pWnd = ...;
pWnd->SendMessage(WM_MYMESSAGE);

Rentang pesan yang ditentukan pengguna yang menggunakan pendekatan ini harus berada dalam rentang WM_USER untuk 0x7fff.

Catatan

ClassWizard tidak mendukung memasukkan rutinitas handler ON_MESSAGE dari antarmuka pengguna ClassWizard. Anda harus memasukkannya secara manual dari editor Visual C++. ClassWizard akan mengurai entri ini dan memungkinkan Anda menelusurinya sama seperti entri peta pesan lainnya.

Pesan Windows Terdaftar

Fungsi RegisterWindowMessage digunakan untuk menentukan pesan jendela baru yang dijamin unik di seluruh sistem. Makro ON_REGISTERED_MESSAGE digunakan untuk menangani pesan-pesan ini. Makro ini menerima nama variabel UINT NEAR yang berisi ID pesan windows terdaftar. Misalnya

class CMyWnd : public CMyParentWndClass
{
public:
    CMyWnd();

    //{{AFX_MSG(CMyWnd)
    afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam);
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

static UINT NEAR WM_FIND = RegisterWindowMessage("COMMDLG_FIND");

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
    //{{AFX_MSG_MAP(CMyWnd)
    ON_REGISTERED_MESSAGE(WM_FIND, OnFind)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

Variabel ID pesan Windows terdaftar (WM_FIND dalam contoh ini) harus berupa variabel NEAR karena cara ON_REGISTERED_MESSAGE diterapkan.

Rentang pesan yang ditentukan pengguna yang menggunakan pendekatan ini akan berada dalam rentang 0xC000 untuk 0xFFFF.

Catatan

ClassWizard tidak mendukung memasukkan rutinitas handler ON_REGISTERED_MESSAGE dari antarmuka pengguna ClassWizard. Anda harus memasukkannya secara manual dari editor teks. ClassWizard akan mengurai entri ini dan memungkinkan Anda menelusurinya sama seperti entri peta pesan lainnya.

Pesan Perintah

Pesan perintah dari menu dan akselerator ditangani dalam peta pesan dengan makro ON_COMMAND. Makro ini menerima ID perintah dan metode. Hanya pesan WM_COMMAND tertentu yang memiliki wParam yang sama dengan ID perintah yang ditentukan yang ditangani oleh metode yang ditentukan dalam entri peta pesan. Fungsi anggota handler perintah tidak mengambil parameter dan mengembalikan void. Makro memiliki formulir berikut:

ON_COMMAND(id, memberFxn)

Pesan pembaruan perintah dirutekan melalui mekanisme yang sama, tetapi gunakan makro ON_UPDATE_COMMAND_UI sebagai gantinya. Fungsi anggota handler pembaruan perintah mengambil satu parameter, penunjuk ke objek CCmdUI , dan mengembalikan void. Makro memiliki formulir

ON_UPDATE_COMMAND_UI(id, memberFxn)

Pengguna tingkat lanjut dapat menggunakan makro ON_COMMAND_EX, yang merupakan bentuk penangan pesan perintah yang diperluas. Makro menyediakan superset fungsionalitas ON_COMMAND. Fungsi anggota handler perintah yang diperluas mengambil satu parameter, UINT yang berisi ID perintah, dan mengembalikan BOOL. Nilai pengembalian harus TRUE untuk menunjukkan bahwa perintah telah ditangani. Jika tidak, perutean akan berlanjut ke objek target perintah lainnya.

Contoh formulir ini:

  • Di dalam Resource.h (biasanya dihasilkan oleh Visual C++)

    #define    ID_MYCMD      100
    #define    ID_COMPLEX    101
    
  • Di dalam deklarasi kelas

    afx_msg void OnMyCommand();
    afx_msg void OnUpdateMyCommand(CCmdUI* pCmdUI);
    afx_msg BOOL OnComplexCommand(UINT nID);
    
  • Di dalam definisi peta pesan

    ON_COMMAND(ID_MYCMD, OnMyCommand)
    ON_UPDATE_COMMAND_UI(ID_MYCMD, OnUpdateMyCommand)
    ON_COMMAND_EX(ID_MYCMD, OnComplexCommand)
    
  • Dalam file implementasi

    void CMyClass::OnMyCommand()
    {
        // handle the command
    }
    
    void CMyClass::OnUpdateMyCommand(CCmdUI* pCmdUI)
    {
        // set the UI state with pCmdUI
    }
    
    BOOL CMyClass::OnComplexCommand(UINT nID)
    {
        // handle the command
        return TRUE;
    }
    

Pengguna tingkat lanjut dapat menangani berbagai perintah dengan menggunakan satu handler perintah: ON_COMMAND_RANGE atau ON_COMMAND_RANGE_EX. Lihat dokumentasi produk untuk informasi selengkapnya tentang makro ini.

Catatan

ClassWizard mendukung pembuatan handler ON_COMMAND dan ON_UPDATE_COMMAND_UI, tetapi tidak mendukung pembuatan handler ON_COMMAND_EX atau ON_COMMAND_RANGE. Namun, Wizard Kelas akan mengurai dan memungkinkan Anda menelusuri keempat varian handler perintah.

Mengontrol Pesan Pemberitahuan

Pesan yang dikirim dari kontrol anak ke jendela memiliki sedikit informasi tambahan dalam entri peta pesan mereka: ID kontrol. Handler pesan yang ditentukan dalam entri peta pesan hanya dipanggil jika kondisi berikut ini benar:

  • Kode pemberitahuan kontrol (kata tinggi lParam), seperti BN_CLICKED, cocok dengan kode pemberitahuan yang ditentukan dalam entri peta pesan.

  • ID kontrol (wParam) cocok dengan ID kontrol yang ditentukan dalam entri peta pesan.

Pesan pemberitahuan kontrol kustom dapat menggunakan makro ON_CONTROL untuk menentukan entri peta pesan dengan kode pemberitahuan kustom. Makro ini memiliki formulir

ON_CONTROL(wNotificationCode, id, memberFxn)

Untuk penggunaan lanjutan ON_CONTROL_RANGE dapat digunakan untuk menangani pemberitahuan kontrol tertentu dari berbagai kontrol dengan handler yang sama.

Catatan

ClassWizard tidak mendukung pembuatan handler ON_CONTROL atau ON_CONTROL_RANGE di antarmuka pengguna. Anda harus memasukkannya secara manual dengan editor teks. ClassWizard akan mengurai entri ini dan memungkinkan Anda menelusurinya seperti entri peta pesan lainnya.

Windows Common Controls menggunakan WM_NOTIFY yang lebih kuat untuk pemberitahuan kontrol yang kompleks. Versi MFC ini memiliki dukungan langsung untuk pesan baru ini dengan menggunakan makro ON_NOTIFY dan ON_NOTIFY_RANGE. Lihat dokumentasi produk untuk informasi selengkapnya tentang makro ini.

Baca juga

Catatan Teknis menurut Angka
Catatan Teknis menurut Kategori