Бесконечный цикл заставляет программу перестать работать - PullRequest
0 голосов
/ 21 февраля 2019

Итак, я создаю программу, в которой появляются 5 прямоугольников и они движутся в разных направлениях, как DVD Screensaver.

Проблема в том, что когда я начинаю перемещать их в бесконечном цикле, программа перестает работать, не позволяявход будет сделан.Если я сделаю цикл не бесконечным, он перестанет работать, пока цикл не закончится, и после этого программа позволит вам что-то делать.

Я думаю, что проблема в том, как я пытаюсь переместить прямоугольники, ноЯ не уверен.

    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 голосов
/ 21 февраля 2019

НЕ выполняйте бесконечные циклы внутри обработчика сообщений пользовательского интерфейса.Это главная причина, почему ваше приложение не работает.Вы не позволяете своему приложению реагировать на сообщения из ОС.

Кроме того, НЕ выполняйте логику не рисования внутри обработчика рисования.Обновление ваших хищников не является задачей, которая вообще относится к вашему событию 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);
}
0 голосов
/ 22 февраля 2019

Спасибо всем, кто помог.Это моя последняя настройка (я буду редактировать этот пост, если найду лучший способ сделать это)

#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);
}
0 голосов
/ 21 февраля 2019

Причина зависания этого приложения заключается в дизайне событий приложений Windows.

То, что происходит в фоновом режиме, любому приложению Windows не разрешается получать доступ к какому-либо аппаратному обеспечению, в отличие от операционной системы, которая может одновременно запускать только одну программу, например, DOS.Это необходимо для совместного использования оборудования, такого как видеокарта или мышь, между несколькими программами.Вместо прямого доступа к оборудованию, ядро ​​Windows манипулирует самим оборудованием при запуске приложений, отправляющих ядру специальный запрос (системные вызовы), Win API фактически представляет собой набор функций, которые можно использовать для отправки такого запроса ядру.

Когда ваше приложение создает окно или рисует его, оно фактически запрашивает ядро ​​операционной системы.Ядро выбирает, когда и как обрабатывать эту операцию, а затем использовать драйвер устройства видеокарты для рисования (поверх уровня аппаратной абстракции или специальных быстрых 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 или другая пользовательская обработка сообщений не будут вызываться, когда они должны быть вызваны, и ваше приложениезависает.

В статье MSDN показано, как создать анимацию, которую вы хотите реализовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...