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

Author Topic: [SOLVED] SFML doesn't show my button class of the vector  (Read 739 times)

0 Members and 1 Guest are viewing this topic.

dimon98165

  • Newbie
  • *
  • Posts: 3
    • View Profile
    • Email
[SOLVED] SFML doesn't show my button class of the vector
« on: January 06, 2025, 09:02:43 pm »
I wanted to create the vector with buttons but any texture there doesn't show correctly.... i don't know why it happens...
I tested and the class "BUTTON_FIXED" in the same stream, and it works correctly... but when i put it in the vector then BOOOM! By the word "BOOOM!" i mean SFML shows my buttons without texture so it shows white color.

heres my own class:

```
template<typename text_t_name> class BUTTON_FIXED{
    sf::RectangleShape button_sprite;
    sf::Text button_text;
    sf::Texture button_normal_texture;
    sf::Texture button_pressed_texture;
    sf::Clock timer;
    bool animation_locked = false;
    std::string button_status = "unpressed";
    int x_button_text = 0;
    int y_button_text = 0;

    //атрибуты
    std::string ownership = "";
public:
    /*
        [параметры]
        text - обязательно,
        size - обязательно,
        char_size - необязательно,
        bgcolor - необязательно,
        textcolor - обязательно,
        text_font - обязательно,
        normal_texture - обязательно,
        pressed - обязательно,
    */

    BUTTON_FIXED(text_t_name text, sf::Vector2f size, int* char_size, sf::Color* bgcolor, sf::Color textcolor, sf::Font& text_font, sf::Texture normal_texture, sf::Texture pressed_texture){
        button_normal_texture = normal_texture;
        button_pressed_texture = pressed_texture;

        button_sprite.setSize(size);

        button_text.setString(text);
        button_text.setFont(text_font);
        button_text.setFillColor(textcolor);

        if(char_size != nullptr){
            button_text.setCharacterSize((*char_size));
        }
        else{
            int i = 0;
            while((button_text.getLocalBounds().width < button_sprite.getLocalBounds().width) && (button_text.getLocalBounds().height < button_sprite.getLocalBounds().height)){
                button_text.setCharacterSize(i);
                i++;
            }
        }
        button_sprite.setTexture(&button_normal_texture);
        button_sprite.setOrigin(button_sprite.getLocalBounds().width/2, button_sprite.getLocalBounds().height/2);

        if(bgcolor != nullptr){
            button_sprite.setFillColor((*bgcolor));
        }

        button_text.setOrigin(button_text.getLocalBounds().width/2, button_text.getLocalBounds().height/2);
    };
    void setPos(int x, int y){
        button_sprite.setPosition(x, y);
        button_text.setPosition(x, y - (button_text.getLocalBounds().height * 0.3));
        x_button_text = x;
        y_button_text = y - (button_text.getLocalBounds().height * 0.3);
    };
    void init(){
        while(true){
            if(this->button_status == "pressed"){
                timer.restart();
                sf::Clock local_timer;
                local_timer.restart();
                if(this->animation_locked == false){
                    button_sprite.setTexture(&button_pressed_texture);
                    button_text.setPosition(this->x_button_text, this->y_button_text + 2);
                    this->animation_locked = true;
                };
                while(true){
                    if(local_timer.getElapsedTime().asSeconds() >= 0.5f){
                        break;
                    }
                }
                if(timer.getElapsedTime().asSeconds() >= 0.5f){
                    button_sprite.setTexture(&button_normal_texture);
                    button_text.setPosition(this->x_button_text, this->y_button_text);
                    this->animation_locked = false;
                    this->button_status = "unpressed";
                }
            }
            utility::wait_milliseconds(100);
        }
    };
    void click(){
        this->button_status = "pressed";
    }
    bool IsTarget(float mouse_x, float mouse_y){
        float x_max = button_sprite.getPosition().x + button_sprite.getLocalBounds().width/2;
        float x_min = button_sprite.getPosition().x - button_sprite.getLocalBounds().width/2;

        float y_max = button_sprite.getPosition().y + button_sprite.getLocalBounds().height/2;
        float y_min = button_sprite.getPosition().y - button_sprite.getLocalBounds().height/2;

        if (mouse_x <= x_max
            &&
            mouse_x >= x_min
            &&
            mouse_y <= y_max
            &&
            mouse_y >= y_min) {
           
            return true;
        }
        return false;
    }
    void drawTo(sf::RenderWindow& window){
        window.draw(button_sprite);
        window.draw(button_text);
    };
    void set_ownership(std::string& new_ownership){
        this->ownership = new_ownership;
    };
    std::string get_ownership(){
        return this->ownership;
    };
};
```
 

