Как написать программу с окнами

Этот урок рассказывает только о том, как открывать окно и как управлять им. Рисование объектов находится вне сферы действия модуля sfml-window: оно обрабатывается модулем sfml-graphics. Однако, управление окном остаётся точно таким же, поэтому прочитать этот урок в любом случае нужно.

Открытие окна

Окна в SFML определяются с помощью класса sf::Window. Окно может быть создано и открыто непосредственно в конструкторе:

#include int main()

Первый аргумент — видео режим (video mode), определяет размер окна (внутренний размер, без заголовка и границ). Здесь мы создаём окно 800 x 600 пикселей.
Класс sf::VideoMode имеет несколько интересных статических функций для получения разрешения рабочего стола или списка допустимых видео режимов для полноэкранного режима. Если интересно, то загляните в документацию.

Второй аргумент это просто заголовок окна.

Этот конструктор может принимать и третий необязательный аргумент: стиль, позволяющий выбрать какие особенности должны быть у окна. Вы можете выбрать любую комбинацию из следующих стилей:

Создание оконного приложения С++/Visual studio 2019/Windows Form

sf::Style::None Без всяких декораций (полезно для заставок); этот стиль не может быть объединён с другими
sf::Style::Titlebar Окно с заголовком
sf::Style::Resize Размер окна можно изменять. Имеется кнопка максимизации окна
sf::Style::Close Окно с кнопкой закрытия окна
sf::Style::Fullscreen Окно в полноэкранном режиме; этот стиль не может быть объединён с другими
sf::Style::Default Стиль по умолчанию с ярлыками Titlebar | Resize | Close

В конструкторе может быть так же четвёртый необязательный аргумент, который определяет опции OpenGL.

Если вы хотите создать окно после создания объекта sf::Window или хотите заново создать его с другим видео режимом или заголовком, вы можете воспользоваться функцией create(). Она требует те же самые аргументы что и конструктор.

#include int main()

Оживление окна

Если вы попробуете выполнить тот код, что был представлен выше, ничего не написав при этом вместо «…», то едва ли вы что-нибудь увидите. Во-первых, потому что программа немедленно завершится, а во вторых, потому что нет обработки событий — так что даже если добавить туда бесконечный цикл, вы увидите «мёртвое» окно, которое нельзя подвинуть, изменить его размер или закрыть.

Добавим кое-что в код:

#include int main() < sf::Window window(sf::VideoMode(800, 600), «My window»); // пусть программа работает до тех пор, пока открыто окно while (window.isOpen()) < // проверить все события окна, которые были вызваны с последней итерации цикла sf::Event event; while (window.pollEvent(event)) < // «запрос закрытия» событие: мы закрываем окно if (event.type == sf::Event::Closed) window.close(); >> return 0; >

Приведённый выше код будет открывать окно и уничтожать его, когда пользователь его закрывает. Рассмотрим в деталях как это работает.

СОЗДАЁМ ОКНО — C++ WINAPI ЧАСТЬ #1

Сначала мы добавили цикл, который гарантирует, что приложение будет обновляться до закрытия окна. Большинство программ на основе SFML будут иметь подобный цикл, который иногда называют главный цикл или игровой цикл.

Затем, первое что мы делаем внутри игрового цикла, это проверяем события которые были вызваны. Обратите внимание, что мы используем цикл while так, что обрабатываются все события, в случае если в очереди их было несколько. Функция pollEvent() возвращает истину, если в очереди были события, и возвращает ложь, если в очереди событий не оказалось.

Всякий раз при получении события, мы должны проверять его тип (закрыто окно? нажата клавиша? подвинута мышка? присоединён джойстик? …) и реагировать соответствующим образом, если это событие нас интересует. В нашем конкретном случае мы заботимся только о событии Event::Closed, которое срабатывает, когда пользователь хочет закрыть окно. На данный момент, окно всё ещё открыто и мы должны закрыть его явно с помощью функции close(). Это позволяет сделать что-нибудь до того, как окно закроется, например сохранить текущее состояние приложения или отобразить сообщение.

Частая ошибка, заключается в том, что люди забывают про цикл событий, потому как ещё не заботятся об обработке событий (используют входы в реальном времени). Но без цикла событий, окно не будет реагировать; действительно, цикл обработки событий играет две роли: в дополнение к обработке пользовательских событий, он даёт возможность окну обрабатывать и внутренние события, которые необходимы для реагирования на изменения размера окна и перемещения его.

Читайте также:
Не выключается программа что делать

После закрытия окна, главный цикл останавливается и программа завершает работу.

На данный момент, мы пока не рассматриваем рисование объектов в окне (об этом уже говорилось в ведении к уроку). Если хотите нарисовать спрайты, текст, фигуры, то всё это описано в уроках о модуле sfml-graphics (перевод их появится немного позже).

