Menggunakan Carets
Bagian ini memiliki sampel kode untuk tugas-tugas berikut:
- Membuat dan Menampilkan Caret
- Menyembunyikan Tanda Sisipan
- Menghancurkan Penanda
- Menyesuaikan Waktu Kedipan
- Pemrosesan Input Papan Ketik
Membuat dan Menampilkan Kursor
Setelah menerima fokus keyboard, jendela harus membuat dan menampilkan tanda sisipan. Gunakan fungsiCreateCaret untuk membuat tanda sisipan di jendela tertentu. Anda kemudian dapat memanggil SetCaretPos untuk mengatur posisi saat ini dari tanda sisipan dan ShowCaret untuk membuat tanda sisipan terlihat.
Sistem mengirim pesan WM_SETFOCUS ke jendela yang menerima fokus keyboard; oleh karena itu, aplikasi harus membuat dan menampilkan tanda sisipan saat memproses pesan ini.
HWND hwnd, // window handle
int x; // horizontal coordinate of cursor
int y; // vertical coordinate of cursor
int nWidth; // width of cursor
int nHeight; // height of cursor
char *lpszChar; // pointer to character
case WM_SETFOCUS:
// Create a solid black caret.
CreateCaret(hwnd, (HBITMAP) NULL, nWidth, nHeight);
// Adjust the caret position, in client coordinates.
SetCaretPos(x, y);
// Display the caret.
ShowCaret(hwnd);
break;
Untuk membuat tanda sisipan berdasarkan bitmap, Anda harus menentukan handle bitmap ketika menggunakan CreateCaret. Anda dapat menggunakan aplikasi grafis untuk membuat bitmap dan pengkompilasi sumber daya untuk menambahkan bitmap ke sumber daya aplikasi Anda. Aplikasi Anda kemudian dapat menggunakan fungsi LoadBitmap untuk memuat handle bitmap. Misalnya, Anda dapat mengganti baris CreateCaret dalam contoh sebelumnya dengan baris berikut untuk membuat tanda sisipan bitmap.
// Load the application-defined caret resource.
hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120));
// Create a bitmap caret.
CreateCaret(hwnd, hCaret, 0, 0);
Atau Anda dapat menggunakan fungsi CreateBitmap atau CreateDIBitmap untuk mengambil handle bitmap caret. Untuk informasi selengkapnya tentang bitmaps, lihat bitmap.
Jika aplikasi Anda menentukan handle bitmap, CreateCaret mengabaikan parameter lebar dan tinggi. Bitmap mendefinisikan ukuran tanda sisipan.
Menyembunyikan Caret
Setiap kali aplikasi Anda menggambar ulang layar saat memproses pesan selain WM_PAINT, aplikasi harus membuat tanda sisipan tidak terlihat dengan menggunakan fungsi HideCaret. Setelah aplikasi Anda selesai menggambar, tampilkan kembali tanda sisipan dengan menggunakan fungsi ShowCaret. Jika aplikasi Anda memproses pesan WM_PAINT, tidak perlu menyembunyikan dan menampilkan kembali tanda sisipan, karena fungsi ini melakukannya secara otomatis.
Sampel kode berikut menunjukkan cara membuat aplikasi Anda menyembunyikan tanda sisipan saat menggambar karakter di layar dan saat memproses pesan WM_CHAR.
HWND hwnd, // window handle
HDC hdc; // device context
case WM_CHAR:
switch (wParam)
{
case 0x08:
// Process a backspace.
break;
case 0x09:
// Process a tab.
break;
case 0x0D:
// Process a carriage return.
break;
case 0x1B:
// Process an escape.
break;
case 0x0A:
// Process a linefeed.
break;
default:
// Hide the caret.
HideCaret(hwnd);
// Draw the character on the screen.
hdc = GetDC(hwnd);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
TextOut(hdc, x, y, lpszChar, 1);
ReleaseDC(hwnd, hdc);
// Display the caret.
ShowCaret(hwnd);
}
Jika aplikasi Anda memanggil fungsi HideCaret beberapa kali tanpa memanggil ShowCaret, kursor tidak akan ditampilkan sampai aplikasi juga memanggil ShowCaret sejumlah kali yang sama.
Menghancurkan Caret
Ketika jendela kehilangan fokus keyboard, sistem mengirim pesan WM_KILLFOCUS ke jendela. Aplikasi Anda harus menghancurkan caret saat memproses pesan ini dengan menggunakan fungsi DestroyCaret. Kode berikut menunjukkan cara menghapus kursor di jendela yang tidak lagi memiliki fokus keyboard.
case WM_KILLFOCUS:
// The window is losing the keyboard focus, so destroy the caret.
DestroyCaret();
break;
Menyesuaikan Waktu Blink
Di Windows 16-bit, aplikasi berbasis Windows dapat memanggil fungsiGetCaretBlinkTime untuk menyimpan waktu blink saat ini, lalu memanggil fungsi SetCaretBlinkTime untuk menyesuaikan waktu blink selama pemrosesan pesan WM_SETFOCUS. Aplikasi akan memulihkan waktu blink yang disimpan untuk penggunaan aplikasi lain dengan memanggil SetCaretBlinkTime selama pemrosesan pesan WM_KILLFOCUS. Namun, teknik ini tidak berfungsi di lingkungan multithreaded. Secara khusus, penonaktifan satu aplikasi tidak disinkronkan dengan aktivasi aplikasi lain, sehingga jika satu aplikasi macet, aplikasi lain masih dapat diaktifkan.
Aplikasi harus menghormati waktu blink yang dipilih oleh pengguna. FungsiSetCaretBlinkTime hanya boleh dipanggil oleh aplikasi yang memungkinkan pengguna untuk mengatur waktu blink.
Memproses Input Keyboard
Contoh berikut menunjukkan cara menggunakan caret pada editor teks yang sederhana. Contoh ini memperbarui posisi kursor saat pengguna mengetik karakter yang dapat dicetak dan menggunakan berbagai tombol untuk berpindah di dalam area klien.
#define TEXTMATRIX(x, y) *(pTextMatrix + (y * nWindowCharsX) + x)
// Global variables.
HINSTANCE hinst; // current instance
HBITMAP hCaret; // caret bitmap
HDC hdc; // device context
PAINTSTRUCT ps; // client area paint info
static char *pTextMatrix = NULL; // points to text matrix
static int nCharX, // width of char. in logical units
nCharY, // height of char. in logical units
nWindowX, // width of client area
nWindowY, // height of client area
nWindowCharsX, // width of client area
nWindowCharsY, // height of client area
nCaretPosX, // x-position of caret
nCaretPosY; // y-position of caret
static UINT uOldBlink; // previous blink rate
int x, y; // coordinates for text matrix
TEXTMETRIC tm; // font information
LONG APIENTRY MainWndProc(
HWND hwnd, // window handle
UINT message, // type of message
UINT wParam, // additional information
LONG lParam) // additional information
{
switch (message)
{
case WM_CREATE:
// Select a fixed-width system font, and get its text metrics.
hdc = GetDC(hwnd);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(hdc, &tm);
ReleaseDC(hwnd, hdc);
// Save the avg. width and height of characters.
nCharX = tm.tmAveCharWidth;
nCharY = tm.tmHeight;
return 0;
case WM_SIZE:
// Determine the width of the client area, in pixels
// and in number of characters.
nWindowX = LOWORD(lParam);
nWindowCharsX = max(1, nWindowX/nCharX);
// Determine the height of the client area, in
// pixels and in number of characters.
nWindowY = HIWORD(lParam);
nWindowCharsY = max(1, nWindowY/nCharY);
// Clear the buffer that holds the text input.
if (pTextMatrix != NULL)
free(pTextMatrix);
// If there is enough memory, allocate space for the
// text input buffer.
pTextMatrix = malloc(nWindowCharsX * nWindowCharsY);
if (pTextMatrix == NULL)
ErrorHandler("Not enough memory.");
else
for (y = 0; y < nWindowCharsY; y++)
for (x = 0; x < nWindowCharsX; x++)
TEXTMATRIX(x, y) = ' ';
// Move the caret to the origin.
SetCaretPos(0, 0);
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_HOME: // Home
nCaretPosX = 0;
break;
case VK_END: // End
nCaretPosX = nWindowCharsX - 1;
break;
case VK_PRIOR: // Page Up
nCaretPosY = 0;
break;
case VK_NEXT: // Page Down
nCaretPosY = nWindowCharsY -1;
break;
case VK_LEFT: // Left arrow
nCaretPosX = max(nCaretPosX - 1, 0);
break;
case VK_RIGHT: // Right arrow
nCaretPosX = min(nCaretPosX + 1,
nWindowCharsX - 1);
break;
case VK_UP: // Up arrow
nCaretPosY = max(nCaretPosY - 1, 0);
break;
case VK_DOWN: // Down arrow
nCaretPosY = min(nCaretPosY + 1,
nWindowCharsY - 1);
break;
case VK_DELETE: // Delete
// Move all the characters that followed the
// deleted character (on the same line) one
// space back (to the left) in the matrix.
for (x = nCaretPosX; x < nWindowCharsX; x++)
TEXTMATRIX(x, nCaretPosY) =
TEXTMATRIX(x + 1, nCaretPosY);
// Replace the last character on the
// line with a space.
TEXTMATRIX(nWindowCharsX - 1,
nCaretPosY) = ' ';
// The application will draw outside the
// WM_PAINT message processing, so hide the caret.
HideCaret(hwnd);
// Redraw the line, adjusted for the
// deleted character.
hdc = GetDC(hwnd);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
TextOut(hdc, nCaretPosX * nCharX,
nCaretPosY * nCharY,
&TEXTMATRIX(nCaretPosX, nCaretPosY),
nWindowCharsX - nCaretPosX);
ReleaseDC(hwnd, hdc);
// Display the caret.
ShowCaret(hwnd);
break;
}
// Adjust the caret position based on the
// virtual-key processing.
SetCaretPos(nCaretPosX * nCharX,
nCaretPosY * nCharY);
return 0;
case WM_CHAR:
switch (wParam)
{
case 0x08: // Backspace
// Move the caret back one space, and then
// process this like the DEL key.
if (nCaretPosX > 0)
{
nCaretPosX--;
SendMessage(hwnd, WM_KEYDOWN,
VK_DELETE, 1L);
}
break;
case 0x09: // Tab
// Tab stops exist every four spaces, so add
// spaces until the user hits the next tab.
do
{
SendMessage(hwnd, WM_CHAR, ' ', 1L);
} while (nCaretPosX % 4 != 0);
break;
case 0x0D: // Carriage return
// Go to the beginning of the next line.
// The bottom line wraps around to the top.
nCaretPosX = 0;
if (++nCaretPosY == nWindowCharsY)
nCaretPosY = 0;
break;
case 0x1B: // Escape
case 0x0A: // Linefeed
MessageBeep((UINT) -1);
break;
default:
// Add the character to the text buffer.
TEXTMATRIX(nCaretPosX, nCaretPosY) =
(char) wParam;
// The application will draw outside the
// WM_PAINT message processing, so hide the caret.
HideCaret(hwnd);
// Draw the character on the screen.
hdc = GetDC(hwnd);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
TextOut(hdc, nCaretPosX * nCharX,
nCaretPosY * nCharY,
&TEXTMATRIX(nCaretPosX, nCaretPosY), 1);
ReleaseDC(hwnd, hdc);
// Display the caret.
ShowCaret(hwnd);
// Prepare to wrap around if you reached the
// end of the line.
if (++nCaretPosX == nWindowCharsX)
{
nCaretPosX = 0;
if (++nCaretPosY == nWindowCharsY)
nCaretPosY = 0;
}
break;
}
// Adjust the caret position based on the
// character processing.
SetCaretPos(nCaretPosX * nCharX,
nCaretPosY * nCharY);
return 0;
case WM_PAINT:
// Draw all the characters in the buffer, line by line.
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc,
GetStockObject(SYSTEM_FIXED_FONT));
for (y = 0; y < nWindowCharsY; y++)
TextOut(hdc, 0, y * nCharY, &TEXTMATRIX(0, y),
nWindowCharsX);
EndPaint(hwnd, &ps);
case WM_SETFOCUS:
// The window has the input focus. Load the
// application-defined caret resource.
hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120));
// Create the caret.
CreateCaret(hwnd, hCaret, 0, 0);
// Adjust the caret position.
SetCaretPos(nCaretPosX * nCharX,
nCaretPosY * nCharY);
// Display the caret.
ShowCaret(hwnd);
break;
case WM_KILLFOCUS:
// The window is losing the input focus,
// so destroy the caret.
DestroyCaret();
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return NULL;
}