I have no idea how to move a bitmap with the arrow keys.
Here is my code

#include <windows.h>
#include <tchar.h>
#include <stdlib.h>
#include <string.h>
#include "Menu.h"
#include "Icon.h"



LPCTSTR		ClsName = L"App";											// Class name
LPCTSTR		WndName = L"WindowsAPI";									// Window title
HWND        hwnd;														// Handle to our main window



////////////////////////////////////////////////////

LRESULT CALLBACK WndProcedure(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam);

		   
////////////////////////////////////////////////////

					
				   INT WINAPI WinMain(HINSTANCE hInstance, 
				   HINSTANCE,
                   LPSTR lpCmdLine, 
				   int nCmdShow)
{
	MSG        Msg;														// Structure to hold messages for our WinProc
	WNDCLASSEX WndClsEx;												// Our WNDCLASSEX structure used to define a window

	// Define our window
	WndClsEx.cbSize			 = sizeof(WNDCLASSEX);									// The size in bytes of the structure
	WndClsEx.style			 = CS_HREDRAW | CS_VREDRAW;								// Style flags: CS_HREDRAW | CS_VREDRAW redraws the window on resize
	WndClsEx.lpfnWndProc	 = WndProcedure;										// Pointer to the windows procedure
	WndClsEx.cbClsExtra		 = 0;													// Extra bytes to allocate the window class structure
	WndClsEx.cbWndExtra		 = 0;													// Extra bytes to allocate the window instance structure
	WndClsEx.hIcon			 = LoadIcon(hInstance, (LPCTSTR)IDI_ICON);				// A handle to the window class's icon 
	WndClsEx.hCursor		 = LoadCursor(NULL, IDC_ARROW);							// A handle to the window class's cursor, this uses default
	WndClsEx.hbrBackground	 = (HBRUSH)GetStockObject(WHITE_BRUSH);					// A handle to the brush used to paint the background, we use white
	WndClsEx.lpszMenuName	 = MAKEINTRESOURCE(IDR_MAIN_MENU);						// We use the menu we created (IDR_MAIN_MENU)		
	WndClsEx.lpszClassName	 = ClsName;												// Class name
	WndClsEx.hInstance		 = hInstance;											// handle to the instance that contains the WinProc for the class
	WndClsEx.hIconSm		 = LoadIcon(WndClsEx.hInstance, (LPCTSTR)IDI_ICON);		// A handle to the window class's small icon 
	// If register class fails, exit with error message

	    if (!RegisterClassEx(&WndClsEx))
    {
        MessageBox(NULL,L"Call to RegisterClassEx failed!",L"Win32 Guided Tour",NULL);

        return 1;
    }

	// Create the window 
	hwnd = CreateWindowEx(0,
						  ClsName, WndName,								// Class name, Window title
						  WS_OVERLAPPEDWINDOW,							// Window style, WS_OVERLAPPEDWINDOW allows resizing
                          100, 100,										// x coord , y coord				
						  600, 500,										// Width, Height
						  NULL,											// Parent (if child)
						  NULL,											// hMenu
						  hInstance,									// Instance
						  NULL);										// Additional info not needed
	
	
  
	// Actually display the window
	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);

	// Decode and treat the messages
	while(GetMessage(&Msg, NULL, 0, 0))
	{
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}

	return Msg.wParam;
}


bool LoadAndBlitBitmap(HDC hWinDC, LPCWSTR szFileName, int x, int y)
{
	// Load the bitmap image file
	HBITMAP hBitmap;
	hBitmap = (HBITMAP)::LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0,
		LR_LOADFROMFILE);
	// Verify that the image was loaded
	if (hBitmap == NULL) {
		::MessageBox(NULL, __T("LoadImage Failed"), __T("Error"), MB_OK);
		return false;
	}

	// Create a device context that is compatible with the window
	HDC hLocalDC;
	hLocalDC = ::CreateCompatibleDC(hWinDC);
	// Verify that the device context was created
	if (hLocalDC == NULL) {
		::MessageBox(NULL, __T("CreateCompatibleDC Failed"), __T("Error"), MB_OK);
		return false;
	}

	// Get the bitmap's parameters and verify the get
	BITMAP qBitmap;
	int iReturn = GetObject(reinterpret_cast<HGDIOBJ>(hBitmap), sizeof(BITMAP),
		reinterpret_cast<LPVOID>(&qBitmap));
	if (!iReturn) {
		::MessageBox(NULL, __T("GetObject Failed"), __T("Error"), MB_OK);
		return false;
	}

	// Select the loaded bitmap into the device context
	HBITMAP hOldBmp = (HBITMAP)::SelectObject(hLocalDC, hBitmap);
	if (hOldBmp == NULL) {
		::MessageBox(NULL, __T("SelectObject Failed"), __T("Error"), MB_OK);
		return false;
	}

	// Blit the dc which holds the bitmap onto the window's dc
	BOOL qRetBlit = ::BitBlt(hWinDC, x, y, qBitmap.bmWidth, qBitmap.bmHeight,
		hLocalDC, 0, 0, SRCCOPY);
	if (!qRetBlit) {
		::MessageBox(NULL, __T("Blit Failed"), __T("Error"), MB_OK);
		return false;
	}

	// Unitialize and deallocate resources
	::SelectObject(hLocalDC, hOldBmp);
	::DeleteDC(hLocalDC);
	::DeleteObject(hBitmap);
	return true;
}