Для рисования объектов можно использовать и OpenGL, при это совсем не задействовав модуль sfml-graphics. Об этом тоже будет рассказано, но чуть позже.

Так что не ожидайте пока увидеть в окне что-то интересное 🙂 Скорее всего это будет окно залитое чёрным или белым цветом.

Управление окном

Конечно, SFML позволяет немного поиграться с вашими окнами. Поддерживаются такие базовые операции как изменение размера окна, позиции, заголовка, иконки..но в отличие от специализированных GUI библиотек (Qt, wxWidgets), SFML не обеспечивает расширенные функции. Окна SFML предназначены только для обеспечения основы для рисования с использованием OpenGL или SFML.

// изменение позиции окна (относительно экрана) window.setPosition(sf::Vector2i(10, 50)); // изменение размера окна window.setSize(sf::Vector2u(640, 480)); // изменение заголовка окна window.setTitle(«SFML window»); // получение размера окна sf::Vector2u size = window.getSize(); unsigned int width = size.x; unsigned int height = size.y; .

Вы можете посмотреть в API документации sf::Window полный список функций.

В том случае если вам необходимо использовать расширенные возможности для вашего окна (или вам хочется создать полноценный GUI), то это можно осуществить с помощью другой библиотеки (например Qt) и встроить SFML уже непосредственно внутрь. Что бы сделать это, вы можете использовать другой конструктор или написать функцию для sf::Window которая будет брать управление существующим окном, специфическое для данной ОС. В этом случае SFML создаст контекст рисования внутри данного окна и будет отлавливать все события без нарушения управления первоначальным окном.

sf::WindowHandle handle = /* зависит от используемой библиотеки и того что вы делаете */; sf::Window window(handle);

Если вы просто хотите использовать некое дополнение, какую-то очень специфическую особенность, вы можете сделать и наоборот: создать окно SFML и получить для него управление, характерное для ОС, для реализации той вещи которая не поддерживается SFML.

sf::Window window(sf::VideoMode(800, 600), «SFML window»); sf::WindowHandle handle = window.getSystemHandle(); // вы можете использовать handle вместе с функциями характерными для ОС

Создание и управление окном в SFML

Эта стать описывает,каким образом создавать и управлять окном. Рисование разных вещей находится вне модуля window — оно относится к модулю sfml-graphics. Однако рисовать что-либо без управления окном нельзя и прочтение этой статьи остается обязательным в любом случае.

Создание окна ===

Окна в SFML определяются в классе sf::Window. Окно может быть создано и открыто следующей конструкцией:

#include int main()

Первый аргумент — video mode, определяет размер окна(внутренний размер,без границ и названия окна). Здесь мы создаем окно 800х600 пикселей.
Класс sf::VideoMode имеет некоторые интересные статичные функции для определения разрешения рабочего стала или списка доступных видео-режимов для полно-экранного режима. Не стесняйтесь почитать об этом в документации.
Второй аргумент — это просто имя для нашего окна.

Конструктор окна поддерживает и третий опциональный аргумент — стиль, который позволяет выбрать какое оформление и возможности для окна вы хотите. Вы можете выбирать любую комбинацию из представленных стилей:

sf::Style::None Никакого оформления вообще (используется для заставок, например); этот стиль не может быть скомбинирован с остальными
sf::Style::Titlebar Окно имеет название
sf::Style::Resize Размер окна может быть изменен и оно имеет кнопку Развернуть
sf::Style::Close Окно имеет кнопку Закрыть
sf::Style::Fullscreen Окно отображается в полно-экранном режиме; этот стиль не может быть скомбинирован с остальными и требует подходящий video mode
sf::Style::Default Стиль по-умолчанию, который совмещает в себе TitlebarResizeClose

Также имеется четвертый опциональный аргумент, который определяет специальные опции OpenGL, которые рассматриваются в соответствующей статье.

Если вы хотите показать окно отдельно после его создания или пересоздать с другим video mode или названием, вы можете вызвать функцию отдельно; она принимает такие же аргументы, как и конструктор класса окна.

#include int main()

Придаем жизнь нашему окну ===

Если вы попробуете запустить код без добавления чего-либо в место где у нас стоит «. «, вам будет сложно что-то увидеть. Во-первых, потому что программа заканчивает свое выполнение мгновенно. Во-вторых, потому что у нас нету никакого управления событиями — поэтому если вы добавите бесконечный цикл к этому коду, вы увидите черное окно, которое нельзя и ни переместить, ни масштабировать, ни закрыть.
Поэтому давайте добавим небольшой код, который сделает нашу программу более интересной:

Читайте также:
Лучшая программа для восстановления файлов после форматирования

