Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Modify textures stored in vector  (Read 2354 times)

0 Members and 3 Guests are viewing this topic.

salem987

  • Newbie
  • *
  • Posts: 7
    • View Profile
Modify textures stored in vector
« on: June 24, 2018, 06:54:21 pm »
Hi everyone,

I made a kind of "Button" class that is composed of a sprite and a text on it.

One of the functions of the class is the setText function that just set a new text on the button:

void Button::setText(std::string newText){
    textOnButton.setString(newText);
}

It actually works in the main():

fleetButton.setText("Heyy") for example works and the new text of the button fleetButton becomes "Heyy".

However, I would like to store all my future button in a vector.

std::vector<Button> listOfButtons;
listOfButtons.push_back(fleetButton);

However, the setText doesn't work anymore if I use it like this :

for(int i =0; i<listOfButtons.size();i++){
        listOfButtons[i].setText("Hey");
 }

In fact, the text doesn't change.

It's the same for the setTexture function that I have.

Thanks for the help ^^
« Last Edit: June 25, 2018, 10:42:32 am by Laurent »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Modify textures stored in vector
« Reply #1 on: June 24, 2018, 10:47:54 pm »
listOfButtons.setText("Hey");
That's not how you access elements in a vector.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

salem987

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Modify textures stored in vector
« Reply #2 on: June 25, 2018, 12:29:17 am »
listOfButtons.setText("Hey");
That's not how you access elements in a vector.

The [ i ] seemed to have disappeared in my message lol, I mean

listOfButtons [ i ].setText of course
« Last Edit: June 25, 2018, 12:31:42 am by salem987 »

salem987

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Modify textures stored in vector
« Reply #3 on: June 25, 2018, 10:40:48 am »
It is really confusing since fleetButton.setText("heyy"); works perfectly but once in a vector and called with listOfButtons [ i ].setText("heyy"); it doesn't work anymore.. Does it have something to do with pointers maybe?

I also have tried this way:

for(auto &i : listOfButtons)
                    {

                        if(i.checkClick(sf::Mouse::getPosition().x,sf::Mouse::getPosition().y))
                        {

                            i.setText("heyy");

                        }
                    }

But still nothing.
« Last Edit: June 25, 2018, 10:46:19 am by Laurent »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Modify textures stored in vector
« Reply #4 on: June 25, 2018, 10:44:24 am »
"Doesn't work" is not a problem description. If you have a compiler error then write it here; if you have a crash write the call stack and show us which line crashes; if you have unexpected results then explain what you expect and what you get instead, etc.

And please use the [code]...[/code] tags for posting code.
« Last Edit: June 25, 2018, 10:45:58 am by Laurent »
Laurent Gomila - SFML developer

salem987

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Modify textures stored in vector
« Reply #5 on: June 25, 2018, 11:03:05 am »
The problem is that there no error message at all from the compiler.

Here are some screenshots with this piece of code:

Code: [Select]
if (event.type == sf::Event::MouseButtonPressed)
            {
                if (event.mouseButton.button == sf::Mouse::Left)
                {
                   
                   fleetButton.setText("Heyy");

                }
            }


Before clicking:



After clicking:



It works perfectly fine here ^^

However, if I put now the Button object in a vector and call setText from it,

Code: [Select]
std::vector<Button> listOfButtons;
listOfButtons.push_back(fleetButton);

and then

Code: [Select]
if (event.type == sf::Event::MouseButtonPressed)
            {
                if (event.mouseButton.button == sf::Mouse::Left)
                {
     
                    for(auto &i : listOfButtons)
                    {

                          i.setText("heyy");
                       
                    }

                }
            }

When I click, the text on the button does not change anymore, while it should be "hey". I'm really stuck here since I don't know where the problem comes from ^^'.

Thanks for the help :P

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Modify textures stored in vector
« Reply #6 on: June 25, 2018, 11:27:06 am »
When you push_back elements to the vector, you put copies of them. Therefore, fleetButton and listOfButtons[i] are two different variables; if you change the text of listOfButtons[i] and then draw fleetButton you won't see the modification.
Laurent Gomila - SFML developer

salem987

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Modify textures stored in vector
« Reply #7 on: June 25, 2018, 12:01:02 pm »
Thanks for your answer, in fact I have been drawing the fleetButton and not listOfButtons[0].

