How to Center Text
There are many cases where you want to center some text in a box or on a button, for example when building a game menu. Simple math should allow you to align the text correctly, but there are a few gotchas to consider when positioning a sf::Text
object.
Load the Font
You need to have a font with a specific character size loaded and set on the text object, otherwise the required text size can’t be determined. There is no default font in SFML 2.
Set a String
Unless you’re using a monospaced font, the characters of a text will have different width and heights. For example an “m” will be quite a bit wider than an “i”. So in order to perfectly position your sf::Text
object, you need to pass a string to it, so with and height are correctly calculated.
This also means, that whenever you change the string of an sf::Text
you have to recalculate the position.
Consider Local Bounds
Unlike an sf::Sprite
or sf::RectangleShape
the local bounds (i.e. getLocalBounds()
) of a sf::Text
object are not fixed to the position (0, 0)
, but can positive or negative in order to maintain a stable text baseline. If the local bounds would not adjust for that, you’d see your text jump around vertically when you change your text and the added “S” suddenly takes more space at the top.
More specifically, this means that you have to add the local bounds position to the origin or position of the sf::Text
object, depending on how you align it.
Rounding Position and Origin
You have align text on integer positions, otherwise the rasterizer might render part of your text blurry, as it has to decide how to fake half-/semi-pixel rendering on your window or render texture. As such it’s already recommended to round your position or origin setting to integer values.
No Scale or Zoom
Another general tip for working with text, never scale the text or zoom a view with a text on it. The result will be washed out and hard to read text, since you’re essentially just enlarge the font texture. What you instead want to do, is to change the font size of your text and render on a separate view. That way you will always retain sharp texts.
Example Code
#include <SFML/Graphics.hpp>
#include <cmath>
sf::Vector2f round(const sf::Vector2f vector)
{
return sf::Vector2f{ std::round(vector.x), std::round(vector.y) };
}
int main()
{
auto window = sf::RenderWindow{ {800, 600, 32}, "SFML Window" };
window.setFramerateLimit(60);
auto font = sf::Font{};
if (!font.loadFromFile("OpenSans.ttf"))
{
sf::err() << "Couldn't load font\n";
return -1;
}
auto text = sf::Text{ "Centered Text", font };
auto center = text.getGlobalBounds().getSize() / 2.f;
auto localBounds = center + text.getLocalBounds().getPosition();
auto rounded = round(localBounds);
text.setOrigin(rounded);
text.setPosition(sf::Vector2f{ window.getSize() / 2u });
text.setFillColor(sf::Color{ 0x655A7CFF });
auto rectangle = sf::RectangleShape{ {300.f, 100.f} };
rectangle.setOutlineThickness(2.f);
rectangle.setOutlineColor(sf::Color{ 0xAB92BFFF });
rectangle.setOrigin(round(rectangle.getGlobalBounds().getSize() / 2.f));
rectangle.setPosition(text.getPosition());
rectangle.setFillColor(sf::Color::Transparent);
while (window.isOpen())
{
for (auto event = sf::Event{}; window.pollEvent(event);)
{
if (event.type == sf::Event::Closed)
{
window.close();
}
}
window.clear(sf::Color{ 0xAFC1D6FF });
window.draw(rectangle);
window.draw(text);
window.display();
}
}