and heres im testing the class... the variable "test_accept" is attempt of creating button(it was successfully showed without problems). But then i put in the vector and BOOOM! again... :
```
struct friends_requests{
                    std::vector<sf::Texture> textures_fr;
                    std::vector<sf::RectangleShape> recshapes;
                    std::vector<std::string> user_ids;
                    std::vector<int*> positions;
                    std::vector<sf::Text> texts;
                    sf::Texture accept_png;
                    sf::Texture decline_png;
                    std::vector<BUTTON_FIXED<const wchar_t*>> vector_of_buttons;

                    friends_requests(P_Directory_Finder_win64& path){
                        std::wstring accept_path = path.get_wpath() + L"\\assets\\images\\accept.png";
                        if(image::loadImageFromUnicodePath(accept_path, this->accept_png) != 0){
                             exit(1);
                        };
                        std::wstring decline_path = path.get_wpath() + L"\\assets\\images\\decline.png";
                        if(image::loadImageFromUnicodePath(decline_path, this->decline_png) != 0){
                             exit(1);
                        };
                    };
                    void load(sf::RectangleShape shape2, std::string& user_id, int* calculated_pos){
                        this->recshapes.push_back(shape2);
                        this->user_ids.push_back(user_id);
                        this->positions.push_back(calculated_pos);
                    };
                    void out(sf::RenderWindow& window, int* mouse_pos, bool& mouse_is_interacting_window){

                        int i_int = 0;
                        if(!this->recshapes.empty()){
                            sf::Font text_font2;
                            if (!text_font2.loadFromFile("assets\\fonts\\montserrat\\static\\Montserrat-Regular.ttf")){
                                std::cerr << "font load failed" << std::endl;
                                exit(1);
                            };
                            BUTTON_FIXED<const wchar_t*> test_accept(L"", {50, 50}, new int(1), nullptr, sf::Color::White, text_font2, accept_png, accept_png);
                            test_accept.setPos(500, 500);
                            test_accept.drawTo(window);
                            for(auto i = this->recshapes.begin(); i != this->recshapes.end(); i++){
                                sf::Text text;
                                text.setString(this->user_ids[i_int]);
                                text.setCharacterSize(20);
                                text.setFont(text_font2);
                                text.setFillColor(sf::Color::White);
                                text.setOrigin(0, text.getLocalBounds().height/2);
                                text.setPosition(this->positions[i_int][0] - 325, this->positions[i_int][1] - 5);
                                this->texts.push_back(text);
                                i_int++;
                            };
                            i_int = 0;

                            for(auto i = this->recshapes.begin(); i != this->recshapes.end(); i++){
                                window.draw((*i));
                                window.draw(this->texts[i_int]);
                                i_int++;
                            };
                                for(int i = 0; i != i_int; i++){
                                    BUTTON_FIXED<const wchar_t*> accept(L"", {50, 50}, new int(1), nullptr, sf::Color::White, text_font2, accept_png, accept_png);
                                    BUTTON_FIXED<const wchar_t*> decline(L"", {50, 50}, new int(1), nullptr, sf::Color::White, text_font2, decline_png, decline_png);
                               

                                    accept.setPos(this->positions[i][0] + 225, this->positions[i][1]);
                                    decline.setPos(this->positions[i][0] + 300, this->positions[i][1]);

                                    accept.set_ownership(this->user_ids[i]);
                                    decline.set_ownership(this->user_ids[i]);

                                    // std::future<void> async_init5 = std::async(std::launch::async, [&accept](){
                                    //     accept.init();
                                    // });
                                    // std::future<void> async_init6 = std::async(std::launch::async, [&decline](){
                                    //     decline.init();
                                    // });

                                    this->vector_of_buttons.push_back(accept);
                                    this->vector_of_buttons.push_back(decline);
                                };
                                int pos_array[2] = {0, 1};
                                for(int i = 0; i != i_int; i++){
                                    this->vector_of_buttons[pos_array[0]].drawTo(window);
                                    this->vector_of_buttons[pos_array[1]].drawTo(window);
                                    pos_array[0]+=2;
                                    pos_array[1]+=2;
                                };
                                if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && mouse_is_interacting_window == true)
                                {
                                    int pos2_array[2] = {0, 1};
                                    for(int i = 0; i != i_int; i++){
                                        if(vector_of_buttons[pos2_array[0]].IsTarget(mouse_pos[0], mouse_pos[1])){
                                            vector_of_buttons[pos2_array[0]].click();
                                        };
                                        if(vector_of_buttons[pos2_array[1]].IsTarget(mouse_pos[0], mouse_pos[1])){
                                            vector_of_buttons[pos2_array[1]].click();
                                        };
                                        pos2_array[0]+=2;
                                        pos2_array[1]+=2;
                                    };
                                };
                        };
                        free(mouse_pos);
                    };
                    void free_memory(){
                        textures_fr.clear();
                        recshapes.clear();
                        user_ids.clear();
                        for(auto i = positions.begin(); i != positions.end(); i++){
                            free(*i);
                        }
                        positions.clear();
                        vector_of_buttons.clear();
                    };
            };
            friends_requests requests = friends_requests(path);
```