However, I have put

Code: [Select]
window.draw(*listOfButtons[0].getSprite());
window.draw(*listOfButtons[0].getText());

instead now, and still nothing :/ .

Does that mean that listOfButton[0] (modified after the loop) gets destroyed when the for loop ends?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Modify textures stored in vector
« Reply #8 on: June 25, 2018, 12:29:38 pm »
You don't seem to fully understand what your code does (or is supposed to do). Maybe you should practice more, with simpler examples, before writing your final code.

Anyway, if you want more help, you should write a complete and minimal code that reproduces the problem. We can't help if we can't see the whole code.
Laurent Gomila - SFML developer

salem987

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Modify textures stored in vector
« Reply #9 on: June 25, 2018, 02:39:01 pm »
I have made now a Test class, which is a minimalist Button class with just a texture and a text on it.

Test.h :

Code: [Select]

#ifndef TEST_H
#define TEST_H
#include <string>
#include <SFML/Graphics.hpp>


class Test
{
public:
    Test(sf::Vector2f location,std::string tstring);
    sf::Sprite* getSprite();
    sf::Text * getText();
    void setText(std::string newText);

private:
    sf::Font font;
    sf::Sprite normal;
    sf::Sprite clicked;
    sf::Sprite* currentSpr;
    sf::Text textOnButton;
    sf::Text* normalText;
    int middleX;
    int middleY;
    int characterSize;
    sf::Texture simplePic;
    sf::Texture simplePicClicked;

};

#endif // TEST_H


Test.cpp :

Code: [Select]

#include "Test.h"


Test::Test(sf::Vector2f location,std::string tstring)
{
    simplePic.loadFromFile("button.png");
    this->font.loadFromFile("arial.ttf");
    simplePicClicked.loadFromFile("buttonClicked.png");
    normal.setTexture(simplePic);
    clicked.setTexture(simplePicClicked);
    this->currentSpr=&this->normal;
    this->normal.setPosition(location);
    this->clicked.setPosition(location);
    if((25*tstring.length()) > simplePic.getSize().x)
    {
        characterSize = ((simplePic.getSize().x) / tstring.length());
    }
    else
    {
        characterSize = 25;
    }
    textOnButton.setFont(font);
    textOnButton.setCharacterSize(characterSize);
    textOnButton.setStyle(sf::Text::Bold);
    textOnButton.setString(tstring);
    textOnButton.setString(tstring);
    middleX = (currentSpr->getPosition().x  + (simplePic.getSize().x / (characterSize*tstring.length()))) + (simplePic.getSize().x - textOnButton.getGlobalBounds().width)/2;
    middleY = (currentSpr->getPosition().y  + (simplePic.getSize().y / 3));
    textOnButton.setPosition(middleX,middleY);
    this->normalText=&this->textOnButton;

}

sf::Sprite* Test::getSprite()
{
    return currentSpr;
}

sf::Text* Test::getText()
{

    return normalText;
}

void Test::setText(std::string newText)
{
    textOnButton.setString(newText);
}


And finally the main :

Code: [Select]

#include <vector>
#include "Test.h"

int main()
{

    sf::VideoMode DesktopMode = sf::VideoMode::getDesktopMode();
    sf::RenderWindow window;
    window.create(DesktopMode,"The Game", sf::Style::Fullscreen);
    Test fleetButton(sf::Vector2f(500,500),"TextA");
    std::vector<Test> listOfButtons;
    listOfButtons.push_back(fleetButton);

    // run the program as long as the window is open
    while (window.isOpen())
    {
        // check all the window's events that were triggered since the last iteration of the loop
        sf::Event event;
        while (window.pollEvent(event))
        {
            // on regarde le type de l'évènement...
            switch (event.type)
            {
            // fenêtre fermée
            case sf::Event::Closed:
                window.close();
                break;

            // touche pressée
            case sf::Event::KeyPressed:
                return 0;
                break;

            // on ne traite pas les autres types d'évènements
            default:
                break;
            }
            if (event.type == sf::Event::MouseButtonPressed)
            {
                if (event.mouseButton.button == sf::Mouse::Left)
                {

                    fleetButton.setText("Heyy");

                }
            }

        }
        window.clear(sf::Color::Black);
        window.draw(*fleetButton.getSprite());
        window.draw(*fleetButton.getText());
        window.display();

    }
}


