Partage
  • Partager sur Facebook
  • Partager sur Twitter

SFML - Classe Button, message d'erreur

    20 juin 2023 à 15:29:39

    Bonjour à tous, 

    Je rencontre un problème dans le code d'un logiciel fait avec SFML, j'essaie de créer une classe Button qui contient la forme du bouton (RectangleShape) et son texte (Text).

    Le problème apparait quand j'exécute le programme en mode debug, la console m'affiche :
    "Exception non gérée à 0x00007FFBB03469E9 (sfml-graphics-d-2.dll) dans Vokey.exe : 0xC0000005 : Violation d'accès lors de la lecture de l'emplacement 0xFFFFFFFFFFFFFFFF." 

    voici le code : 

    class Button.cpp : 

    #include "button.hpp"
    
    Button::Button(string btn_txt, int chr_size, Vector2f size)
    {
    	// Initalisation du rectangle
    	button.setSize(Vector2f(size.x, size.y));
    	button.setFillColor(BUTTON_COLOR);
    	button.setOrigin(button.getSize().x / 2, button.getSize().y / 2);
    
    	// Initalisation du texte
    	if (!font.loadFromFile("src/JosefinSans-Bold.ttf"))
    	{
    		cout << "Erreur chargement de la Font" << endl;
    		
    	}
    	text.setFont(font);
    	text.setString(btn_txt);
    	text.setCharacterSize(chr_size);
    	text.setFillColor(TEXT_COLOR);
    	text.setPosition(0, 0);
    }
    
    void Button::setPosition(Vector2f pos)
    {
    	button.setPosition(pos);
    	text.setPosition(pos);
    }
    
    Vector2f Button::getPosition()
    {
    	return button.getPosition();
    }
    
    void Button::draw(RenderWindow& window)
    {
    	
    	window.draw(text);
    	window.draw(button);
    }

    main.cpp :

    #include "main.hpp"
    
    int main()
    {
        // =====> Création éléments menu
            //Logo :
        Sprite vokey_logo;
        Texture vokey_logo_texture;
        if (!vokey_logo_texture.loadFromFile("src/vokey.png"))
            cout << "logo non chargé" << endl;
        vokey_logo.setTexture(vokey_logo_texture);
        vokey_logo.setPosition(100, 100);
    
            //Bouttons :
        vector<Button> buttons_menu;
        for (int i = 0; i < 4; i++)
        {
            string text3 = "texte";
            buttons_menu.push_back(Button(text3, 5, Vector2f(400, 65)));
        }
    
        buttons_menu[0].setPosition(Vector2f(window.getSize().x / 2, 420));
        buttons_menu[1].setPosition(Vector2f(window.getSize().x / 2, buttons_menu[0].getPosition().y + 80));
        buttons_menu[2].setPosition(Vector2f(window.getSize().x / 2, buttons_menu[1].getPosition().y + 80));
        buttons_menu[3].setPosition(Vector2f(window.getSize().x / 2, 800));
    
    
    	while (window.isOpen())
    	{
            while (window.pollEvent(event)) {
                input.InputHandler(event, window);
                checkBtn();
            } 
            window.clear(Color(43, 43, 53));
            displayMenu(window, vokey_logo, buttons_menu);
    
            window.draw(text1);
            window.display();
    	}
    }
    
    void displayMenu(RenderWindow& window, Sprite& logo, vector<Button>& buttons)
    {
        window.draw(logo);
        for (auto &button : buttons)
        {
            button.draw(window);
        }
    }
    

    Je précise que le problème disparait lorsque je supprime la ligne window.draw(text) dans la fonction Button::draw()

    Si vous avez des idées je suis preneur, merci d'avance :)

    -
    Edité par CédricL'Informaticien 20 juin 2023 à 15:35:07

    • Partager sur Facebook
    • Partager sur Twitter
      21 juin 2023 à 9:30:59

      Utilisez un débogueur.

      Où et comment les champs windows et text sont sensés être initialisés ?

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        21 juin 2023 à 10:06:09

        Ces variables sont initialisées dans les .hpp que je n'ai pas inclus, je pense que ce n'est pas nécessaire, je peux vous les partager si besoin mais j'ais simplement fais :

        //Main.hpp
        RenderWindow window(VideoMode(800, 900), "Vokey");
        
        //Button.hpp
        RectangleShape button;
        



        Par contre je n'ai pas compris, qu'entendez vous par "Utilisez un débogueur", Visual Studio l'inclus de base non ? 



        -
        Edité par CédricL'Informaticien 21 juin 2023 à 10:08:44

        • Partager sur Facebook
        • Partager sur Twitter
          21 juin 2023 à 11:04:10

          Bonjour,

          Ce que veux dire bacelar, je pense c'est de compiler en mode Debug (donc avec l'option qui permet de produire les symboles de débuggage) puis de lancer l' exécutable ainsi généré avec le Debugger (clic droit sur le projet de l'exécutable, choisir 'déboguer'  puis 'démarrer une nouvelle 'instance' ). Avec un debugger, tu as la possibilité d' exécuter en mode pas à pas ton programme et également de mettre des 'breakpoints' qui vont dire au debugger de s'arrêter à ce 'breakpoint' à ce moment là tu pourras surveiller la valeur actuelle des différentes variables qui sont dans la portée de la fonction.

          • Partager sur Facebook
          • Partager sur Twitter

          Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

            21 juin 2023 à 11:23:37

            Je n'utilise pas cette lib, mais :

            Un main.hpp je ne suis pas pour, le module qui contient la fonction main, n'est pas voué à être réutilisé.

            Les définitions de variables serait mieux placées dans les fichiers sources .cpp , les fichiers entêtes .hpp sont plutôt voués aux déclarations.

            Et aussi éviter autant que possible les variables globales.

            • Partager sur Facebook
            • Partager sur Twitter
            ...
              21 juin 2023 à 13:24:36

              Warren79 a écrit:

              Bonjour,

              Ce que veux dire bacelar, je pense c'est de compiler en mode Debug (donc avec l'option qui permet de produire les symboles de débuggage) puis de lancer l' exécutable ainsi généré avec le Debugger (clic droit sur le projet de l'exécutable, choisir 'déboguer'  puis 'démarrer une nouvelle 'instance' ). Avec un debugger, tu as la possibilité d' exécuter en mode pas à pas ton programme et également de mettre des 'breakpoints' qui vont dire au debugger de s'arrêter à ce 'breakpoint' à ce moment là tu pourras surveiller la valeur actuelle des différentes variables qui sont dans la portée de la fonction.

              J'utilisais donc déjà cette option par contre je ne connaissais pas les breakpoint c'est génial merci ! Par contre je ne trouve quand même pas la solution :(

              rouIoude a écrit:

              Je n'utilise pas cette lib, mais :

              Un main.hpp je ne suis pas pour, le module qui contient la fonction main, n'est pas voué à être réutilisé.

              Les définitions de variables serait mieux placées dans les fichiers sources .cpp , les fichiers entêtes .hpp sont plutôt voués aux déclarations.

              Et aussi éviter autant que possible les variables globales.

              Ok donc j'ai supprimé mon main.hpp et à l'avenir j'essaie d'éviter les variables globales, merci du conseil 

              -
              Edité par CédricL'Informaticien 21 juin 2023 à 13:26:33

              • Partager sur Facebook
              • Partager sur Twitter
                21 juin 2023 à 15:23:35

                Petite précision à l'intervention de @Warren79, pas besoin de compiler en Mode Debug pour pouvoir déboguer, on peut générer des informations de debugging même en Release, même si c'est moins précis et plus compliqué à suivre.

                Je suis tout à fait d'accord avec @rouloude, pas de code dans les .hpp.

                Potentiellement inclus plusieurs fois, on ne sait pas si les différentes "instances" des variables globales seront fusionnées ou pas, on ne sait pas dans quel ordre ce foutoir global s'initialise, etc...

                Qu'est qui garantit que votre variable globale "window" est initialisée quand Button::draw de votre variable globale "button" est appelé ?

                Rien, si elles ne sont pas défini dans la même unité de compilation. (et bonjour la galère quand ces cochonneries sont dans des .cpp différents et encore pire quand c'est dans des .h)

                -
                Edité par bacelar 21 juin 2023 à 18:03:02

                • Partager sur Facebook
                • Partager sur Twitter
                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                  21 juin 2023 à 15:46:37

                  Bacelar a écrit [... Release et mode Debug à la fois ]

                  Je le savais déjà ;), cela fait partie des options de génération de projets dans CMake sous l'appelation 'RelWithDebInfo', logiciel que j'utilise depuis pas mal d'années  mais comme je n'utilise ce mode de génération que très peu je n' y avais plus pensé. Je développe principalement sous xubuntu avec codelite,  gcc et CMake mais parfois je teste aussi d'autres plateformes avec CMake comme Windows avec visual Studio ou mingw en ligne de commande avec des fichiers batchs.

                  J'avais utilisé le profiler de Visual Studio une fois pour tester un programme de jeu vidéo que j'avais créé en C++ pour savoir dans quels fonctions mon programme passait le plus de temps, cela m'avait permis de déceler une fonction qui n' était pas nécessairement utile à chaque tour de boucle de ma fonction update() une fois le jeu en mode partie et j'avais vu également que la fonction la plus utilisée dans une partie par le joueur était celle qui testait si un délai impartit s' était écoulé.

                  bool AccurateTimeDelay::hasTimeElapsed(std::chrono::milliseconds elapsedTime) const
                  {
                  	return std::chrono::steady_clock::now() - precedent >= elapsedTime;
                  }
                  

                  Par contre je ne sais plus si j'avais généré l' exécutable en Debug ou en RelWithDebInfo.:)

                  -
                  Edité par Warren79 21 juin 2023 à 21:42:35

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

                    21 juin 2023 à 18:05:00

                    Faire du profiling en Debug, ça n'a pas beaucoup de sens. ;-)
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                      21 juin 2023 à 23:21:44

                      ça sent la ligne 16 du button.cpp qui saute lors du push_back

                      la texture est perdue et il tape à son ancien emplacement alors qu'il n'a plus le droit d'y accéder

                      • Partager sur Facebook
                      • Partager sur Twitter
                        22 juin 2023 à 8:38:58

                        Djarkan a écrit:

                        ça sent la ligne 16 du button.cpp qui saute lors du push_back

                        la texture est perdue et il tape à son ancien emplacement alors qu'il n'a plus le droit d'y accéder


                        Alors comment je peux le vérifier et le corriger ? C'est bien pour ça que que la variable font est déclarée comme private pour éviter qu'elle ne perde sa valeur attribuée ? Et qu'est ce que tu entend par "la ligne 16  saute lors du push_back"

                        • Partager sur Facebook
                        • Partager sur Twitter
                          22 juin 2023 à 9:07:15

                          bacelar a écrit:

                          Faire du profiling en Debug, ça n'a pas beaucoup de sens. ;-)


                          Disons, que comme je ne fais que des jeux indépendants / amateurs, si ça rame à un moment donné dans un de mes jeux c'est plus le code que je produis qui serait fautif de ce ralentissement. Ma config: AMD Ryzen 3700X et Nvidia RTX 2700. D' autant plus que la SDL2 a des fonctions de dessinage/drawing assez performantes comme la SFML 2. C'est pour cette raison que je ne lance pas souvent le profiler sous Visual Studio. Par contre à chaque fois que j' implémente une nouvelle fonctionnalité dans un de mes programmes je le teste systématiquement en mode Debug.

                          -
                          Edité par Warren79 3 juillet 2023 à 21:02:46

                          • Partager sur Facebook
                          • Partager sur Twitter

                          Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

                            22 juin 2023 à 11:44:30

                            Utilisez le débogueur !
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                              22 juin 2023 à 20:28:12

                              ta font est vivante du loadFromFile jusqu'a la fin du constructeur

                              j'enleverais la font du bouton pour que les 2 soient indépendants, et ajouterais une methode au bouton pour charger la font

                              une fois le bouton créé. donc la texture reste en vie le temps de vie de la font et non du construteur du bouton

                              une variable est en vie entre ses { }

                              rien

                              {

                              type variable      // naissance

                              }  // mort , mémoire déallouée

                              • Partager sur Facebook
                              • Partager sur Twitter
                                22 juin 2023 à 20:54:08

                                @Djarkan : L'objet font ne me semble pas créé dans le constructeur de la classe Button. (On ne sais pas où il est crée, mais il n'est pas local au constructeur de la classe Button).

                                • Partager sur Facebook
                                • Partager sur Twitter
                                ...
                                  23 juin 2023 à 0:46:57

                                  non mais il est chargé d'un fichier dedans donc à la sortie du constructeur la mémoire est libérée et il ne garde que l'adresse des font TTF

                                  donc quand il veut s'en servir dans le main ....

                                  oui / non ?

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    23 juin 2023 à 9:08:24

                                    Comme j'ai dit plus haut, je n'utilise pas cette lib, mais il n'y a aucune raison que l'objet font soit modifié (que la police de caractère soit déchargée) à la sortie du constructeur de la classe Button.

                                    Ce qui est détruit à la sortie d'un bloc ce sont les variables locales au bloc (variables automatiques). Or ici ce n'est pas le cas. 

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    ...
                                      23 juin 2023 à 13:33:00

                                      rouIoude a écrit:

                                      Comme j'ai dit plus haut, je n'utilise pas cette lib, mais il n'y a aucune raison que l'objet font soit modifié (que la police de caractère soit déchargée) à la sortie du constructeur de la classe Button.

                                      Ce qui est détruit à la sortie d'un bloc ce sont les variables locales au bloc (variables automatiques). Or ici ce n'est pas le cas. 


                                      C'est ce qui me semble aussi ! La variable font est déclarée dans le Button.hpp c'est une variable private comme dit plus haut, elle ne devrait pas perdre sa valeur puisqu'elle est initialisée dans le constructeur

                                      Button.hpp

                                      #include <SFML/Graphics.hpp>
                                      #include <iostream>
                                      
                                      using namespace std;
                                      using namespace sf;
                                      
                                      #define BUTTON_COLOR Color(217, 217, 217)
                                      #define TEXT_COLOR Color(255, 255, 255)
                                      
                                      class Button
                                      {
                                      public:
                                      	Button(string btn_txt, int chr_size, Vector2f size);
                                      	void update(RenderWindow& window);
                                      	void setPosition(Vector2f pos);
                                      	void draw(RenderWindow& window);
                                      	void startClickAnimation();
                                      
                                      	//GETS
                                      	Vector2f getPosition();
                                      	FloatRect getGlobalBounds();
                                      
                                      private:
                                      	RectangleShape button;
                                      	Font font;
                                      	Text text;
                                      	Clock time;
                                      
                                      	bool start_animation;
                                      	float scale_speed;
                                      
                                      };



                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        24 juin 2023 à 11:43:07

                                        j ai une classe bitmaptext qui contient une classe bitmapfont

                                        le constructeur de bitmaptext appele le constructeur de bitmapfont

                                        je passe soit le nom de la fonte ou l'adresse le la font

                                         BitmapText(std::string fontName, unsigned int glyphWidth, unsigned int glyphHigth);
                                         BitmapText(sf::Texture& fontTexture, unsigned int glyphWidth, unsigned int glyphHigth);
                                        
                                        BitmapText::BitmapText(std::string fontName, unsigned int glyphWidth, unsigned int glyphHigth) : m_bitmapFont(fontName, glyphWidth, glyphHigth),
                                                                                                                                         m_fontName{fontName}, m_glyphWidth{glyphWidth},
                                                                                                                                         m_glyphHigth{glyphHigth}, m_scale{1}
                                        {
                                        
                                        }
                                        
                                        
                                        
                                        BitmapText::BitmapText(sf::Texture& fontTexture, unsigned int glyphWidth, unsigned int glyphHigth) : m_bitmapFont(fontTexture, glyphWidth, glyphHigth),
                                                                                                                                             m_glyphWidth{glyphWidth}, m_glyphHigth{glyphHigth}, m_scale{1}
                                        {
                                        
                                        }
                                        
                                        
                                        
                                        BitmapFont(std::string fileName, unsigned int glyphWidth, unsigned int glyphHigth);
                                                                                        BitmapFont(sf::Texture& fontTexture, unsigned int glyphWidth, unsigned int glyphHigth);
                                        
                                        BitmapFont::BitmapFont(std::string fileName, unsigned int glyphWidth, unsigned int glyphHeigth) : m_glyphWidth{glyphWidth}, m_glyphHeigth{glyphHeigth}
                                        {
                                            setBitmapFont(fileName);
                                        }
                                        
                                        BitmapFont::BitmapFont(sf::Texture& fontTexture, unsigned int glyphWidth, unsigned int glyphHeigth) : m_letterTexture{fontTexture}, m_glyphWidth{glyphWidth}, m_glyphHeigth{glyphHeigth}
                                        {
                                            m_letterSprite.setTexture(fontTexture);
                                            sf::Vector2u textSize = m_letterTexture.getSize();
                                            m_nbColunms = textSize.x / m_glyphHeigth;
                                        }
                                        
                                        bool BitmapFont::setBitmapFont(std::string fileName)
                                        {
                                            bool success = m_letterTexture.loadFromFile(fileName);
                                            if(success) { m_letterSprite.setTexture(m_letterTexture); }
                                            sf::Vector2u textSize = m_letterTexture.getSize();
                                            m_nbColunms = textSize.x / m_glyphHeigth;
                                            return success;
                                        }



                                        tant je je l'utilise "à la volée" cela fonctionne, des que je la met dans un container push_back ou std::make_unique ... badaboum j'ai aussi un crash violation d'acces

                                        donc cedric est ce que sans le mettre dans un vecteur , ton bouton fonctionne ??

                                        avant d'en faire plein, est ce qu'il fonctionne seul ?

                                        -
                                        Edité par Djarkan 24 juin 2023 à 11:59:15

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          27 juin 2023 à 12:05:55

                                          Question:
                                          Un bouton doit-il "posséder" une font ?

                                          Chaque fois qu'un bouton est instancié, une font est instanciée et chargée, donc accès au disque.
                                          C'est très dommage, d'autant que la plupart du temps, les boutons d'une interface graphique utilisent la même font.
                                          A mon avis, il sera plus judicieux d'externaliser les fonts, et faire en sorte que le bouton "utilise" une font.

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            27 juin 2023 à 13:46:10

                                            Djarkan a écrit:

                                            donc cedric est ce que sans le mettre dans un vecteur , ton bouton fonctionne ??

                                            avant d'en faire plein, est ce qu'il fonctionne seul ?

                                            -
                                            Edité par Djarkan 24 juin 2023 à 11:59:15


                                            Non, même seul le problème reste le même

                                            Deedolith a écrit:

                                            Question:
                                            Un bouton doit-il "posséder" une font ?

                                            Chaque fois qu'un bouton est instancié, une font est instanciée et chargée, donc accès au disque.
                                            C'est très dommage, d'autant que la plupart du temps, les boutons d'une interface graphique utilisent la même font.
                                            A mon avis, il sera plus judicieux d'externaliser les fonts, et faire en sorte que le bouton "utilise" une font.


                                            C'est vrais vous avez raison, par contre même en créant la font depuis le main.cpp et en la passant en paramètre au constructeur le problème apparait toujours.

                                            J'ai réussi à le faire fonctionner avec une méthode pas du tout efficace : J'ai crée une fonction update qui crée une font et l'applique au texte avant de le dessiner à chaque répétition de ma boucle principale. Cela "règle" le soucis mais ce n'est pas du tout optimisé

                                            Si quelqu'un a une meilleur solution ...   

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              27 juin 2023 à 16:10:48

                                              La dernière version du code sera utile.
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                27 juin 2023 à 16:16:25

                                                Au faite :

                                                    if (!font.loadFromFile("src/JosefinSans-Bold.ttf"))
                                                    {
                                                        cout << "Erreur chargement de la Font" << endl;
                                                         
                                                    }
                                                    text.setFont(font);

                                                tu as une console pour voir les erreurs ? parce que si tu as un échec au chargement du fichier font tu continues quand même.

                                                Tu pourrais peut-être utiliser les exceptions pour gérer ça ?

                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                ...

                                                SFML - Classe Button, message d'erreur

                                                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                • Editeur
                                                • Markdown