我的英语不好,所以,如果你不能理解我的问题,我很抱歉。
描述: 我正在使用win32 api制作一个绘画程序,当我尝试解决使用鼠标画线时,将线保留在画布中,它不能很好地工作。
代码: 这是Win进程函数
LRESULT MainWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int canvasWidth = 1200; //初始的画布大小, initialize canvas width
static int canvasHeight = 700; //初始的画布大小, initialize canvas height
static int workWidth = canvasWidth + 60; //设定的工作区大小, set work area width
static int workHeight = canvasHeight + 60; //设定的工作区大小, set work area height
static std::vector<Scroll*> scrolls; //滚动条容器, Scroll container
static RECT clientRC; //窗口客户区矩形, window client rectangle
static HDC hMemDC; //内存设备上下文, memory device context
static HBITMAP hMemBM; //内存位图, memory bitmap
static POINT ptPreviouse; //鼠标上一次位置, previous mouse position
static POINT ptCurrent; //鼠标当前位置, current mouse position
static bool bDraw = false; //是否开始绘制, whether to start drawing
static HDC hDC; //绘图设备上下文, drawing device context
static RECT canvasRect; //画布区域, canvas area
TRACKMOUSEEVENT mouseEvent; //鼠标追踪事件, mouse track event
static int CanvasLTop_X = 0; //画布的左上x坐标, canvas left top x
static int CanvasLTop_Y = 0; //画布的左上y坐标, canvas left top y
static int OldCanvasLTop_X = 0; //上一个画布的左上x坐标, previous canvas left top x
static int OldCanvasLTop_Y = 0; //上一个画布的左上y坐标, previous canvas left top y
static int VscrollPos = 0; //垂直滚动条位置, vertical scroll bar position
static int HscrollPos = 0; //水平滚动条位置, horizontal scroll bar position
switch (message)
{
case WM_COMMAND:
{
// 分析菜单选择:
//analysis menu selection
switch (LOWORD(wParam))
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, MainWindow::About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDC_BUTTON1:
// TODO: 在此处添加按钮事件处理代码...
//TODO: add button event handling code here...
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_CREATE:
{
// TODO: 在此处添加控件创建代码...
//TODO: add control creation code here...
GetClientRect(hWnd, &clientRC);
hDC = GetDC(hWnd);
//创建垂直滚动条
//create vertical scroll bar
Scroll* VerticalScroll = new Scroll(hWnd, SB_VERT, 0, workHeight, clientRC.bottom);
scrolls.push_back(VerticalScroll);
//创建水平滚动条
//create horizontal scroll bar
Scroll* HorizontalScroll = new Scroll(hWnd, SB_HORZ, 0, workWidth, clientRC.right);
scrolls.push_back(HorizontalScroll);
//创建内存设备上下文
//create memory device context
hMemDC = CreateCompatibleDC(hDC);
hMemBM= CreateCompatibleBitmap(hDC, canvasWidth, canvasHeight);
SelectObject(hMemDC, hMemBM);
PatBlt(hMemDC, 0, 0, clientRC.right, clientRC.bottom, WHITENESS);
ReleaseDC(hWnd, hDC);
}
break;
case WM_DRAWITEM:
{
DRAWITEMSTRUCT* ptrDIS = (DRAWITEMSTRUCT*)lParam; // 转换为DRAWITEMSTRUCT结构, convert to DRAWITEMSTRUCT structure
// TODO: 在此处添加绘制控件代码...
//TODO: add control drawing code here...
}
break;
case WM_SIZE:
{
// TODO: 在此处添加大小变化事件处理代码...
//TODO: add size change event handling code here...
hDC = GetDC(hWnd);
//将内容保存至临时位图
//copy content to temporary bitmap
HDC tempDC = CreateCompatibleDC(hDC);
HBITMAP tempBM = CreateCompatibleBitmap(hDC, clientRC.right, clientRC.bottom);
SelectObject(tempDC, tempBM);
BitBlt(tempDC, 0, 0, clientRC.right, clientRC.bottom, hMemDC, 0, 0, SRCCOPY);
GetClientRect(hWnd, &clientRC);
//更新滚动条信息
//update scroll bar information
for (Scroll* scroll : scrolls)
{
if (scroll->widgeType == SB_VERT)
{
SCROLLINFO newVSI = scroll->GetScrollStruct();
newVSI.cbSize = sizeof(SCROLLINFO);
newVSI.fMask = SIF_ALL;
newVSI.nMax = workHeight;
newVSI.nPage = clientRC.bottom;
scroll->UpdateScrollInfo(hWnd, newVSI);
}
if (scroll->widgeType == SB_HORZ)
{
SCROLLINFO newHSI = scroll->GetScrollStruct();
newHSI.cbSize = sizeof(SCROLLINFO);
newHSI.fMask = SIF_ALL;
newHSI.nMax = workWidth;
newHSI.nPage = clientRC.right;
scroll->UpdateScrollInfo(hWnd, newHSI);
}
}
//计算画布的新位置
//calculate new canvas position
if (clientRC.right - 45 < canvasWidth) CanvasLTop_X = 30;
else CanvasLTop_X = (clientRC.right - canvasWidth) / 2;
if (clientRC.bottom - 45 < canvasHeight) CanvasLTop_Y = 30;
else CanvasLTop_Y = (clientRC.bottom - canvasHeight) / 2;
//将临时位图内容复制到内存设备上下文
//copy temporary bitmap content to memory device context
hMemDC= CreateCompatibleDC(hDC);
hMemBM = CreateCompatibleBitmap(hDC, clientRC.right, clientRC.bottom);
SelectObject(hMemDC, hMemBM);
PatBlt(hMemDC, 0, 0, clientRC.right, clientRC.bottom, WHITENESS);
BitBlt(hMemDC, CanvasLTop_X, CanvasLTop_Y, canvasWidth, canvasHeight, tempDC, OldCanvasLTop_X, OldCanvasLTop_Y, SRCCOPY);
//更新画布坐标
//update canvas coordinates
OldCanvasLTop_X = CanvasLTop_X;
OldCanvasLTop_Y = CanvasLTop_Y;
DeleteObject(tempBM);
DeleteDC(tempDC);
}
break;
case WM_PAINT:
{
// TODO: 在此处添加使用 hdc 的任何绘图代码...
//TODO: add any drawing code using hdc here...
PAINTSTRUCT ps;
hDC = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &clientRC);
//获取滚动条位置
//get scroll bar position
for (Scroll* scroll : scrolls)
{
if (scroll->widgeType == SB_VERT)
{
VscrollPos = scroll->GetScrollPos(hWnd);
}
if (scroll->widgeType == SB_HORZ)
{
HscrollPos = scroll->GetScrollPos(hWnd);
}
}
//跟新画布区域
//update canvas area
canvasRect = { CanvasLTop_X - HscrollPos, CanvasLTop_Y - VscrollPos , CanvasLTop_X + canvasWidth - HscrollPos, CanvasLTop_Y + canvasHeight - VscrollPos };
//将内存设备上下文内容复制到窗口设备上下文
//copy memory device context content to drawing device context
BitBlt(hDC, canvasRect.left, canvasRect.top, canvasWidth, canvasHeight, hMemDC, canvasRect.left, canvasRect.top, SRCCOPY);
EndPaint(hWnd, &ps);
ReleaseDC(hWnd, hDC);
}
break;
case WM_VSCROLL:
{
// TODO: 在此处添加垂直滚动条事件处理代码...
//TODO: add vertical scroll bar event handling code here...
SCROLLINFO verticalSI;
for (Scroll* scroll : scrolls)
{
if (scroll->widgeType == SB_VERT)
{
verticalSI = scroll->GetScrollStruct();
int newPos = scroll->GetScrollPos(hWnd);
switch (LOWORD(wParam))
{
case SB_LINEUP:
newPos -= 10;
break;
case SB_LINEDOWN:
newPos += 10;
break;
case SB_PAGEUP:
newPos -= verticalSI.nPage;
break;
case SB_PAGEDOWN:
newPos += verticalSI.nPage;
break;
case SB_THUMBTRACK:
newPos = verticalSI.nTrackPos;
break;
}
if (newPos < 0) newPos = 0;
if (newPos > verticalSI.nMax - verticalSI.nPage) newPos = verticalSI.nMax - verticalSI.nPage;
ScrollWindowEx(hWnd, 0, scroll->GetScrollPos(hWnd) - newPos, nullptr, nullptr, nullptr, nullptr, SW_INVALIDATE | SW_ERASE);
scroll->UpdateScrollInfo(hWnd, newPos);
UpdateWindow(hWnd);
break;
}
}
}
break;
case WM_HSCROLL:
{
// TODO: 在此处添加水平滚动条事件处理代码...
//TODO: add horizontal scroll bar event handling code here...
for (Scroll* scroll : scrolls)
{
if (scroll->widgeType == SB_HORZ)
{
SCROLLINFO horizontalSI = scroll->GetScrollStruct();
int newPos = scroll->GetScrollPos(hWnd);
switch (LOWORD(wParam))
{
case SB_LINEUP:
newPos -= 10;
break;
case SB_LINEDOWN:
newPos += 10;
break;
case SB_PAGEUP:
newPos -= horizontalSI.nPage;
break;
case SB_PAGEDOWN:
newPos += horizontalSI.nPage;
break;
case SB_THUMBTRACK:
newPos = horizontalSI.nTrackPos;
break;
}
if (newPos < 0) newPos = 0;
if (newPos > horizontalSI.nMax - horizontalSI.nPage) newPos = horizontalSI.nMax - horizontalSI.nPage;
ScrollWindowEx(hWnd, scroll->GetScrollPos(hWnd) - newPos, 0, nullptr, nullptr, nullptr, nullptr, SW_INVALIDATE | SW_ERASE);
scroll->UpdateScrollInfo(hWnd, newPos);
UpdateWindow(hWnd);
break;
}
}
}
break;
case WM_LBUTTONDOWN:
{
hDC = GetDC(hWnd);
bDraw = true;
ptPreviouse.x = LOWORD(lParam);
ptPreviouse.y = HIWORD(lParam);
}
break;
case WM_MOUSEMOVE:
{
if (bDraw)
{
MoveToEx(hMemDC, ptPreviouse.x, ptPreviouse.y, nullptr);
LineTo(hMemDC, LOWORD(lParam), HIWORD(lParam));
BitBlt(hDC, canvasRect.left, canvasRect.top, canvasWidth, canvasHeight, hMemDC, canvasRect.left, canvasRect.top, SRCCOPY);
ptPreviouse.x = LOWORD(lParam);
ptPreviouse.y = HIWORD(lParam);
mouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
mouseEvent.dwFlags = TME_LEAVE;
mouseEvent.hwndTrack = hWnd;
TrackMouseEvent(&mouseEvent);
}
}
break;
case WM_LBUTTONUP:
{
bDraw = false;
ReleaseDC(hWnd, hDC);
}
break;
case WM_MOUSELEAVE:
{
bDraw = false;
ReleaseDC(hWnd, hDC);
}
break;
case WM_DESTROY:
{
//释放scrolls容器中的对象
//release objects in scrolls container
for (Scroll* scroll : scrolls)
{
delete scroll;
}
scrolls.clear();
PostQuitMessage(0);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
效果: 第一次抽奖 首先画一个“?” 向下滚动窗口: 滚动至底部 向后滚动: 滚动到顶部 第二次抽奖 绘制一个新对象
我的技术很差。不知道怎么解决。
请勿在
WM_PAINT
消息处理程序之外直接在窗口上绘制。 下次重新绘制窗口时,您绘制的任何内容都将被删除。
您有几个选择:
让你的鼠标处理程序将坐标保存在丢失的地方,然后仅响应
WM_PAINT
绘制所有线条。
创建一个与窗口大小相同的内存位图,并让鼠标处理程序在该位图上绘制线条。然后使用
WM_PAINT
将当前位图绘制到窗口上。