We can notice here that fleetButton sets the text to "heyy" correctly (like the 2 pictures I sent earlier).
However, if I replace fleetButton by listOfButtons[ 0 ], like here:

Code: [Select]

#include <vector>
#include "Test.h"

int main()
{

    sf::VideoMode DesktopMode = sf::VideoMode::getDesktopMode();
    sf::RenderWindow window;
    window.create(DesktopMode,"The Game", sf::Style::Fullscreen);
    Test fleetButton(sf::Vector2f(500,500),"TextA");
    std::vector<Test> listOfButtons;
    listOfButtons.push_back(fleetButton);

    // run the program as long as the window is open
    while (window.isOpen())
    {
        // check all the window's events that were triggered since the last iteration of the loop
        sf::Event event;
        while (window.pollEvent(event))
        {
            // on regarde le type de l'évènement...
            switch (event.type)
            {
            // fenêtre fermée
            case sf::Event::Closed:
                window.close();
                break;

            // touche pressée
            case sf::Event::KeyPressed:
                return 0;
                break;

            // on ne traite pas les autres types d'évènements
            default:
                break;
            }
            if (event.type == sf::Event::MouseButtonPressed)
            {
                if (event.mouseButton.button == sf::Mouse::Left)
                {

                    listOfButtons[0].setText("Heyy");

                }
            }

        }
        window.clear(sf::Color::Black);
        window.draw(*listOfButtons[0].getSprite());
        window.draw(*listOfButtons[0].getText());
        window.display();

    }
}


When I click, the text stays the same :(


Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Modify textures stored in vector
« Reply #10 on: June 25, 2018, 03:07:22 pm »
It's really bad to store resources (fonts and textures) inside the object that use them: when it gets copied around (because of std::vector), all links between font/text and texture/sprite will be broken, since your class doesn't implement a copy constructor. So this design is definitely wrong.
Laurent Gomila - SFML developer

salem987

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Modify textures stored in vector
« Reply #11 on: June 25, 2018, 04:14:10 pm »
I finally made it work with this:

Code: [Select]

#include <vector>
#include "Test.h"

int main()
{

    sf::VideoMode DesktopMode = sf::VideoMode::getDesktopMode();
    sf::RenderWindow window;
    window.create(DesktopMode,"The Game", sf::Style::Fullscreen);
    Test fleetButton(sf::Vector2f(500,500),"TextA");
    std::vector<Test*> listOfButtons;
    listOfButtons.push_back(&fleetButton);

    // run the program as long as the window is open
    while (window.isOpen())
    {
        // check all the window's events that were triggered since the last iteration of the loop
        sf::Event event;
        while (window.pollEvent(event))
        {
            // on regarde le type de l'évènement...
            switch (event.type)
            {
            // fenêtre fermée
            case sf::Event::Closed:
                window.close();
                break;

            // touche pressée
            case sf::Event::KeyPressed:
                return 0;
                break;

            // on ne traite pas les autres types d'évènements
            default:
                break;
            }
            if (event.type == sf::Event::MouseButtonPressed)
            {
                if (event.mouseButton.button == sf::Mouse::Left)
                {

                    listOfButtons[0]->setText("Heyy");

                }
            }

        }
        window.clear(sf::Color::Black);
        window.draw(*listOfButtons[0]->getSprite());
        window.draw(*listOfButtons[0]->getText());
        window.display();

    }
}


I shoud just have initialized the vector like this:

Code: [Select]
std::vector<Test*> listOfButtons;

and not like this:

Code: [Select]
std::vector<Test> listOfButtons;

even if I don't really know why ^^

Thank you!
« Last Edit: June 25, 2018, 04:15:56 pm by salem987 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Modify textures stored in vector
« Reply #12 on: June 25, 2018, 04:30:33 pm »
When you store pointers, you copy those pointers, not the objects themselves. Therefore there's no copy, and you avoid the problems that you previously had. But this means that your objects have to be stored somewhere else, and that your vector is just a "view" on them.
Laurent Gomila - SFML developer