无限循环使程序停止工作

时间:2019-02-21 09:38:21

标签: c++ winapi

所以我正在创建一个程序,其中生成了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);
        }
    }

这是循环的交互方式(我删除了不与之交互的情况)

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            srand(time(NULL));
            // TODO: Добавьте сюда любой код прорисовки, использующий HDC...
            SpawnPredator(hdc, 50, 5);
            MovePredator(hdc, ps, 50, 5);
            EndPaint(hWnd, &ps);
        }
    }
}

3 个答案:

答案 0 :(得分:3)

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

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

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

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

   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或其他自定义消息处理将在需要调用时不被调用,并且您的应用程序挂起。

Following MSDN article显示了如何制作您想要实现的动画。

答案 1 :(得分:1)

请勿在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);
}

答案 2 :(得分:0)

感谢所有提供帮助的人。这是我的最终设置(如果我找到更好的方法,将编辑这篇文章)

#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);
}