#include int main() < sf::Window window(sf::VideoMode(800, 600), «My window»); // программа работает сколь угодно долго,пока открыто наше окно while (window.isOpen()) < // проверяем все события окна,которые были запущены после последней итерации цикла sf::Event event; while (window.pollEvent(event)) < // если произошло событие Закрытие,закрываем наше окно if (event.type == sf::Event::Closed) window.close(); >> return 0; >

Представленный код создает и открывает окно, уничтожая его, когда пользователь закрывает его. Давайте разберем боле детально, как это работает.

Во-первых, мы добавляем цикл, который гарантирует, что приложение будет обновлено, пока окно не закрыто. Многие(но не все) программы на SFML имеют этот цикл, который иногда называют игровым или главным.

Далее, первая вещь, которую мы должны сделать внутри нашего игрового цикла — это проверить события, которые были запущены. Обратите внимание, что таким образом мы обрабатываем все события, даже если их несколько в очереди. Функция pollEvent возвращает true, если событие в ожидании, или false, если нету событий.

Теперь, когда мы получили событие,мы должны проверить его тип (окно закрыто? нажата клавиша? передвинут курсор? подключен джойстик. ) и реагировать соответственно, если требуется. В нашем коде мы реагируем только на событие Event::Closed, которое запускается,когда пользователь хочет закрыть окно. В этот момент окно все еще открыто и мы закрываем его явно с помощью соответствующей функции. Это дает возможность что-либо сделать перед тем, как окно будет закрыто, например сохранить текущее состояние приложения, или показать сообщение.

Частая ошибка, которую допускают люди — это забывают о цикле событий, потому что они не беспокоятся об управлении событиями(используют ввод в реальном времени). Но без цикла событий, окно не будет отзывчивым; действительно, цикл событий имеет два назначения — вдобавок к обеспечению управления событиями для пользователя, это дает окну возможность обработать свои внутренние события, что требуется, чтобы окно могло реагировать на перемещение или изменения размера.

После этого окно будет закрыто, главный цикл завершен и приложение выполнено.

Вы возможно заметили, что мы пока не говорим о рисовании чего-либо в окне. Как написано в Введении, рисование не относится к модулю sfml-window и вы можете перейти сразу к статьям о модуле sfml-graphics, если вы хотите отобразить спрайты,текст или фигуры.

Для рисования вы также можете использовать напрямую OpenGL и полностью игнорировать модуль sfml-graphics. sf::Window внутренне создает контекст OpenGL и готов дать вам возможность вызывать функции OpenGL. Вы можете узнать поподробнее об этом в соответствующей статье.

Поэтому не ожидайте увидеть что-либо интересное в этом окне — вы можете увидеть цвет заливки (черный или белый), или что-то, что было отображено ранее в приложении, используя OpenGL, или. что-нибудь еще.

Играемся с окном ===

Конечно же, SFML дает вам возможность немного поиграть с вашими окнами. Базовые функции для окна,такие как изменение его размера, позиции, названия или иконки, но в отличие от специализированных GUI библиотек (Qt, wxWidgets), SFML не дает дополнительных возможностей. Окна SFML только дают основу для рисования с помощью OpenGL или самого SFML.
Ниже приведены функции управления окном:

// изменяет позиции окна(относительно рабочего стола) window.setPosition(sf::Vector2i(10, 50)); // изменяет размер окна window.setSize(sf::Vector2u(640, 480)); // изменяет название окна window.setTitle(«SFML window»); // получаем размер окна sf::Vector2u size = window.getSize(); unsigned int width = size.x; unsigned int height = size.y; .

Вы можете обратиться к API документации для полного списка функций sf::Window.

В случае, если вам действительно нужны дополнительный возможности для вашего окна, вы можете создать GUI, используя другую библиотеку, и встроить SFML в неё. Чтобы так сделать, вам придется использовать другой конструктор, или создать функцию для sf::Window, которая примет специфичный для операционной системы handle окна. В этом случае, SFML создаст контекст рисования внутри переданного окна и будет управлять всеми его событиями, не нарушая изначальное управление окном.

sf::WindowHandle handle = /* отдельно для того что вы делаете и для библиотеки, которую вы используете */; sf::Window window(handle);

Если вы просто хотите дополнительную, очень специфичную возможность, вы можете также добавить её другим путем: создать окно SFML, получить специфичный для операционной системы handle окна и имлементировать вещи, которые SFML не поддерживает.

sf::Window window(sf::VideoMode(800, 600), «SFML window»); sf::WindowHandle handle = window.getSystemHandle(); // теперь вы можете использовать handle со специфичными для операционной системы функциями

Интеграция SFML с другими библиотеками требует некоторых затрат и не будет описана здесь, но вы можете обсудить это в комментариях к статье.

Контролируем частоту кадров ===

