在屏幕上绘制图像后背景发生变化

Background changes after images are drawn on the screen

本文关键字:背景 变化 图像 屏幕 绘制      更新时间:2023-10-16

我们在课堂上使用C++中的Visual Studios 2012学习windows原始触摸事件。我让我的演示发挥了作用,它确实做到了它应该做的事情,那就是在你的指尖下画圆圈,以检测触摸事件是否被触发。但过了一段时间后,如果你还在屏幕上画圆圈,屏幕就会变成蓝色!圆圈仍然显示,但它们是蓝色的,有黑色的轮廓,我仍然可以移动它们。我给教授看了看,他似乎不明白,这就是我来这里的原因。有人能看看我的代码,让我知道它的原因吗?

// GT_HelloWorldWin32.cpp
// compile with: /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c
    #ifndef WINVER // Specifies that the minimum required platform is Windows 7.
#define WINVER 0x0601 // Change this to the appropriate value to target other versions of Windows.
#endif
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows 7.
#define _WIN32_WINNT 0x0601 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <windows.h> // for windows touch
#include <windowsx.h> // included for point conversion
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include "wtypes.h"
#include <iostream>
using namespace std;
// The main window class name.
TCHAR szWindowClass[] = _T("win32app");
// The string that appears in the application's title bar.
TCHAR szTitle[] = _T("Hello World!");
//Instancing the handler
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//Maximum ammount of touches allowed
#define MAXPOINTS 10
// You will use this array to track touch points
int points[MAXPOINTS][2];
// You will use this array to switch the color / track ids
int idLookup[MAXPOINTS];
// You can make the touch points larger
// by changing this radius value
static int radius = 30;
// There should be at least as many colors
// as there can be touch points so that you
// can have different colors for each point
COLORREF colors[] = { RGB(153,255,51), 
RGB(153,0,0), 
RGB(0,153,0), 
RGB(255,255,0), 
RGB(255,51,204), 
RGB(0,0,0),
RGB(0,153,0), 
RGB(153, 255, 255), 
RGB(153,153,255), 
RGB(0,51,153)
};
int wmId, wmEvent, i, x, y, index;
UINT cInputs;
PTOUCHINPUT pInputs;
POINT ptInput; 
// This function is used to return an index given an ID
int GetContactIndex(int dwID){
for (int i=0; i < MAXPOINTS; i++){
if (idLookup[i] == -1){
idLookup[i] = dwID;
return i;
}else{
if (idLookup[i] == dwID){
return i;
}
}
}
// Out of contacts
return -1;
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wcex;
int width = 0, height = 0; // Screen resolution
GetScreenResolution(width, height);
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
hInst = hInstance; // Store instance handle in our global variable
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application does not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
800, 600,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd) {
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
// register the window for touch instead of gestures
RegisterTouchWindow(hWnd, 0); 
// the following code initializes the points
for (int i=0; i< MAXPOINTS; i++){
points[i][0] = -1;
points[i][1] = -1;
idLookup[i] = -1;
} 
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes touch messages for the main window.
//
// WM_TOUCH - handles WM_TOUCH messages in the application
// WM_DESTROY - post a quit message and return
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// For double buffering
static HDC memDC = 0;
static HBITMAP hMemBmp = 0;
HBITMAP hOldBmp = 0; 
//For drawing / fills
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_TOUCH:
//LOWORD(wParam) = number of touch points in this message
//HIWORD(wParam) = reserved for future use
//lParam = handle for use with GetTouchInputInfo
cInputs = LOWORD(wParam);
pInputs = new TOUCHINPUT[ cInputs ];
if(pInputs)
{
if( GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT)) )
{
for (int i=0; i < static_cast<INT>(cInputs); i++)
{
TOUCHINPUT ti = pInputs[i];
index = GetContactIndex(ti.dwID);
if(ti.dwID != 0 && index < MAXPOINTS )
{
//get screen corrdinates of touch
ptInput.x = TOUCH_COORD_TO_PIXEL(ti.x);
ptInput.y = TOUCH_COORD_TO_PIXEL(ti.y);
//get coordinates relative to the top left of the application window
ScreenToClient(hWnd, &ptInput);
if(ti.dwFlags & TOUCHEVENTF_UP)
{
points[index][0] = -1;
points[index][1] = -1;
}
else
{
points[index][0] = ptInput.x;
points[index][1] = ptInput.y;
}
}
}
}
CloseTouchInputHandle((HTOUCHINPUT)lParam);
delete [] pInputs;
}
InvalidateRect(hWnd, NULL, FALSE);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
RECT client;
GetClientRect(hWnd, &client); 
//START DOUBLE BUFFERING
if (!memDC)
{
memDC = CreateCompatibleDC(hdc);
}
hMemBmp = CreateCompatibleBitmap(hdc, client.right, client.bottom);
hOldBmp = (HBITMAP)SelectObject(memDC, hMemBmp); 
FillRect(memDC, &client, CreateSolidBrush(RGB(255,255,255)));
//Draw Touched Points 
for (i=0; i < MAXPOINTS; i++)
{
SelectObject( memDC, CreateSolidBrush(colors[i])); 
x = points[i][0];
y = points[i][1];
if (x >0 && y>0)
{ 
Ellipse(memDC, x - radius, y - radius, x + radius, y + radius);
}
}
BitBlt(hdc, 0,0, client.right, client.bottom, memDC, 0,0, SRCCOPY);
EndPaint(hWnd, &ps);
ReleaseDC(hWnd, hdc);
//DeleteObject(hMemBmp); 
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

我现在看到问题了。你有一个GDI资源泄漏。

在两个位置,您调用CreateSolidBrush,但从未删除创建的笔刷。你在这里做

FillRect(memDC, &client, CreateSolidBrush(RGB(255,255,255)));

这里是

SelectObject( memDC, CreateSolidBrush(colors[i]));

实际上,您应该将每个CreateSolidBrush函数的结果分配给一个HBRUSH,然后在完成后调用它的DeleteObject

您还需要释放已注释掉的位图:DeleteObject(hMemBmp),并删除对ReleaseDC的调用,正如我在注释中所说。

一般来说,您应该仔细跟踪您创建的所有GDI对象,并确保在完成这些对象后将其删除。