////////////////////////////////////////////////////

LRESULT CALLBACK WndProcedure(HWND hwnd,			// Handle to our main window
							  UINT Msg,				// Our message that needs to be processed
							  WPARAM wParam,		// Extra values of message (Mouse for example might have x and y coord values)
							  LPARAM lParam)		// Extra values of message (Mouse for example might have x and y coord values)
{
		PAINTSTRUCT ps;
    HDC hdc;
	int x = 0;
	int y = 0;
    switch(Msg)
	{
		case WM_DESTROY:								// If a close message is sent to the message loop
			PostQuitMessage(WM_QUIT);					// Exit
			break;
			case WM_KEYDOWN:
{
    switch (wParam) {
        case VK_LEFT:
        {
            break;
        }
        case 'X':
        {
            ::MessageBox(hwnd, _T("X") , _T("Key Pressed"), MB_OK);
            break;
        }
    }
    break;
}
			case WM_CLOSE:
    if (MessageBox(hwnd, L"Really quit?", L"My application", MB_YESNO|MB_ICONQUESTION) == IDYES)
    {
        DestroyWindow(hwnd);
    }
    // Else: User canceled. Do nothing.
    return 0;
	break;
				case WM_INITDIALOG:
		return TRUE;
			case WM_PAINT:
		
				{
	
    
    hdc = BeginPaint(hwnd, &ps);



LoadAndBlitBitmap(hdc, __T("Rocket.bmp"), 0, 0);
LoadAndBlitBitmap(hdc, __T("Rocket2.bmp"), x, y);
HPEN hPenOld;

// Draw a red line
HPEN hLinePen;
COLORREF qLineColor;
qLineColor = RGB(255, 0, 0);
hLinePen = CreatePen(PS_SOLID, 7, qLineColor);
hPenOld = (HPEN)SelectObject(hdc, hLinePen);

MoveToEx(hdc, 500, 100, NULL);
LineTo(hdc, 100, 250);

MoveToEx(hdc, 100, 100, NULL);
LineTo(hdc, 500, 250);

SelectObject(hdc, hPenOld);
DeleteObject(hLinePen);
    break;
				}
		// This message is sent when the user selects a command item from a menu,
		// when a control sends a message to its parent window, 
		// or when an accelerator keystroke is translated.
		case WM_COMMAND:
		{
			// Value of the low-order word of wParam. 
			// Specifies the identifier of the menu item, control, or accelerator. 
			switch(LOWORD(wParam))
			{
				case IDM_EXIT:
					if (MessageBox(hwnd, L"Really quit?", L"My application", MB_YESNO|MB_ICONQUESTION) == IDYES)
    {
        DestroyWindow(hwnd);
    }
    // Else: User canceled. Do nothing.
    return 0;
	break;
					case IDM_ABOUT:
			{
				::MessageBox(hwnd, _T("Test") , _T("My Application"), MB_OK|MB_ICONASTERISK);
				break;
			}
			}
		}
		break;
	  
		default:										// Handle all other messages in a normal way
			return DefWindowProc(hwnd, Msg, wParam, lParam);
	}
	
    return 0;
}

Recommended Answers

All 24 Replies

You did not post Icon.h and Menu.h..

These are my resources

lines 143, 144 corresponds with line 185. If you wanted to you could delete lines 143, 144 and replace x any on line 185 with two numbers.

I see you are drawing the bitmaps directly. Then you'll have to get the arrow keystrokes from the main window and then determine which bitmap is to be moved. Perhaps you could get mouse pointer coordinates at a WM_LBUTTONDOWN message and then decide which bitmap is to get attention.

I see you are drawing the bitmaps directly. Then you'll have to get the arrow keystrokes from the main window and then determine which bitmap is to be moved. Perhaps you could get mouse pointer coordinates at a WM_LBUTTONDOWN message and then decide which bitmap is to get attention.

