Breadatarian Breadatarian - 1 month ago 18
C++ Question

C++ changing image on user input in WinAPI

I am having issues in getting my .bmp image displayed to change to another one on user input. The image can be successfully printed at the start (

title.bmp
), but is supposed to change when pressing 1 or 2 followed by enter (to
introduction.bmp
&
start.bmp
). I must be missing something!

Where this happens is around the bottom of the code from
while (running == 1) {
so skip down to there.
I am using
loadImage("title.bmp");
to print my images (I change the filename appropriately of course), and
cin >> menuSelection;
to pause the program and wait until the user presses one or two followed by enter.

I've searched many, many pages on how to print and change images in WinAPI, and this is the closest I can get. If there is any other information I have missed please tell me and I will comment it. Thanks in advance for helping!

//These are the libraries (external files) to include at the start.
#include <cstdio>
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>

using namespace std;

//Defining the [global] variables that will be used throughout the program
int running = 1;
int menuSelection = 0;
int userInput;
int userInputDummy;
int intPointer;

//Starter variables used in creating a window and printing images. These are global.
HDC imageDC; // the DC to hold our image
HBITMAP imageBmp; // the actual bitmap which contains the image (will be put in the DC)
HBITMAP imageBmpOld; // the DC's old bitmap (for cleanup)

const int screenSize_X = 640;
const int screenSize_Y = 480;

//Functions! Sections of code to re-used in the program

// Function to load the image into our DC so we can draw it to the screen
void loadImage(const char* pathname)
{
imageDC = CreateCompatibleDC(NULL); // create an offscreen DC

imageBmp = (HBITMAP)LoadImageA( // load the bitmap from a file
NULL, // not loading from a module, so this is NULL
pathname, // the path we're loading from
IMAGE_BITMAP, // we are loading a bitmap
0, 0, // don't need to specify width/height
LR_DEFAULTSIZE | LR_LOADFROMFILE// use the default bitmap size (whatever the file is), and load it from a file
);

imageBmpOld = (HBITMAP)SelectObject(imageDC, imageBmp); // put the loaded image into our DC
}

// Function to clean up
void cleanUpImage()
{
SelectObject(imageDC, imageBmpOld); // put the old bmp back in our DC
DeleteObject(imageBmp); // delete the bmp we loaded
DeleteDC(imageDC); // delete the DC we created
}

// The function to draw our image to the display (the given DC is the screen DC)
void drawImage(HDC screen)
{
BitBlt(
screen, // tell it we want to draw to the screen
0, 0, // as position 0,0 (upper-left corner)
screenSize_X, // width of the rect to draw
screenSize_Y, // height of the rect
imageDC, // the DC to get the rect from (our image DC)
0, 0, // take it from position 0,0 in the image DC
SRCCOPY // tell it to do a pixel-by-pixel copy
);
}

// A callback to handle Windows messages as they happen
LRESULT CALLBACK wndProc(HWND wnd, UINT msg, WPARAM w, LPARAM l)
{
// what kind of message is this?
switch (msg)
{
// we are interested in WM_PAINT, as that is how we draw
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC screen = BeginPaint(wnd, &ps); // Get the screen DC
drawImage(screen); // draw our image to our screen DC
EndPaint(wnd, &ps); // clean up
}break;

// we are also interested in the WM_DESTROY message, as that lets us know when to close the window
case WM_DESTROY:
PostQuitMessage(0);
break;
}

// for everything else, let the default window message handler do its thing
return DefWindowProc(wnd, msg, w, l);
}

// A function to create the window and get it set up
HWND createWindow(HINSTANCE inst)
{
WNDCLASSEX wc = { 0 }; // create a WNDCLASSEX struct and zero it
wc.cbSize = sizeof(WNDCLASSEX); // tell windows the size of this struct
wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); // tell it to use the normal arrow cursor for this window
wc.hInstance = inst; // give it our program instance
wc.lpfnWndProc = wndProc; // tell it to use our wndProc function to handle messages
wc.lpszClassName = TEXT("DisplayImage"); // give this window class a name.

RegisterClassEx(&wc); // register our window class with Windows

// the style of the window we want... we want a normal window but do not want it resizable.
int style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; // normal overlapped window with a caption and a system menu (the X to close)

// Figure out how big we need to make the window so that the CLIENT area (the part we will be drawing to) is
// the desired size
RECT rc = { 0,0,screenSize_X,screenSize_Y }; // desired rect
AdjustWindowRect(&rc, style, FALSE); // adjust the rect with the given style, FALSE because there is no menu

return CreateWindow( // create the window
TEXT("DisplayImage"), // the name of the window class to use for this window (the one we just registered)
TEXT("Display an Image"), // the text to appear on the title of the window
style | WS_VISIBLE, // the style of this window (OR it with WS_VISIBLE so it actually becomes visible immediately)
100, 100, // create it at position 100,100
rc.right - rc.left, // width of the window we want
rc.bottom - rc.top, // height of the window
NULL, NULL, // no parent window, no menu
inst, // our program instance
NULL); // no extra parameter

}

//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

// _________________________________________________________________________________________
// The actual entry point for the program!
// This is Windows' version of the 'main' function:
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int show)
{
// load our image
loadImage("title.bmp");

// create our window
HWND wnd = createWindow(inst);

// Do the message pump! keep polling for messages (and respond to them)
// until the user closes the window.
MSG msg;

while (GetMessage(&msg, wnd, 0, 0)) // while we are getting non-WM_QUIT messages...
TranslateMessage(&msg); // translate them
DispatchMessage(&msg); // and dispatch them (our wndProc will process them)
{

while (running == 1) {
//Welcoming the user to the program, and asking them what they want to do (starts functions)
cin >> menuSelection;

//Selecting the introduction option
if (menuSelection == 1) {
loadImage("introduction.bmp");
cin >> userInputDummy;
menuSelection = 0;
}
//Selecting the start option
else if (menuSelection == 2) {
loadImage("start");
cin >> userInputDummy;
menuSelection = 0;
}
//Selecting the exit option
else if (menuSelection == 3) {
menuSelection = 0;
running = 0;
}
}
// once the user quits....
cleanUpImage();
return 0;
return EXIT_SUCCESS;
}
}

Answer

you cannot use cin in win32 use an editbox then get the user's input from it as character string then if you want convert it to an integer value otherwise use the API:

GetDlgItemInt(...);

you are also handling only GetMessage in while-loop while you only handle dispatchmessage outside the loop which means you handle it only once, when getmessage fails (the end of program) so the result is a freezing windows as long as there's no one who takes messages from getmessage to the target windo.

the solution: make DispatchMessage inside while loop:

  • another thing: you pass hwnd to getmessage the result destroying the window won't make the application exit.

take a look at GetMessage() when passing a non-null value: link text

the correct thing in your case:

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

* don't load image inside loop just load at the time wanted:

make an edit box with style ES_NUMBER and another button names for example change image so when clicked take the content of edit box convert it to integer, check whether it is 1 or 2 then load imaged depending the value.

  • you may ask "why I can't use iostream input and output streams in win32" because I ask you "where is console windows?" and if it is here what is the role of while-loop (blocking waiting for messages)?