Иногда, когда ваше приложение запускается быстро, вы можете заметить визуальные артефакты, такие как рывки при показе изображения. Причиной этому служит то, что скорость обновления вашего приложения не синхронизирована с вертикальной частотой вашего монитора, и, как результат, низ предыдущего кадра смешивается с верхом следующего.
Решение этой проблемы — использовать вертикальную синхронизацию. Это автоматически управляется видео-картой, и может быть легко включено или выключено с помощью функции setVerticalSyncEnabled:

Читайте также:
Установка программ на Андроид приставку

window.setVerticalSyncEnabled(true); // запустите это один раз, после создания окна

После вызова этой функции, ваше приложение будет запускаться с частотой отображения монитора, зачастую это 60 кадров в секунду.

Иногда вызов setVerticalSyncEnable не дает никакого эффекта, это потому что вертикальная синхронизация выключена в настройках драйвера вашей видеокарты. В настройках драйвера установите в режим «выбирается приложением».

В других ситуациях, вы также можете установить, чтобы ваше приложение запускалось с установленной вами частотой кадров, отличной от частоты монитора. Этого можно достигнуть, используя функцию setFramerateLimit:

window.setFramerateLimit(30); // запустите это один раз, после создания окна

В отличие от setVerticalSyncEnabled, эта функция реализуется самим SFML, используя комбинацию sf::Clock и sf::sleep. Важным моментом является то, что эта функция не на 100% надежна, особенно для высокой частоты кадров: минимальное время для sf::sleep зависит от используемой операционной системы и может быть не ниже 10 или 15 миллисекунд. Не надейтесь на эту функцию в реализации точного контроля временем.

Никогда не используйте вместе setVerticalSyncEnabled и setFramerateLimit. Это сочетание ни к чему хорошему не приведет.

Вещи, которые следует знать об окнах

Ниже список того, что можно и нельзя делать с окнами в SFML.

Вы можете создавать несколько окон

SFML дает возможность создавать несколько окон, управлять ими всеми в главном потоке или в любом другом собственном для окна потоке.В этом случае не забудьте о цикле событий для каждого окна.

Несколько мониторов все еще не имеют корректной поддержки

SFML не управляет несколькими окнами. Как результат, вы не сможете выбрать, на каком мониторе будет отображено окно, и у вас не будет возможности создать более одного полно-экранного окна. Это должно быть улучшено в следующих версиях.

События должны быть обработаны в потоке окна

Это важное ограничение многих операционных систем: цикл событий должен быть вызван в том же потоке, в котором создано окно. Это значит что если вы захотите создать поток для управления событиями, вам нужно быть уверенным что окно будет создано в том же потоке. Если вы на самом деле имеете необходимость разделить вещи между потоками, удобнее будет хранить управление событиями в главном потоке, а остальное переместить в другие потоки (рендеринг, физику, логику. ). Это решение будет также совместимо с остальными ограничениями, описанными ниже.

В OS X окна и события должны быть обработаны в главном потоке

Да, это правда.Mac OS X выдаст ошибку, если вы попробуете создать окно или обрабатывать события не в главном потоке.

В Windows окно, которое больше рабочего стола, не отображается корректно

По некоторым причинам Windows не любит окна, которые больше рабочего стола. Это включает в себя окна, созданные с помощью VideoMode::getDesktopMode(): вместе с добавленными границами и именем окна, вы получаете окно, которое немного больше чем рабочий стол.

Источник: devtribe.ru

С++ Winapi создание окна в консольном приложении, а так же создание контекстного меню.

Один только вопрос, при чем тут консольное приложение? И если оно создавалось действительно как консольное, не диверсия ли использовать в нем окна? Включишь такое в командный файл, а оно возьми и нарисуй что-нибудь, да еще и зависнет на ожидании ответа, которого никогда не будет, потому как юзера за экраном нет.

#3
12:20, 10 апр 2016

Zab
> И если оно создавалось действительно как консольное, не диверсия ли
> использовать в нем окна? Включишь такое в командный файл, а оно возьми и
> нарисуй что-нибудь, да еще и зависнет на ожидании ответа, которого никогда не
> будет, потому как юзера за экраном нет.
Ну надо знать, что включаешь в командный файл, а не включать туда что попало. В линуксе вообще нет различия между консольными и оконными приложениями. Живут же как-то. А в винде лишь разница в том, что у них разные мейны и в консольном ещё вылезает консоль. Первое различие легко поправить, написав функцию WinMain, которая вызывает main.

Я так сделал в движке, чтобы писать один main, в релизе он вызывается из WinMain, а в дебаге это консольное приложение, где в консоль пишется отладочная информация.

  • Имбирная Ведьмочка
  • Участник

#4
13:20, 10 апр 2016

Нет никакой разницы. Есть разные варианты инициализации от рантайма.

Источник: gamedev.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru