Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Heritage de la classe drawable  (Lu 2625 fois)

0 Membres et 1 Invité sur ce sujet

Rick_Cplusplus

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
    • E-mail
Heritage de la classe drawable
« le: Juillet 17, 2019, 04:59:35 pm »
Bonjour la communauté,

Je souhaite faire une classe bouton (pas original mais utile).
cette classe a, entre autre, 2 membres :
- un sf::Text qui contient le texte à afficher sur le bouton,
- un sf::RectangleShape qui entoure le texte pour rendre visible le bouton.

Question : puis-je combiner (si oui comment ?) ces 2 membres pour constituer un sf::Sprite à retourner à ma fenêtre pour l'affichage du bouton ou suis-je obligé de retourner les 2 membres via 2 "getter" séparés ?  ???

Une alternative serait de faire hériter ma classe bouton de sf::Drawable mais ça me fait un peu peur en terme de syntaxe... :-[
Salutations,

Rick.
« Modifié: Août 02, 2019, 05:22:19 pm par Rick_Cplusplus »

G.

  • Hero Member
  • *****
  • Messages: 1593
    • Voir le profil
Re: sf::Text + sf::RectangleShape => sf::sprite ?
« Réponse #1 le: Juillet 17, 2019, 05:29:53 pm »
Tu devrais essayer d'hériter de sf::Drawable, c'est bidon

Rick_Cplusplus

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
    • E-mail
Re: sf::Text + sf::RectangleShape => sf::sprite ?
« Réponse #2 le: Juillet 19, 2019, 10:04:16 am »
Bonjour la communauté,

Bidon ? Pas tant que ça pour mon niveau actuel... :P

Mais bon, je me suis lancé et j'y suis arrivé !
- Merci aux codes proposés dans le wiki (roundedRectangle et lineShape),
- Merci à l'exemple fourni avec la classe sf::Shape,
- Merci à Mister G pour l'incitation au dépassement !  ;)

Reste une chose que je n'ai pas comprise, c'est le sens de "virtual" dans :
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
tiré de l'exemple là ->  https://www.sfml-dev.org/documentation/2.5.1-fr/classsf_1_1Drawable.php

Je ne l'ai pas mis ce "virtual" et ça fonctionne tout de même, donc quid de la chose ? ???

Rick

Rick_Cplusplus

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
    • E-mail
Implementer la classe drawable
« Réponse #3 le: Août 02, 2019, 09:57:01 am »
Bonjour la comunauté,

Bon je reviens là dessus pke je sèche sur un pb.
voici le code (minimal) du header :
#ifndef BOUTON_H
#define BOUTON_H

#include <string>
#include <SFML/Graphics.hpp>

class Bouton : public sf::Drawable
{
    public:

        Bouton(sf::Vector2f, const std::string &, unsigned int, unsigned int = 255, unsigned int = 255, unsigned int = 255); // constructeur

        sf::Font m_font;
        sf::Vector2f m_position; // position du bouton ("ligne de base" et gauche) / sa fenetre
        unsigned int m_rouge; // couleur rouge fond bouton
        unsigned int m_vert; // couleur vert fond bouton
        unsigned int m_bleu; // couleur bleu fond bouton

        sf::Text m_legende; // texte qui apparait sur le bouton
        sf::RectangleShape m_rect; // rectangle représentant le bouton

    private:

        void draw(sf::RenderTarget&, sf::RenderStates = sf::RenderStates::Default) const; // la méthode de la classe virtuelle à implémenter
};

#endif // BOUTON_H
 

Le CPP associé :

#include "Bouton.h"

Bouton::Bouton(sf::Vector2f position, const std::string &legende, unsigned int htrText, unsigned int rouge, unsigned int vert, unsigned int bleu) : m_position(position), m_rouge(rouge), m_vert(vert), m_bleu(bleu) //constructeur
{

    m_font.loadFromFile("Arial.TTF");
    m_legende.setFont(m_font);
    m_legende.setCharacterSize(htrText);

    m_legende.setOutlineThickness(0);
    m_legende.setOutlineColor(sf::Color::White);
    m_legende.setFillColor(sf::Color::Black);
    m_legende.setString(legende);
    m_legende.setOrigin(m_legende.getLocalBounds().width / 2, 0);
    m_legende.setPosition(position);

    m_rect.setOutlineColor(sf::Color::Black);
    m_rect.setOutlineThickness(5);
    m_rect.setFillColor(sf::Color (m_rouge, m_vert, m_bleu));
    m_rect.setSize(sf::Vector2f(m_legende.getLocalBounds().width, m_legende.getLocalBounds().height));
    m_rect.setOrigin(m_rect.getLocalBounds().width / 2, 0);
    m_rect.setPosition(position.x, position.y + m_legende.getLocalBounds().top);
}

void Bouton::draw(sf::RenderTarget& fenetre, sf::RenderStates) const
{
    fenetre.draw(m_rect);
    fenetre.draw(m_legende);
}
 

J'ai mis les variable en "Public", je sais c'est mal, mais c'est évidement provisoire. ;)

Ensuite j'ai une classe fenêtre qui est composée de la classe bouton. les boutons sont placés dans un vector (le nombre de bouton étant variable d'une instance de fenêtre à l'autre).

Le header de la classe fenetre :

#ifndef FENETRE_H
#define FENETRE_H

#include <iostream>
#include <string>
#include <vector>
#include <SFML/Graphics.hpp>

#include "Bouton.h"

class Fenetre
{
    public:
        Fenetre(const std::string &, const sf::Vector2u &, unsigned int); // constructeur
        Fenetre(const std::string &titre, const sf::VideoMode &Mode, unsigned int numero); // constructeur
        ~Fenetre();

        // methode
        void efface(); // efface le contenu de la fenêtre
        void dessine(sf::Drawable &drawable); // dessine un objet "dessinable"
        void affiche(); // affiche le contenu de la fenêtre

        void evenement(); // gère les événement et met à jour la fenêtre

        void ouvre(unsigned int); // ouvre la fenêtre
        void configure(const std::string &titre, const sf::Vector2u &taille, unsigned int); // configuration de la fenêtre (titre, taille et n° d'ordre d'ouverture)

        void addBouton(sf::Vector2f, std::string, unsigned int, unsigned int = 255, unsigned int = 255, unsigned int = 255); // ajoute un bouton à la fenêtre (position et texte)

        void ferme(); // ferme la fenêtre

        bool fini(); // retourne le statut ouvert ou ferme de la fenêtre

        bool getEtatBouton(unsigned int); // retourne l'état du bouton n° uint de la fenêtre

        // attribut - membre
        sf::RenderWindow m_fenetre; // fenêtre crée par la classe
        sf::Vector2u m_taille; // taille de la fenêtre
        std::string m_titre; // titre de la fenêtre
        unsigned int m_bpp; // nb de bit par pixel
        unsigned int m_no; // numéro d'ordre de fenêtre (ordre d'ouverture)

        bool m_fini; // statut ouvert / fermé de la fenêtre

        unsigned int m_nbBouton; // nombre de bouton de la fenêtre
        std::vector <Bouton> m_vBouton; // vecteur contenant les boutons de la fenêtre
        std::vector <bool> m_vEtatBouton; // vecteur contant l'état des boutons

        sf::Vector2u m_sPos; // position de la souris

    private:

};
#endif // FENETRE_H
 

Et le CPP qui implémente :

#include "Fenetre.h"

Fenetre::Fenetre(const std::string &titre, const sf::Vector2u &taille, unsigned int numero) // c(a)stor
{
    configure(titre, taille, numero);
}

Fenetre::Fenetre(const std::string &titre, const sf::VideoMode &Mode, unsigned int numero) // constructeur
{
    configure(titre, sf::Vector2u(Mode.width, Mode.height), numero);
}

void Fenetre::configure(const std::string &titre, const sf::Vector2u &taille, unsigned int numero)
{
    m_titre = titre;
    m_taille = taille;
    m_no = numero;
    m_fini = false;

    ouvre(numero);

    m_bpp = 32;
}

Fenetre::~Fenetre(){ ferme();}

void Fenetre::addBouton(sf::Vector2f position, std::string legende, unsigned int htrText, unsigned int rouge, unsigned int vert, unsigned int bleu)
{
    Bouton bouton(position, legende, htrText, rouge, vert, bleu);
    m_vBouton.push_back(bouton);
    m_vEtatBouton.push_back(false);
}

bool Fenetre::getEtatBouton(unsigned int numero)
{
    return m_vEtatBouton[numero];
}

void Fenetre::ouvre(unsigned int numero)
{
    if(numero == 0) m_fenetre.create(sf::VideoMode::getDesktopMode(), m_titre, sf::Style::Fullscreen);
    else m_fenetre.create({m_taille.x, m_taille.y, m_bpp}, m_titre, sf::Style::Default);
}

void Fenetre::ferme()
{
    m_fenetre.close();
}

void Fenetre::evenement()
{
    // on inspecte tous les evenements de la fenêtre qui ont ete emis depuis la precedente iteration
    sf::Event event;
    while (m_fenetre.pollEvent(event))
    {
        // evenement "fermeture demandee" : on ferme la fenêtre
        if (event.type == sf::Event::Closed)
            {
            m_fini = true;
            }

        // evenement mouseclick
        if (event.type == sf::Event::MouseButtonPressed)
        {
            // click gauche...
            if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
            {

                // vérif et mise à jour des boutons fenetre (cliqué ou non) ?
                for(unsigned int i = 0; i < m_vBouton.size(); i++)
                {
                    m_sPos.x = sf::Mouse::getPosition(m_fenetre).x;
                    m_sPos.y = sf::Mouse::getPosition(m_fenetre).y;
                    m_vBouton[i].active(m_sPos);
                }
            }
        }

        // evenement bouton relache
        if (event.type == sf::Event::MouseButtonReleased)
        {
                // activation action lié au bouton ?
                for(unsigned int i = 0; i < m_vBouton.size(); i++)
                {
                    m_sPos.x = sf::Mouse::getPosition(m_fenetre).x;
                    m_sPos.y = sf::Mouse::getPosition(m_fenetre).y;
                    m_vBouton[i].desactive(m_sPos);
                    m_vEtatBouton[i] = true;
                }
        }

    }
}

void Fenetre::efface()
{
    for(unsigned int i = 0; i < m_vBouton.size(); i++)
    {
        m_vEtatBouton[i] = false;
    }
    m_fenetre.clear(sf::Color::Black);
}

void Fenetre::dessine(sf::Drawable &drawable)
{
    m_fenetre.draw(drawable);
}

void Fenetre::affiche()
{
    for(unsigned int i = 0; i < m_vBouton.size(); i++)
    {
        m_fenetre.draw(m_vBouton[i]);
    }
    m_fenetre.display();
}

bool Fenetre::fini()
{
    return this -> m_fini;
}
 

Le pb c'est que ça compile...  :-\

Mais lorsque j'instancie une fenetre depuis le main() que j'y ajoute un bouton et que je lance une boucle while "fenetre ouverte", le code plante lors de l'appel au dessin du bouton.
m_fenetre.draw(m_vBouton[i]);

dans Fenetre::affiche() et je suis pas capable de comprendre pourquoi... Je suspecte une mauvaise définiton de la classe bouton héritant de la classe vrtuelle sf::drawable mais je sèche sur le debogage.

En grattant encore un peu je me suis rendu compte que m_rect s'affiche mais pas m_legende.
void Bouton::draw(sf::RenderTarget& fenetre, sf::RenderStates) const
{
    fenetre.draw(m_rect);
    fenetre.draw(m_legende);
}
 
m_legende est pourtant un sf::Text défini par le constructeur du bouton.

Une idée ?

Rick.

P.S : DSL pour le code "en vrac", j'ai essayé mais ce n'est pas facile de faire un code "minimal"
« Modifié: Août 02, 2019, 01:41:44 pm par Rick_Cplusplus »