在屏幕上绘制图像后的背景更改

时间:2013-11-19 13:53:22

标签: c++ visual-studio winapi uigesturerecognizer multi-touch

我们正在使用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;
}

1 个答案:

答案 0 :(得分:0)

我现在看到了问题。您有GDI资源泄漏。

在两个地方你叫CreateSolidBrush,但你永远不会删除你创建的画笔。你在这里做到了

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

在这里

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

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

您还需要发布您已注释掉的位图:DeleteObject(hMemBmp),并按照我在评论中说的那样删除对ReleaseDC的调用。

通常,您应该仔细跟踪您创建的所有GDI对象,并确保在完成它们后删除它们。