如何捲動文字
本節描述您可以對應用程式主視窗程式所做的變更,讓使用者卷動文字。 本節中的範例會建立並顯示文字字串陣列,並處理 WM_HSCROLL 和 WM_VSCROLL 滾動條訊息,讓使用者可以垂直和水準捲動文字。
您需要知道的事項
技術
必要條件
- C/C++
- Windows 使用者介面程序設計
指示
處理WM_CREATE訊息
卷動單位通常會在處理 WM_CREATE 訊息時設定。 根據與視窗裝置內容 (DC) 相關聯之字型維度的捲動單位,是很方便的。 若要擷取特定DC的字型尺寸,請使用 GetTextMetrics 函式。
在本節的範例中,一個垂直滾動單元相當於字元單元格的高度,加上外部前置。 一個水準捲動單位相當於字元儲存格的平均寬度。 因此,水平捲動位置不會對應到實際字元,除非螢幕字型是固定寬度。
處理WM_SIZE訊息
處理 WM_SIZE 訊息時,您可以調整卷動範圍和捲動位置,以反映工作區的維度,以及顯示的文字行數。
SetScrollInfo 函式會設定滾動條的最小和最大位置值、頁面大小,以及滾動條的捲動位置。
處理WM_HSCROLL和WM_VSCROLL訊息
每當使用者按兩下滾動條或拖曳滾動盒時,滾動條會將WM_HSCROLL和WM_VSCROLL訊息傳送至視窗程式。 WM_VSCROLL和WM_HSCROLL低序字組各包含一個要求代碼,指出卷動動作的方向和大小。
處理WM_HSCROLL和WM_VSCROLL訊息時,會檢查滾動條要求代碼,並計算卷動增量。 將增量套用至目前的捲動位置之後,視窗會使用 ScrollWindowEx 函式捲動至新位置,而滾動盒的位置會使用 SetScrollInfo 函式來調整。
捲動窗口之後,其工作區的一部分會失效。 為了確保更新無效的區域,UpdateWindow 函式會用來產生WM_PAINT訊息。
處理WM_PAINT訊息
處理 WM_PAINT 訊息時,繪製您想要出現在窗口無效部分的文字行會很方便。 下列範例會使用目前卷動位置和無效區域的維度來判斷無效區域內線條的範圍,以便顯示它們。
卷動文字的範例
下列範例是顯示其工作區中文字之視窗的視窗程式。 此範例示範如何捲動文字,以回應水準和垂直滾動條的輸入。
#include "strsafe.h"
LRESULT CALLBACK MyTextWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
SCROLLINFO si;
// These variables are required to display text.
static int xClient; // width of client area
static int yClient; // height of client area
static int xClientMax; // maximum width of client area
static int xChar; // horizontal scrolling unit
static int yChar; // vertical scrolling unit
static int xUpper; // average width of uppercase letters
static int xPos; // current horizontal scrolling position
static int yPos; // current vertical scrolling position
int i; // loop counter
int x, y; // horizontal and vertical coordinates
int FirstLine; // first line in the invalidated area
int LastLine; // last line in the invalidated area
HRESULT hr;
size_t abcLength; // length of an abc[] item
// Create an array of lines to display.
#define LINES 28
static TCHAR *abc[] = {
TEXT("anteater"), TEXT("bear"), TEXT("cougar"),
TEXT("dingo"), TEXT("elephant"), TEXT("falcon"),
TEXT("gazelle"), TEXT("hyena"), TEXT("iguana"),
TEXT("jackal"), TEXT("kangaroo"), TEXT("llama"),
TEXT("moose"), TEXT("newt"), TEXT("octopus"),
TEXT("penguin"), TEXT("quail"), TEXT("rat"),
TEXT("squid"), TEXT("tortoise"), TEXT("urus"),
TEXT("vole"), TEXT("walrus"), TEXT("xylophone"),
TEXT("yak"), TEXT("zebra"),
TEXT("This line contains words, but no character. Go figure."),
TEXT("")
};
switch (uMsg)
{
case WM_CREATE :
// Get the handle to the client area's device context.
hdc = GetDC (hwnd);
// Extract font dimensions from the text metrics.
GetTextMetrics (hdc, &tm);
xChar = tm.tmAveCharWidth;
xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * xChar/2;
yChar = tm.tmHeight + tm.tmExternalLeading;
// Free the device context.
ReleaseDC (hwnd, hdc);
// Set an arbitrary maximum width for client area.
// (xClientMax is the sum of the widths of 48 average
// lowercase letters and 12 uppercase letters.)
xClientMax = 48 * xChar + 12 * xUpper;
return 0;
case WM_SIZE:
// Retrieve the dimensions of the client area.
yClient = HIWORD (lParam);
xClient = LOWORD (lParam);
// Set the vertical scrolling range and page size
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = LINES - 1;
si.nPage = yClient / yChar;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
// Set the horizontal scrolling range and page size.
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = 2 + xClientMax / xChar;
si.nPage = xClient / xChar;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
return 0;
case WM_HSCROLL:
// Get all the vertial scroll bar information.
si.cbSize = sizeof (si);
si.fMask = SIF_ALL;
// Save the position for comparison later on.
GetScrollInfo (hwnd, SB_HORZ, &si);
xPos = si.nPos;
switch (LOWORD (wParam))
{
// User clicked the left arrow.
case SB_LINELEFT:
si.nPos -= 1;
break;
// User clicked the right arrow.
case SB_LINERIGHT:
si.nPos += 1;
break;
// User clicked the scroll bar shaft left of the scroll box.
case SB_PAGELEFT:
si.nPos -= si.nPage;
break;
// User clicked the scroll bar shaft right of the scroll box.
case SB_PAGERIGHT:
si.nPos += si.nPage;
break;
// User dragged the scroll box.
case SB_THUMBTRACK:
si.nPos = si.nTrackPos;
break;
default :
break;
}
// Set the position and then retrieve it. Due to adjustments
// by Windows it may not be the same as the value set.
si.fMask = SIF_POS;
SetScrollInfo (hwnd, SB_HORZ, &si, TRUE);
GetScrollInfo (hwnd, SB_HORZ, &si);
// If the position has changed, scroll the window.
if (si.nPos != xPos)
{
ScrollWindow(hwnd, xChar * (xPos - si.nPos), 0, NULL, NULL);
}
return 0;
case WM_VSCROLL:
// Get all the vertial scroll bar information.
si.cbSize = sizeof (si);
si.fMask = SIF_ALL;
GetScrollInfo (hwnd, SB_VERT, &si);
// Save the position for comparison later on.
yPos = si.nPos;
switch (LOWORD (wParam))
{
// User clicked the HOME keyboard key.
case SB_TOP:
si.nPos = si.nMin;
break;
// User clicked the END keyboard key.
case SB_BOTTOM:
si.nPos = si.nMax;
break;
// User clicked the top arrow.
case SB_LINEUP:
si.nPos -= 1;
break;
// User clicked the bottom arrow.
case SB_LINEDOWN:
si.nPos += 1;
break;
// User clicked the scroll bar shaft above the scroll box.
case SB_PAGEUP:
si.nPos -= si.nPage;
break;
// User clicked the scroll bar shaft below the scroll box.
case SB_PAGEDOWN:
si.nPos += si.nPage;
break;
// User dragged the scroll box.
case SB_THUMBTRACK:
si.nPos = si.nTrackPos;
break;
default:
break;
}
// Set the position and then retrieve it. Due to adjustments
// by Windows it may not be the same as the value set.
si.fMask = SIF_POS;
SetScrollInfo (hwnd, SB_VERT, &si, TRUE);
GetScrollInfo (hwnd, SB_VERT, &si);
// If the position has changed, scroll window and update it.
if (si.nPos != yPos)
{
ScrollWindow(hwnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
UpdateWindow (hwnd);
}
return 0;
case WM_PAINT :
// Prepare the window for painting.
hdc = BeginPaint (hwnd, &ps);
// Get vertical scroll bar position.
si.cbSize = sizeof (si);
si.fMask = SIF_POS;
GetScrollInfo (hwnd, SB_VERT, &si);
yPos = si.nPos;
// Get horizontal scroll bar position.
GetScrollInfo (hwnd, SB_HORZ, &si);
xPos = si.nPos;
// Find painting limits.
FirstLine = max (0, yPos + ps.rcPaint.top / yChar);
LastLine = min (LINES - 1, yPos + ps.rcPaint.bottom / yChar);
for (i = FirstLine; i <= LastLine; i++)
{
x = xChar * (1 - xPos);
y = yChar * (i - yPos);
// Note that "55" in the following depends on the
// maximum size of an abc[] item. Also, you must include
// strsafe.h to use the StringCchLength function.
hr = StringCchLength(abc[i], 55, &abcLength);
if ((FAILED(hr))|(abcLength == NULL))
{
//
// TODO: write error handler
//
}
// Write a line of text to the client area.
TextOut(hdc, x, y, abc[i], abcLength);
}
// Indicate that painting is finished.
EndPaint (hwnd, &ps);
return 0;
case WM_DESTROY :
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
相關主題