如何滚动位图
本节介绍可以对应用程序的主窗口过程进行的更改,以便让用户能够滚动位图。
示例中的菜单项可将屏幕内容复制到位图中,并在客户端区域显示该位图。 该示例还处理由滚动条生成的 WM_HSCROLL and WM_VSCROLL 消息,以便用户可以水平和垂直滚动位图。 与滚动文本示例不同,位图示例使用 BitBlt 函数来绘制客户端区域的无效部分。
需要了解的事项
技术
先决条件
- C/C++
- Windows 用户界面编程
说明
处理 WM_CREATE 消息
在处理 WM_CREATE 消息时,将初始化滚动所需的变量。 使用 CreateCompatibleDC 函数可以创建兼容设备上下文 (DC),使用 CreateBitmap 函数可以创建位图,而使用 SelectObject 函数可以为 DC 选择位图。 请注意,兼容的 DC 也称为内存 DC。
检索显示设备的特定设备的相关信息。 如果为屏幕创建了兼容的 DC(如示例中所示),请使用 GetDeviceCaps 函数来获取这些信息。 这些信息包括每个像素的相邻颜色位数、颜色平面数以及 DC 的高度和宽度。
处理 WM_SIZE 消息
在处理 WM_SIZE 消息时,需要调整滚动范围和位置,以反映客户区和将要显示的位图的尺寸。
SetScrollInfo 函数用于设置滚动条的最小和最大位置值、页面大小和滚动位置。
处理 WM_HSCROLL 和 WM_VSCROLL 消息
在处理 WM_HSCROLL 和 WM_VSCROLL 消息时,将检查滚动条请求代码,并将滚动位置设置为反映用户滚动操作的新值。 如果滚动位置在滚动范围内,则使用 ScrollWindow 函数将窗口滚动到新位置。 然后使用 SetScrollInfo 函数来调整滚动框的位置。
在滚动窗口后,其客户区的一部分将失效。 为确保更新无效区域,请使用 UpdateWindow 函数来生成 WM_PAINT 消息。 在处理 WM_PAINT 消息时,应用程序必须重新绘制客户区底部的无效区域。 在滚动或调整客户区大小时,该示例使用 BitBlt 函数将位图的相应部分复制到客户区的无效部分。
滚动位图的示例
通过下面的示例,用户可以将屏幕内容捕获到位图中,并在客户区中滚动位图。 当用户右键单击客户区时,屏幕内容就会被捕获。
LRESULT CALLBACK MyBitmapWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
SCROLLINFO si;
// These variables are required by BitBlt.
static HDC hdcWin; // window DC
static HDC hdcScreen; // DC for entire screen
static HDC hdcScreenCompat; // memory DC for screen
static HBITMAP hbmpCompat; // bitmap handle to old DC
static BITMAP bmp; // bitmap data structure
static BOOL fBlt; // TRUE if BitBlt occurred
static BOOL fScroll; // TRUE if scrolling occurred
static BOOL fSize; // TRUE if fBlt & WM_SIZE
// These variables are required for horizontal scrolling.
static int xMinScroll; // minimum horizontal scroll value
static int xCurrentScroll; // current horizontal scroll value
static int xMaxScroll; // maximum horizontal scroll value
// These variables are required for vertical scrolling.
static int yMinScroll; // minimum vertical scroll value
static int yCurrentScroll; // current vertical scroll value
static int yMaxScroll; // maximum vertical scroll value
switch (uMsg)
{
case WM_CREATE:
// Create a normal DC and a memory DC for the entire
// screen. The normal DC provides a snapshot of the
// screen contents. The memory DC keeps a copy of this
// snapshot in the associated bitmap.
hdcScreen = CreateDC(L"DISPLAY", (PCTSTR) NULL,
(PCTSTR) NULL, (CONST DEVMODE *) NULL);
hdcScreenCompat = CreateCompatibleDC(hdcScreen);
// Retrieve the metrics for the bitmap associated with the
// regular device context.
bmp.bmBitsPixel =
(BYTE) GetDeviceCaps(hdcScreen, BITSPIXEL);
bmp.bmPlanes = (BYTE) GetDeviceCaps(hdcScreen, PLANES);
bmp.bmWidth = GetDeviceCaps(hdcScreen, HORZRES);
bmp.bmHeight = GetDeviceCaps(hdcScreen, VERTRES);
// The width must be byte-aligned.
bmp.bmWidthBytes = ((bmp.bmWidth + 15) &~15)/8;
// Create a bitmap for the compatible DC.
hbmpCompat = CreateBitmap(bmp.bmWidth, bmp.bmHeight,
bmp.bmPlanes, bmp.bmBitsPixel, (CONST VOID *) NULL);
// Select the bitmap for the compatible DC.
SelectObject(hdcScreenCompat, hbmpCompat);
// Initialize the flags.
fBlt = FALSE;
fScroll = FALSE;
fSize = FALSE;
// Initialize the horizontal scrolling variables.
xMinScroll = 0;
xCurrentScroll = 0;
xMaxScroll = 0;
// Initialize the vertical scrolling variables.
yMinScroll = 0;
yCurrentScroll = 0;
yMaxScroll = 0;
break;
case WM_SIZE:
{
int xNewSize;
int yNewSize;
xNewSize = LOWORD(lParam);
yNewSize = HIWORD(lParam);
if (fBlt)
fSize = TRUE;
// The horizontal scrolling range is defined by
// (bitmap_width) - (client_width). The current horizontal
// scroll value remains within the horizontal scrolling range.
xMaxScroll = max(bmp.bmWidth-xNewSize, 0);
xCurrentScroll = min(xCurrentScroll, xMaxScroll);
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = xMinScroll;
si.nMax = bmp.bmWidth;
si.nPage = xNewSize;
si.nPos = xCurrentScroll;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
// The vertical scrolling range is defined by
// (bitmap_height) - (client_height). The current vertical
// scroll value remains within the vertical scrolling range.
yMaxScroll = max(bmp.bmHeight - yNewSize, 0);
yCurrentScroll = min(yCurrentScroll, yMaxScroll);
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = yMinScroll;
si.nMax = bmp.bmHeight;
si.nPage = yNewSize;
si.nPos = yCurrentScroll;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
break;
}
case WM_PAINT:
{
PRECT prect;
hdc = BeginPaint(hwnd, &ps);
// If the window has been resized and the user has
// captured the screen, use the following call to
// BitBlt to paint the window's client area.
if (fSize)
{
BitBlt(ps.hdc,
0, 0,
bmp.bmWidth, bmp.bmHeight,
hdcScreenCompat,
xCurrentScroll, yCurrentScroll,
SRCCOPY);
fSize = FALSE;
}
// If scrolling has occurred, use the following call to
// BitBlt to paint the invalid rectangle.
//
// The coordinates of this rectangle are specified in the
// RECT structure to which prect points.
//
// Note that it is necessary to increment the seventh
// argument (prect->left) by xCurrentScroll and the
// eighth argument (prect->top) by yCurrentScroll in
// order to map the correct pixels from the source bitmap.
if (fScroll)
{
prect = &ps.rcPaint;
BitBlt(ps.hdc,
prect->left, prect->top,
(prect->right - prect->left),
(prect->bottom - prect->top),
hdcScreenCompat,
prect->left + xCurrentScroll,
prect->top + yCurrentScroll,
SRCCOPY);
fScroll = FALSE;
}
EndPaint(hwnd, &ps);
break;
}
case WM_HSCROLL:
{
int xDelta; // xDelta = new_pos - current_pos
int xNewPos; // new position
int yDelta = 0;
switch (LOWORD(wParam))
{
// User clicked the scroll bar shaft left of the scroll box.
case SB_PAGEUP:
xNewPos = xCurrentScroll - 50;
break;
// User clicked the scroll bar shaft right of the scroll box.
case SB_PAGEDOWN:
xNewPos = xCurrentScroll + 50;
break;
// User clicked the left arrow.
case SB_LINEUP:
xNewPos = xCurrentScroll - 5;
break;
// User clicked the right arrow.
case SB_LINEDOWN:
xNewPos = xCurrentScroll + 5;
break;
// User dragged the scroll box.
case SB_THUMBPOSITION:
xNewPos = HIWORD(wParam);
break;
default:
xNewPos = xCurrentScroll;
}
// New position must be between 0 and the screen width.
xNewPos = max(0, xNewPos);
xNewPos = min(xMaxScroll, xNewPos);
// If the current position does not change, do not scroll.
if (xNewPos == xCurrentScroll)
break;
// Set the scroll flag to TRUE.
fScroll = TRUE;
// Determine the amount scrolled (in pixels).
xDelta = xNewPos - xCurrentScroll;
// Reset the current scroll position.
xCurrentScroll = xNewPos;
// Scroll the window. (The system repaints most of the
// client area when ScrollWindowEx is called; however, it is
// necessary to call UpdateWindow in order to repaint the
// rectangle of pixels that were invalidated.)
ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
(CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
SW_INVALIDATE);
UpdateWindow(hwnd);
// Reset the scroll bar.
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = xCurrentScroll;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
break;
}
case WM_VSCROLL:
{
int xDelta = 0;
int yDelta; // yDelta = new_pos - current_pos
int yNewPos; // new position
switch (LOWORD(wParam))
{
// User clicked the scroll bar shaft above the scroll box.
case SB_PAGEUP:
yNewPos = yCurrentScroll - 50;
break;
// User clicked the scroll bar shaft below the scroll box.
case SB_PAGEDOWN:
yNewPos = yCurrentScroll + 50;
break;
// User clicked the top arrow.
case SB_LINEUP:
yNewPos = yCurrentScroll - 5;
break;
// User clicked the bottom arrow.
case SB_LINEDOWN:
yNewPos = yCurrentScroll + 5;
break;
// User dragged the scroll box.
case SB_THUMBPOSITION:
yNewPos = HIWORD(wParam);
break;
default:
yNewPos = yCurrentScroll;
}
// New position must be between 0 and the screen height.
yNewPos = max(0, yNewPos);
yNewPos = min(yMaxScroll, yNewPos);
// If the current position does not change, do not scroll.
if (yNewPos == yCurrentScroll)
break;
// Set the scroll flag to TRUE.
fScroll = TRUE;
// Determine the amount scrolled (in pixels).
yDelta = yNewPos - yCurrentScroll;
// Reset the current scroll position.
yCurrentScroll = yNewPos;
// Scroll the window. (The system repaints most of the
// client area when ScrollWindowEx is called; however, it is
// necessary to call UpdateWindow in order to repaint the
// rectangle of pixels that were invalidated.)
ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
(CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
SW_INVALIDATE);
UpdateWindow(hwnd);
// Reset the scroll bar.
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = yCurrentScroll;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
break;
}
case WM_RBUTTONDOWN:
{
// Get the compatible DC of the client area.
hdcWin = GetDC(hwnd);
// Fill the client area to remove any existing contents.
RECT rect;
GetClientRect(hwnd, &rect);
FillRect(hdcWin, &rect, (HBRUSH)(COLOR_WINDOW+1));
// Copy the contents of the current screen
// into the compatible DC.
BitBlt(hdcScreenCompat, 0, 0, bmp.bmWidth,
bmp.bmHeight, hdcScreen, 0, 0, SRCCOPY);
// Copy the compatible DC to the client area.
BitBlt(hdcWin, 0, 0, bmp.bmWidth, bmp.bmHeight,
hdcScreenCompat, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hdcWin);
fBlt = TRUE;
break;
}
case WM_DESTROY :
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
相关主题