Could you give an example. Isn't WM_LBUTTONDOWN for mouse clicks?

Could I use a bool statment?

Could you give an example. Isn't WM_LBUTTONDOWN for mouse clicks?

WM_LBUTTONDOWN is for mouse clicks, yes. But I saw you had two bitmaps so I thought you might want to decide which of them to move, otherwise handle WM_KEYDOWN. I'll write you a short example.

Here you go. This is one way to go, it does not demonstrate how to select which bitmap to move but that wasn't the question either.

Also, the bitmap will flicker. To prevent that you could either not paint the bitmaps directly but assign them to static controls or use double buffering.

#include <windows.h>

struct
{
    int x, y;
} pos = {0};

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_PAINT:
            {
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hwnd, &ps);

                HBITMAP hbm = LoadBitmap(GetModuleHandle(NULL),
                                          MAKEINTRESOURCE(IDB_BITMAP1));
			//This would be a bitmap from a resource file
                HDC hdcTmp = CreateCompatibleDC(hdc);
                HBITMAP hbmOld = (HBITMAP)SelectObject(hdcTmp, hbm);

                BitBlt(hdc, pos.x, pos.y, 100, 100, hdcTmp, 0, 0, SRCCOPY);

                EndPaint(hwnd, &ps);
                SelectObject(hdcTmp, hbmOld);
                DeleteDC(hdcTmp);
                DeleteObject(hbm);
            }
            break;

        case WM_KEYDOWN:
        {
            switch(wParam)
            {
                case VK_RIGHT:
                    pos.x++;
                    InvalidateRect(hwnd, NULL, TRUE);
                    break;
                case VK_LEFT:
                    pos.x--;
                    InvalidateRect(hwnd, NULL, TRUE);
                    break;
                case VK_UP:
                    pos.y--;
                    InvalidateRect(hwnd, NULL, TRUE);
                    break;
                case VK_DOWN:
                    pos.y++;
                    InvalidateRect(hwnd, NULL, TRUE);
                    break;
            }
        }
        break;

	//Other cases
    }
    return 0;
}

INT APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
   //Register the class and create window etc..
}

Thanks, It worked but does it matter if you don't load the bitmap as a resource. I didn't. I know how to select the one I want to move. All I need to do now is to stop it flickering. Which is better, assigning them to static controls or to use double buffering?

Could you give me some help with double buffering. From what I've heard, that's the best solution to the problem.

Double buffering is a bit tricky. Basically you create a second/third DC and do all your painting into that one and then BitBlt() everything into the main DC.

Take a look at this page to see an example:
http://www.winprog.org/tutorial/animation.html

A couple of things to consider are:

If using InvalidateRect(), let the last parameter be FALSE, so that windows doesn't assume the window to be "dirty".

When painting anywhere else than in WM_PAINT, use GetDC() and ReleaseDC() instead of BeginPaint() and EndPaint(). This way you can just do all the painting through a function and call it from anywhere, for example the case labels.

What do I put in instead of prc->right?

That's the width of the client area of the window.
Get it like this:

RECT rcClient;
GetClientRect(hwnd, &rcClient);

This is the code I am trying to adapt:

