Поскольку @ super предлагает , использование библиотеки было бы хорошим решением, и, безусловно, лучше, чем мое, но на случай, если это удовлетворит ваши потребности, я реализовал super basic TextField
class.
Может быть много ошибок, но это может дать вам представление о том, как достичь этой функциональности.
A TextField
- это не более чем прямоугольник, который содержит текст .Поскольку он будет иметь sf::Text
, он должен иметь sf::Font
.Кроме того, я ограничиваю количество символов, которое оно будет содержать.Для того, чтобы мы могли писать внутри TextField
, мы должны знать, выбран ли он, то есть имеет ли он focus .Итак, первый подход может быть следующим:
class TextField : public sf::Transformable, public sf::Drawable{
private:
unsigned int m_size;
sf::Font m_font;
std::string m_text;
sf::RectangleShape m_rect;
bool m_hasfocus;
};
Нам нужен конструктор для этого класса:
class TextField : public sf::Transformable, public sf::Drawable{
public:
TextField(unsigned int maxChars) :
m_size(maxChars),
m_rect(sf::Vector2f(15 * m_size, 20)), // 15 pixels per char, 20 pixels height, you can tweak
m_hasfocus(false)
{
m_font.loadFromFile("C:/Windows/Fonts/Arial.ttf"); // I'm working on Windows, you can put your own font instead
m_rect.setOutlineThickness(2);
m_rect.setFillColor(sf::Color::White);
m_rect.setOutlineColor(sf::Color(127,127,127));
m_rect.setPosition(this->getPosition());
}
private:
unsigned int m_size;
sf::Font m_font;
std::string m_text;
sf::RectangleShape m_rect;
bool m_hasfocus;
};
Нам также нужны некоторые базовые методы, мы хотим получить текст внутри:
const std::string sf::TextField::getText() const{
return m_text;
}
и переместите его, поместив его где-нибудь внутри нашего окна:
void sf::TextField::setPosition(float x, float y){
sf::Transformable::setPosition(x, y);
m_rect.setPosition(x, y);
}
это сложный вопрос.Мы перезаписываем setPosition
метод из sf::Transformable
, потому что нам нужно обновить наш m_rect
.
Кроме того, нам нужно знать, находится ли точка внутри поля:
bool sf::TextField::contains(sf::Vector2f point) const{
return m_rect.getGlobalBounds().contains(point);
}
довольно просто, мы используем cointains
метод sf::RectangleShape
, уже в sfml .
Установите (или отключите) фокус на TextField
:
void sf::TextField::setFocus(bool focus){
m_hasfocus = focus;
if (focus){
m_rect.setOutlineColor(sf::Color::Blue);
}
else{
m_rect.setOutlineColor(sf::Color(127, 127, 127)); // Gray color
}
}
легкий.Для эстетики мы также меняем цвет контура рамки, когда фокусируем.
И последнее, но не менее важное, наш TextField
должен вести себя как-то так, когда ввод (или sf::Event
) получен:
void sf::TextField::handleInput(sf::Event e){
if (!m_hasfocus || e.type != sf::Event::TextEntered)
return;
if (e.text.unicode == 8){ // Delete key
m_text = m_text.substr(0, m_text.size() - 1);
}
else if (m_text.size() < m_size){
m_text += e.text.unicode;
}
}
Эта проверка удаления ключа немного грязная, я знаю.Может быть, вы можете найти лучшее решение.
Вот и все!Теперь main
выглядит так:
int main()
{
RenderWindow window({ 500, 500 }, "SFML", Style::Close);
sf::TextField tf(20);
tf.setPosition(30, 30);
while (window.isOpen())
{
for (Event event; window.pollEvent(event);)
if (event.type == Event::Closed)
window.close();
else if (event.type == Event::MouseButtonReleased){
auto pos = sf::Mouse::getPosition(window);
tf.setFocus(false);
if (tf.contains(sf::Vector2f(pos))){
tf.setFocus(true);
}
}
else{
tf.handleInput(event);
}
window.clear();
window.draw(tf);
window.display();
}
return 0;
}
Подтверждение концепции: