Bonjour,
J'ai commencé une petite GUI pour la SFML, et là j'en suis à faire un éditeur de ligne, c'est-à-dire une cadre, on clique dedans et on peut y entrer du texte. Ma classe LineEditor n'est pas parfaite (par exemple pour le moment un texte trop long dépasse du cadre), mais elle fonctionne. Sauf quand elle est membre d'une autre classe !
Voici la définition (abrégée) de LineEditor :
#ifndef LINEEDITOR_H
#define LINEEDITOR_H
#include <iostream>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Mouse.hpp>
#include <SFML/Window/Event.hpp>
namespace glan
{
class LineEditor : public sf::Drawable
{
public:
LineEditor() = delete;
// Default constructor.
LineEditor(sf::Texture const& boxTexture, sf::Font const& font, sf::RenderWindow *shownIn,
unsigned int characterSize = 15, sf::Vector2f const& offset = sf::Vector2f(),
sf::Texture const& cursorTexture = sf::Texture(), sf::String const& str = sf::String(), bool numbersOnly = false, unsigned int charMax = -1);
// Constructor.
// Arguments :
//
// boxTexture : The texture of the text editor itself, used by 'box' member.
// Using an empty texture will lead to an undifined behavior.
//
// font : The font of the displayed text.
//
// characterSize : The character size of the displayed text.
//
// offset : The offset of the displayed text relatively to the box.
// The text's position is defined as following :
// displayedText.setPosition(box.getPosition() + textOffset);
//
// shownIn : A pointer to the sf::RenderWindow in which the text editor will be shown, kept in 'parent' member. Must not be null.
//
// cursorTexture : The texture of the custom cursor. If the default value is used, no custom cursor will be shown.
//
// str : The string which is already shown at the creation of the text editor.
void treatEvent(sf::Event const& event);
// Treats the Event 'event'.
// Can treat the following events : MouseMoved, MouseButtonPressed, MouseButtonReleased and TextEntered.
private:
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
// Draw the text editor to a render target.
sf::RenderWindow *parent;
sf::Sprite box; // The box in which the text is.
sf::Sprite cursor; // The cursor shown when the box is hovered.
bool customCursor;
mutable sf::Text text;
sf::Vector2f textOffset;
unsigned int maxChar; // The maximum characters the class is allowed to handle. If 0, there is no limit.
bool onlyNumbers; // If true, keys input which are not numbers will be ignored.
mutable bool hasFocus, isPressed, active;
};
} // namespace glan
#endif // LINEEDITOR_H
#include "LineEditor.h"
namespace glan
{
LineEditor::LineEditor(sf::Texture const& boxTexture, sf::Font const& font, sf::RenderWindow *shownIn,
unsigned int characterSize, sf::Vector2f const& offset,
sf::Texture const& cursorTexture, sf::String const& str, bool numbersOnly, unsigned int charMax) :
parent(shownIn), box(boxTexture), cursor(cursorTexture), customCursor(cursorTexture.getSize() != sf::Vector2u()), text(str, font, characterSize),
textOffset(offset), maxChar(charMax), onlyNumbers(numbersOnly), hasFocus(false), isPressed(false), active(false)
{
text.setPosition(box.getPosition() + textOffset);
cursor.setOrigin( static_cast<sf::Vector2f>( (cursor.getTexture()->getSize()) / (unsigned)2 ) );
}
//////////////////////////////////////////////////////////////////////////////
void LineEditor::treatEvent(sf::Event const& event)
{
sf::Vector2f msPos(static_cast<sf::Vector2f>(sf::Mouse::getPosition(*parent)));
switch(event.type)
{
case sf::Event::MouseMoved:
cursor.setPosition(msPos);
if(box.getGlobalBounds().contains(msPos))
{
hasFocus = true;
if(customCursor)
parent->setMouseCursorVisible(false);
}
else
{
hasFocus = false;
if(customCursor)
parent->setMouseCursorVisible(true);
}
break;
case sf::Event::MouseButtonPressed:
if(hasFocus)
isPressed = true;
break;
case sf::Event::MouseButtonReleased:
if(isPressed)
active=true;
else
active=false;
isPressed=false;
break;
case sf::Event::TextEntered:
if(active)
{
sf::Uint32 chr = event.text.unicode;
sf::String temp(text.getString());
if(chr == 8 && temp.getSize() > 0) // If the user pressed backspace...
temp.erase(temp.getSize() - 1);
else if(chr > 31 && temp.getSize() < maxChar)
temp+=chr;
text.setString(temp);
}
break;
default:
break;
}
}
//////////////////////////////////////////////////////////////////////////////
void LineEditor::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(box, states);
target.draw(text, states);
if(hasFocus && customCursor)
target.draw(cursor);
}
} // namespace glan
sf::Texture cursor, box;
cursor.loadFromFile("resources/cursor.png");
box.loadFromFile("resources/editor.png");
sf::Font font;
font.loadFromFile("resources/LETTERS_.ttf");
sf::RenderWindow window(sf::VideoMode(800,600), "code minimal");
LineEditor line(box, font, &window, 15, sf::Vector2f(5,5), cursor, "hoho");
line.setColor(sf::Color::Black);
while(window.isOpen())
{
window.clear(sf::Color::White);
window.draw(line);
window.display();
sf::Event event;
while(window.pollEvent(event))
{
line.treatEvent(event);
if(event.type == sf::Event::Closed)
window.close();
}
}
class MyWindow
{
private:
sf::RenderWindow window;
sf::Font fnt;
sf::Texture box, cursor;
LineEditor line;
// Members which hold the properties of the window
sf::VideoMode windowVideoMode;
sf::String windowTitle;
sf::Uint32 windowStyle;
sf::ContextSettings windowSettings;
public:
MyWindow() : window(), fnt(), box(), cursor(), line(box, fnt, &window, 15, sf::Vector2f(5,5), cursor, "hoho"),
windowVideoMode(sf::VideoMode(800,600)), windowTitle("My window"), windowStyle(sf::Style::Default), windowSettings(sf::ContextSettings())
{
fnt.loadFromFile("resources/LETTERS_.ttf");
box.loadFromFile("resources/editor.png");
cursor.loadFromFile("resources/cursor.png");
line.setBoxTexture(box);
line.setCursorTexture(cursor);
line.setFont(fnt);
line.setColor(sf::Color::Black);
line.setPosition(100,100);
}
void Window::show()
{
window.create(windowVideoMode, windowTitle, windowStyle, windowSettings);
while(window.isOpen())
{
window.clear(sf::Color::White);
window.draw(line);
window.display();
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
line.treatEvent(event);
}
}
}
};
Quand j'utilise le 2e code, que j'instancie une MyWindow et que j'appelle sa fonction show(), une fenêtre s'ouvre bien, mais elle reste blanche, le LineEditor n'y apparaît pas, il semble qu'il n'y soit même pas puisqu'il ne réagit pas quand je passe ma souris là où il est supposé être (j'avais ajouté une petite ligne de code qui affichait "focused" dans la console quand ma souris passe sur lui).
J'ai aussi essayé de créer un LineEditor dans la fonction show() (donc non membre de MyWindow) pour remplacer le LineEditor member, et là il est bien affiché, mais ne réagit toujours pas aux évènements. Je ne comprends pas.
Merci d'avance pour vos réponses.