bool LoadAndBlitBitmap(HDC hWinDC, LPCWSTR szFileName, int x, int y)
{
	// Load the bitmap image file
	HBITMAP hBitmap;
	hBitmap = (HBITMAP)::LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0,
		LR_LOADFROMFILE);
	// Verify that the image was loaded
	if (hBitmap == NULL) {
		::MessageBox(NULL, __T("LoadImage Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Create a device context that is compatible with the window
	HDC hLocalDC;
	hLocalDC = ::CreateCompatibleDC(hWinDC);
	// Verify that the device context was created
	if (hLocalDC == NULL) {
		::MessageBox(NULL, __T("CreateCompatibleDC Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Get the bitmap's parameters and verify the get
	BITMAP qBitmap;
	int iReturn = GetObject(reinterpret_cast<HGDIOBJ>(hBitmap), sizeof(BITMAP),
		reinterpret_cast<LPVOID>(&qBitmap));
	if (!iReturn) {
		::MessageBox(NULL, __T("GetObject Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Select the loaded bitmap into the device context
	HBITMAP hOldBmp = (HBITMAP)::SelectObject(hLocalDC, hBitmap);
	if (hOldBmp == NULL) {
		::MessageBox(NULL, __T("SelectObject Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Blit the dc which holds the bitmap onto the window's dc
	BOOL qRetBlit = ::BitBlt(hWinDC, x, y, qBitmap.bmWidth, qBitmap.bmHeight,
		hLocalDC, 0, 0, SRCCOPY);
	if (!qRetBlit) {
		::MessageBox(NULL, __T("Blit Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Unitialize and deallocate resources
	::SelectObject(hLocalDC, hOldBmp);
	::DeleteDC(hLocalDC);
	::DeleteObject(hBitmap);
	return true;
}

Everything I do seems to do nothing.
This the code in the paint section.

LoadAndBlitBitmap(hdc, __T("Rocket2.bmp"), pos.x, pos.y);

It looks like it should work. How and where do you obtain hdc?

Sorry, I didn't explain very well. This code works but it doesn't double buffer. I took out all of the code that should have made it double buffer as it didn't work. I need help making this code double buffer.

That is correct, it does not double buffer. You need a third DC in which you do all the painting before you BitBlt() everything from that DC into the main DC.

This is what I have done to the code:

bool LoadAndBlitBitmap(HDC hWinDC, LPCWSTR szFileName, int x, int y)
{
	RECT rcClient;
GetClientRect(hwnd, &rcClient);

	// Load the bitmap image file
	HBITMAP hBitmap;

	hBitmap = (HBITMAP)::LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0,
		LR_LOADFROMFILE);
	// Verify that the image was loaded
	if (hBitmap == NULL) {
		::MessageBox(NULL, __T("LoadImage Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Create a device context that is compatible with the window
	HDC  hdcBuffer;
	hdcBuffer = ::CreateCompatibleDC(hWinDC);

	HBITMAP hbmBuffer;
		hbmBuffer= ::CreateCompatibleBitmap(hWinDC, rcClient.right, rcClient.bottom);
	// Verify that the device context was created
	if ( hdcBuffer == NULL) {
		::MessageBox(NULL, __T("CreateCompatibleDC Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Get the bitmap's parameters and verify the get
	BITMAP qBitmap;
	int iReturn = GetObject(reinterpret_cast<HGDIOBJ>(hBitmap), sizeof(BITMAP),
		reinterpret_cast<LPVOID>(&qBitmap));
	if (!iReturn) {
		::MessageBox(NULL, __T("GetObject Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Select the loaded bitmap into the device context
	HBITMAP hbmOldBuffer = (HBITMAP)::SelectObject(hdcBuffer, hdmBuffer);
	if (hbmOldBuffer == NULL) {
		::MessageBox(NULL, __T("SelectObject Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Blit the dc which holds the bitmap onto the window's dc
	BOOL qRetBlit = ::BitBlt(hWinDC, x, y, rcClient.right, rcClient.bottom,
		hdcBuffer, 0, 0, SRCCOPY);
	if (!qRetBlit) {
		::MessageBox(NULL, __T("Blit Failed"), __T("Error"), MB_OK);
		return false;
	}
 
	// Unitialize and deallocate resources
	::SelectObject(hdcBuffer, hbmOldBuffer);
	::DeleteDC(hdcBuffer);
	::DeleteObject(hbmBuffer);
	return true;
}

It doesn't work. I get the error 'error C2065: 'hdmBuffer' : undeclared identifier'

Row 39. Change to hbmBuffer.

I changed that and it didn't work. I think it may be to do with these lines

bool LoadAndBlitBitmap(HDC hWinDC, LPCWSTR szFileName, int x, int y)

HBITMAP hbmBuffer;
		hbmBuffer= ::CreateCompatibleBitmap(hWinDC, rcClient.right, rcClient.bottom);

Is there something in these lines that isn't right?

I've found the answer. The LoadAndBlitBitmap code was fine, but I needed to add some code too the paint section. This is the code I added.

RECT rcClient;
GetClientRect(hwnd,&rcClient);
 //Create a device context that is compatible with the window
HDC hMemDC;
hMemDC = ::CreateCompatibleDC(hdc);
// Verify that the device context was created
if (hMemDC == NULL) {
		::MessageBox(NULL, __T("CreateCompatibleDC Failed"), __T("Error"), MB_OK);
		return false;
	}
HBITMAP hBitmap = CreateCompatibleBitmap(hdc,rcClient.right, rcClient.bottom);
 int savedDC = SaveDC(hMemDC);

SelectObject(hMemDC,hBitmap);
 LoadAndBlitBitmap(hMemDC, __T("Rocket.bmp"), 0, 0);
LoadAndBlitBitmap(hMemDC, __T("Rocket2.bmp"), pos.x, pos.y); BitBlt(hdc,0,0,rcClient.right,rcClient.bottom,hMemDC,0,0,SRCCOPY);

 RestoreDC(hMemDC,savedDC);

DeleteObject(hBitmap);
DeleteObject(hMemDC);

Yes, that was the third dc I was talking about. If you want you could move that code into the function.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.