heres code where i put arguments in it, so you can look at that:
```
//friends_requests
                            if(!args_to_extract["<friends_requests>"].empty()){
                                int i3 = 1;

                                for(auto i = args_to_extract["<friends_requests>"].begin(); i != args_to_extract["<friends_requests>"].end(); i++){
                                    //std::cout << *i << std::endl; //имя друга, который кинул запрос

                                    sf::RectangleShape example(sf::Vector2f(700, 70));
                                    unsigned int y = 90 * i3;
                                   
                                    example.setOrigin(example.getLocalBounds().width/2, example.getLocalBounds().height/2);
                                    example.setPosition(size.width/2, 100 + y);
                                    example.setTexture(&friends_requests_background_png);

                                    int* positions = (int*)malloc(sizeof(int) * 2);
                                    *(positions+0) = size.width/2;
                                    *(positions+1) = 100 + y;

                                    requests.load(example, (*i), positions);
                                    i3++;
                                };
                                int* mos_pos = (int*)malloc(sizeof(int) * 4);
                                *(mos_pos + 0) = mouse_y;
                                *(mos_pos + 1) = mouse_x;

                                requests.out(window, mos_pos, mouse_is_interacting_window);
                                requests.free_memory();
                            };
```
 

heres screenshot of anything i see: https://ibb.co/3pvwVQv
« Last Edit: January 07, 2025, 11:25:46 am by dimon98165 »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11084
    • View Profile
    • development blog
    • Email
Re: SFML doesn't show my button class of the vector
« Reply #1 on: January 07, 2025, 09:27:06 am »
This is the so called "white square problem": https://www.sfml-dev.org/tutorials/3.0/graphics/sprite/#the-white-square-problem

The sprite gets a pointer to the texture, but since both are in the same class, which is in a vector, that may reallocate all the objects at a different memory space, your texture is moved in memory and the pointer is invalidated. As such the sprite is no longer "linking" to the texture and you get an untextured button.

The second issue with this setup is, that whenever your class is copied, the texture is also copied, which is an expensive operation, as the data needs to be transferred again to the GPU.

The "simple" fix for the first problem is to call setTexture again.
The better fix that also solves the second problem is to use something like a ResourceHolder, that manages the lifetime and ownership of the texture and then just inject that texture into the class where needed, that way the texture doesn't get moved around in memory.
Official FAQ: https://www.sfml-dev.org/faq/
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

dimon98165

  • Newbie
  • *
  • Posts: 3
    • View Profile
    • Email
Re: SFML doesn't show my button class of the vector
« Reply #2 on: January 07, 2025, 11:25:31 am »
THANK YOU VERY MUCH!!!!!!!!!!!!!!!!!!!!!!!!!!!! YAY!!!!!!!

 

anything