gpt4 book ai didi

c++ - 滚动大图像故障的 MSDN 示例

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:34:10 24 4
gpt4 key购买 nike

简介及相关信息:

我正在尝试以自然大小在主窗口中绘制图像。目前我需要渲染 EMF。

通过互联网浏览后,我找到了this MSDN example .

问题:

我已经试过了,发现效果不佳。

用户右键单击后,如说明所述,桌面屏幕截图会正确绘制在主窗口中。

但是,当用户调整窗口大小时,会出现如下图所示的绘画伪影。当用户稍微滚动然后调整窗口大小时,也会出现以下效果。

这是图片:

enter image description here

这是我第一次尝试滚动图像并使用滚动条,所以我真的很难找到解决方案。

问题:

How to fix article code to remove this visual artifact?

Can you recommend another example, like tutorial/code example/etc that I can study?

Can you provide "verbal" instructions/guidelines that could help me?

为了使您的任务更加轻松,这里是重现该问题的尽可能小的代码。请注意,我只是简单地复制/粘贴了窗口过程并为程序添加了最少的代码来创建工作演示:

#include <windows.h>

LRESULT CALLBACK WndProc(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);
}

// WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

// register main window class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"Main_Window";
wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);

if (!RegisterClassEx(&wc))
{
MessageBox(NULL, L"Window Registration Failed!", L"Error!",
MB_ICONEXCLAMATION | MB_OK);

return 0;
}

// create main window
hwnd = CreateWindowEx(0, L"Main_Window", L"Scrollable map",
WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
50, 50, 400, 400, NULL, NULL, hInstance, 0);

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

return Msg.wParam;
}

最佳答案

根据您的描述,问题似乎很简单,就是您的窗口在调整大小时没有重新绘制。

在放大窗口时使用 InvalidateRect 强制重新绘制新发现的区域,或者设置 CS_VREDRAWCS_HREDRAW 样式自动重绘客户区的窗口类。

关于c++ - 滚动大图像故障的 MSDN 示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30970778/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com