Here's a simple example that uses waitEvent.
Warning: The rectangle will flash rapidly
#include <SFML/Graphics.hpp>
int main()
{
auto window = sf::RenderWindow{{1920u, 1080u}, "Wait Event"};
window.setFramerateLimit(144);
auto rectangle = sf::RectangleShape{{100.f, 100.f}};
rectangle.setFillColor(sf::Color::Red);
rectangle.setPosition({200.f, 200.f});
while (window.isOpen())
{
if (rectangle.getFillColor() == sf::Color::Red)
{
rectangle.setFillColor(sf::Color::Green);
}
else
{
rectangle.setFillColor(sf::Color::Red);
}
window.clear();
window.draw(rectangle);
window.display();
auto event = sf::Event{};
if (window.waitEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
}
}
}
}
Now don't move your mouse over the window and you'll see that the color remains the same, until you press a key of move the mouse again.
The "problem" this code nice demonstrates is, that the rendering loop will pause for as long as there's no event. If you have a UI application where nothing happens when the user does no input, this can work, but if you say render a game or a simulation, then you want to continuously render something, even if there's no user input happening right now.
And here is a much more complicated example that uses a second thread for rendering.
This is a bit unsafe, as discussed in the other thread, because there's no way to properly protect shared access on the window, as waitEvent blocks. It should generally work, but there's no guarantee.
Important to note is that events always have to be processed in the thread, which created the window, which is why I'm using a rendering thread.
Second note is that you need to disable the OpenGL context on the event thread and enable it on the rendering thread.
As you see it's much more complex and in the end, you're not doing anything special here, we just do a way more complicated pollEvent, as we push the events from the event thread into a queue that is processed in the rendering thread, but hey, we're using waitEvent, which was the whole requirement...
#include <mutex>
#include <string>
#include <thread>
#include <queue>
#include <SFML/Graphics.hpp>
class Application
{
sf::RenderWindow m_window;
std::queue<sf::Event> m_eventQueue;
std::mutex m_sharedAccess;
void renderGame()
{
// Set OpenGL Context active on the current thread
m_window.setActive(true);
auto rectangle = sf::RectangleShape{{100.f, 100.f}};
rectangle.setFillColor(sf::Color::Red);
rectangle.setPosition({200.f, 200.f});
auto clock = sf::Clock{};
auto accumulator = sf::Time::Zero;
while (m_window.isOpen())
{
{
auto lock = std::unique_lock<std::mutex>{m_sharedAccess};
while (!m_eventQueue.empty())
{
auto event = sf::Event{};
event = m_eventQueue.back();
m_eventQueue.pop();
if (event.type == sf::Event::Closed)
{
m_window.close();
}
}
}
if (rectangle.getFillColor() == sf::Color::Red)
{
rectangle.setFillColor(sf::Color::Green);
}
else
{
rectangle.setFillColor(sf::Color::Red);
}
auto frameTime = clock.restart();
accumulator += frameTime;
if (accumulator >= sf::seconds(1.f))
{
m_window.setTitle(std::to_string(1.f / frameTime.asSeconds()));
accumulator = sf::Time::Zero;
}
m_window.clear();
m_window.draw(rectangle);
m_window.display();
}
}
public:
Application() : m_window{{1920u, 1080u}, "Wait Event"}
{
m_window.setFramerateLimit(144);
}
void run()
{
// Set OpenGL Context inactive on the current thread
m_window.setActive(false);
auto renderThread = std::thread{&Application::renderGame, this};
// Handle events on the same thread the window was created on
auto event = sf::Event{};
while (m_window.waitEvent(event))
{
{
auto lock = std::unique_lock<std::mutex>{m_sharedAccess};
m_eventQueue.push(event);
}
if (event.type == sf::Event::Closed)
{
break;
}
}
renderThread.join();
}
};
int main()
{
auto app = Application{};
app.run();
}