C++ 在 WinAPI 中更改用户输入的图像

C++ changing image on user input in WinAPI

我在将我的 .bmp 图像显示为根据用户输入更改为另一个图像时遇到问题。图像可以在开始时成功打印 (title.bmp),但应该在按 1 或 2 然后按 enter 时发生变化(到 introduction.bmp & start.bmp)。我一定是漏掉了什么!

发生这种情况的地方在 while (running == 1) { 代码的底部附近,所以请跳到那里。 我正在使用 loadImage("title.bmp"); 来打印我的图像(当然我会适当地更改文件名),并使用 cin >> menuSelection; 来暂停程序并等待用户按下一个或两个然后输入。

我搜索了很多关于如何在 WinAPI 中打印和更改图像的页面,这是我能找到的最接近的页面。如果我遗漏了任何其他信息,请告诉我,我会发表评论。在此先感谢您的帮助!

//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;
        }
    }

你不能在 win32 中使用 cin 使用编辑框然后从中获取用户输入的字符串然后如果你想将它转换为整数值否则使用 API:

GetDlgItemInt(...);

你还在 while 循环中只处理 GetMessage 而你只在循环外处理 dispatchmessage 这意味着你只处理一次,当 getmessage 失败时(程序结束)所以结果是冻结 windows 只要没有人从getmessage 取消息到目标windo。

解决方案:在 while 循环中创建 DispatchMessage:

  • 另一件事:您将 hwnd 传递给 getmessage 结果破坏 window 不会使应用程序退出。

查看传递非空值时的 GetMessage(): link text

你的情况下正确的是:

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

* 不要在循环内加载图片,只在需要的时候加载:

创建一个样式为 ES_NUMBER 的编辑框和另一个按钮名称,例如更改图像,以便在单击时将编辑框的内容转换为整数,检查它是 1 还是 2,然后根据值。

  • 你可能会问"why I can't use iostream input and output streams in win32"因为我问你"where is console windows?"如果是这里while-loop(阻塞等待消息)的作用是什么?