C++ 无限循环使程序停止工作

C++ 无限循环使程序停止工作,c++,winapi,C++,Winapi,所以我正在创建一个程序,其中有5个矩形,它们朝着不同的方向移动,就像DVD屏幕保护程序一样 问题是当我开始在无限循环中移动它们时,程序停止工作,不允许进行任何输入。如果我使循环不是无限的,它将停止工作,直到循环结束,然后程序允许你做一些事情 我想问题在于我试图移动矩形的方式,但我不确定 void MovePredator(HDC hdc, PAINTSTRUCT ps,int size, int amount) { for (;;) {

所以我正在创建一个程序,其中有5个矩形,它们朝着不同的方向移动,就像DVD屏幕保护程序一样

问题是当我开始在无限循环中移动它们时,程序停止工作,不允许进行任何输入。如果我使循环不是无限的,它将停止工作,直到循环结束,然后程序允许你做一些事情

我想问题在于我试图移动矩形的方式,但我不确定

    void MovePredator(HDC hdc, PAINTSTRUCT ps,int size, int amount)
    {
        for (;;)
        {
            FillRect(hdc, &ps.rcPaint, (HBRUSH)(1));
            for (int i = 0; i < amount; ++i)
            {
                int Offset = size / 2;
                if (Predator[i].LocationX - Offset == 0 || Predator[i].LocationX + Offset == 1420)
                {
                    Predator[i].MoveX *= -1;
                }
                if (Predator[i].LocationY - Offset == 0 || Predator[i].LocationY + Offset == 700)
                {
                    Predator[i].MoveY *= -1;
                }
                Predator[i].LocationX += Predator[i].MoveX;
                Predator[i].LocationY += Predator[i].MoveY;
                Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
            }
            Sleep(10);
        }
    }

    void SpawnPredator(HDC hdc, int size, int amount)
    {
        int Offset = size / 2;
        for (int i = 0; i < amount; ++i)
        {
            Predator[i].LocationX = rand() % 1300 + 50;
            Predator[i].LocationY = rand() % 600 + 50;
            Predator[i].MoveX = rand()%2;
            Predator[i].MoveY = rand()%2;
            if (Predator[i].MoveX == 0) Predator[i].MoveX = -1;
            if (Predator[i].MoveY == 0) Predator[i].MoveY = -1;
            Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
        }
    }

此应用程序挂起的原因是Windows应用程序基于事件的设计的本质

在后台,任何windows应用程序都不允许直接访问任何硬件,这与操作系统不同,操作系统一次只能运行一个程序,例如DOS。这是在多个程序之间共享视频卡或鼠标等硬件所必需的。Windows内核不直接访问硬件,而是在运行向内核发送特殊请求的应用程序(系统调用)时操纵硬件本身,Win API实际上是一组可用于向内核发送此类请求的函数

当您的应用程序创建或绘制窗口时,它实际上要求操作系统内核执行此操作。内核选择何时以及如何处理此操作,然后使用视频卡设备驱动程序绘制(通过硬件抽象层或特殊的fast API,如OpenGL或Direct X等)

另一件事——应用程序如何知道用户是否使用鼠标或键盘进行输入。Windows将这些输入存储在称为事件的特殊内部结构队列中,每个应用程序线程都有这样一个队列。 应用程序本身应该有一个等待操作系统事件并对其作出反应的循环—这种循环称为运行循环,通常如下所示:

   MSG messages; // Here messages to the application are saved 
    // Run the message loop. It will run until GetMessage() returns 0 
   while (GetMessage (&messages, NULL, 0, 0))
   {
      /* Translate virtual-key messages into character messages */
      TranslateMessage(&messages);
      /* Send message to WindowProcedure */
      DispatchMessage(&messages);
   }
如果您使用的是像MFC这样的库,则该循环由库提供,但它仍然存在。 创建窗口后,您或您的库–注册一个
WindowProcedure
回调函数,该函数对运行循环发送到窗口对象(如WM_PAINT)的消息作出反应。当您的程序不需要处理某些特定事件时,此类函数通常调用
DefWindowProc
函数

WM_PAINT
在最大化、最小化、恢复或显示隐藏窗口时发生,或者您可以使用SendMessage功能将此消息发送给自己的窗口。 如果在处理消息期间执行无限循环,或阻止执行运行循环的线程,则会冻结运行循环,并且在需要调用DefWindowProc或其他自定义消息处理时不会调用它们,应用程序将挂起


演示如何制作要实现的动画。

此应用程序挂起的原因是基于Windows应用程序事件的设计

在后台,任何windows应用程序都不允许直接访问任何硬件,这与操作系统不同,操作系统一次只能运行一个程序,例如DOS。这是在多个程序之间共享视频卡或鼠标等硬件所必需的。Windows内核不直接访问硬件,而是在运行向内核发送特殊请求的应用程序(系统调用)时操纵硬件本身,Win API实际上是一组可用于向内核发送此类请求的函数

当您的应用程序创建或绘制窗口时,它实际上要求操作系统内核执行此操作。内核选择何时以及如何处理此操作,然后使用视频卡设备驱动程序绘制(通过硬件抽象层或特殊的fast API,如OpenGL或Direct X等)

另一件事——应用程序如何知道用户是否使用鼠标或键盘进行输入。Windows将这些输入存储在称为事件的特殊内部结构队列中,每个应用程序线程都有这样一个队列。 应用程序本身应该有一个等待操作系统事件并对其作出反应的循环—这种循环称为运行循环,通常如下所示:

   MSG messages; // Here messages to the application are saved 
    // Run the message loop. It will run until GetMessage() returns 0 
   while (GetMessage (&messages, NULL, 0, 0))
   {
      /* Translate virtual-key messages into character messages */
      TranslateMessage(&messages);
      /* Send message to WindowProcedure */
      DispatchMessage(&messages);
   }
如果您使用的是像MFC这样的库,则该循环由库提供,但它仍然存在。 创建窗口后,您或您的库–注册一个
WindowProcedure
回调函数,该函数对运行循环发送到窗口对象(如WM_PAINT)的消息作出反应。当您的程序不需要处理某些特定事件时,此类函数通常调用
DefWindowProc
函数

WM_PAINT
在最大化、最小化、恢复或显示隐藏窗口时发生,或者您可以使用SendMessage功能将此消息发送给自己的窗口。 如果在处理消息期间执行无限循环,或阻止执行运行循环的线程,则会冻结运行循环,并且在需要调用DefWindowProc或其他自定义消息处理时不会调用它们,应用程序将挂起


演示如何制作要实现的动画。

不要在UI消息处理程序中执行无限循环。这是你的应用程序无法运行的主要原因。您不允许应用程序对来自操作系统的消息保持响应

此外,请勿在绘制处理程序内执行非绘制逻辑。更新捕食者根本不属于你的
WM_PAINT
事件。改为使用计时器,并使其在发生更改时使窗口失效以触发重新绘制。只要在你被要求粉刷窗户的时候,按原样粉刷现有的捕食者就可以了

另外,您的
WndProc()
缺少对所有未处理消息的
DefWindowProc()
调用

尝试类似以下内容:

void MovePredator(int size, int amount)
{
    int Offset = size / 2;
    for (int i = 0; i < amount; ++i)
    {
        if (Predator[i].LocationX - Offset == 0 || Predator[i].LocationX + Offset == 1420)
        {
            Predator[i].MoveX *= -1;
        }
        if (Predator[i].LocationY - Offset == 0 || Predator[i].LocationY + Offset == 700)
        {
            Predator[i].MoveY *= -1;
        }
        Predator[i].LocationX += Predator[i].MoveX;
        Predator[i].LocationY += Predator[i].MoveY;
    }
}

void SpawnPredator(int amount)
{
    for (int i = 0; i < amount; ++i)
    {
        Predator[i].LocationX = rand() % 1300 + 50;
        Predator[i].LocationY = rand() % 600 + 50;
        Predator[i].MoveX = rand() % 2;
        Predator[i].MoveY = rand() % 2;
        if (Predator[i].MoveX == 0)
            Predator[i].MoveX = -1;
        if (Predator[i].MoveY == 0)
            Predator[i].MoveY = -1;
    }
}

void PaintPredator(HDC hdc, int size, int amount)
{
    int Offset = size / 2;
    for (int i = 0; i < amount; ++i)
    {
        Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_CREATE:
            srand(time(NULL));
            SetTimer(hWnd, 1, 10, NULL);
            return 0;

        case WM_TIMER:
            SpawnPredator(5);
            MovePredator(50, 5);
            InvalidateRect(hWnd, NULL);
            return 0;

        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            FillRect(hdc, &ps.rcPaint, (HBRUSH)(1)); 
            PaintPredator(hdc, 50, 5);
            EndPaint(hWnd, &ps);
            return 0;
        }
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}
void MovePredator(整数大小,整数金额)
{
int Offset=大小/2;
对于(int i=0;i#define STEP 1

int idtimer = -1;

struct Mob
{
    int LocationX = 0;
    int LocationY = 0;
    int MoveX = 0;
    int MoveY = 0;
};

struct Mob Predator[100];

void SpawnPredator(int amount)
{
    for (int i = 0; i < amount; ++i)
    {
        Predator[i].LocationX = rand() % 1300 + 50;
        Predator[i].LocationY = rand() % 600 + 50;
        Predator[i].MoveX = rand() % 2;
        Predator[i].MoveY = rand() % 2;
        if (Predator[i].MoveX == 0) Predator[i].MoveX = -STEP;
        else Predator[i].MoveX = STEP;
        if (Predator[i].MoveY == 0) Predator[i].MoveY = -STEP;
        else Predator[i].MoveY = STEP;
    }
}

void MovePredator(int size, int amount)
{
    for (int i = 0; i < amount; ++i)
    {
        int Offset = size / 2;
        if (Predator[i].LocationX - Offset <= 0 || Predator[i].LocationX + Offset >= 1420)
        {
            Predator[i].MoveX *= -1;
        }
        if (Predator[i].LocationY - Offset <= 0 || Predator[i].LocationY + Offset >= 700)
        {
            Predator[i].MoveY *= -1;
        }
        Predator[i].LocationX += Predator[i].MoveX;
        Predator[i].LocationY += Predator[i].MoveY;
    }
}

void PaintPredator(HDC hdc, int size, int amount)
{
    for (int i = 0; i < amount; ++i)
    {
        int Offset = size / 2;
        Rectangle(hdc, Predator[i].LocationX - Offset, Predator[i].LocationY - Offset, Predator[i].LocationX + Offset, Predator[i].LocationY + Offset);
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    srand(time(NULL));
    switch (message)
    {
    case WM_CREATE:
    {
        SpawnPredator(5);
        SetTimer(hWnd, idtimer = 1, 10, NULL);
    }
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Разобрать выбор в меню:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_TIMER:
    {   
        MovePredator(50, 5);
        InvalidateRect(hWnd, NULL, FALSE);
        break;
    }
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            FillRect(hdc, &ps.rcPaint, (HBRUSH)(4));
            PaintPredator(hdc, 50, 5);
            //Rectangle(hdc, 0, 10, 20, 30);
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}