Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
197 views
in Technique[技术] by (71.8m points)

c++ - White square SFML

I've faced with The white square problem at SFML C++ while I'm trying to display a textured button. I've got an ImageButton.h which inherits from Button.h. The texture is loaded successfully (checked in debugger). But in the end, I see a white square. How to solve it?

Button.h

#ifndef BUTTON_H
#define BUTTON_H

#include<SFML/Graphics.hpp>

class Button
{
public:
    Button();
    Button(sf::Vector2f size, sf::Vector2f pos,sf::Color outlineColor, float sizeOutline);
    void virtual draw(sf::RenderWindow* w) = 0;
protected:
    sf::RectangleShape frame;
};



#endif // !BUTTON_H

Button.cpp

#include "Button.h"

Button::Button()
{
}

Button::Button(sf::Vector2f size, sf::Vector2f pos,sf::Color outlineColor, float sizeOutline)
{
    frame.setPosition(pos);
    frame.setSize(size);
    frame.setOutlineColor(outlineColor);
    frame.setOutlineThickness(sizeOutline);
}


ImageButton.h

#ifndef IMAGE_BUTTON_H
#define IMAGE_BUTTON_H

#include"Button.h"

class ImageButton : public Button
{
public:
    ImageButton();
    ImageButton(sf::Vector2f size, sf::Vector2f pos, sf::Color outlineColor, float sizeOutline, std::string path);
    void draw(sf::RenderWindow* w);
private:
    sf::Texture backTexture;
    sf::Sprite background;
};


#endif // !IMAGE_BUTTON_H

ImageButton.cpp

#include "ImageButton.h"

ImageButton::ImageButton()
{
}

ImageButton::ImageButton(sf::Vector2f size, sf::Vector2f pos, sf::Color outlineColor, float sizeOutline, std::string path)
    : Button(size,pos,outlineColor,sizeOutline)
{
    
    backTexture.loadFromFile(path, sf::IntRect(sf::Vector2i(pos.x,pos.y),sf::Vector2i(size.x,size.y)));
    backTexture.setSmooth(true);
    background.setTexture(backTexture);
    background.setPosition(pos);
}

void ImageButton::draw(sf::RenderWindow* w)
{
    w->draw(this->background);
    w->draw(this->frame);
}

programm.h

#ifndef PROGRAMM_H
#define PROGRAMM_H

#include<SFML/Graphics.hpp>
#include"ImageButton.h"


class programm
{
public:
    programm();
    void run();
private:
    ImageButton b;
    sf::RenderWindow* window;
    sf::Event e;
    void render();
    void update();

};
#endif // !PROGRAMM_H

programm.cpp

#include "programm.h"

programm::programm()
{
    this->window = new sf::RenderWindow(sf::VideoMode(600, 600), "Novel Editor", sf::Style::Close);
    this->window->setPosition(sf::Vector2i(0, 0));
    this->window->setFramerateLimit(60);
    this->b = ImageButton(sf::Vector2f(50.f, 50.f), sf::Vector2f(50.f, 50.f), sf::Color::Yellow, 5.f, "images\putin.png");
}

void programm::run()
{
    while (this->window->isOpen())
    {
        while (this->window->pollEvent(e))
        {
            update();
        }
    }
}

void programm::render()
{
    this->window->clear();
    b.draw(this->window);
    this->window->display();
}

void programm::update()
{
    switch (e.type)
    {
    case sf::Event::Closed:
    {
        this->window->close();
        break;
    }
    default:
        break;
    }

    render();
}

Screenshot

enter image description here

question from:https://stackoverflow.com/questions/65858332/white-square-sfml

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
programm::programm()
{
    ...
    this->b = ImageButton(...); //< this line cause the bug
}

You are initializing your image button this->b by assigning from a local ImageButton. Now the sprite will have the texture reference of the local instance's texture, and when the local instance will "die" the texture will be freed. You need to maintain the lifetime of the texture

Solution 1: override the assignment operator and set texture there like this

ImageButton& operator=(const ImageButton& ref) {
        backTexture = ref.backTexture;
        background = ref.background;
        background.setTexture(backTexture);
        return *this;
}

Solution 2: Create a TextureManager and make it as your texture API for all your program, maintain your texture lifetime through it.

Solution 3: initialize the image button at programm constructor

programm::programm()
    :b (sf::Vector2f(50.f, 50.f), sf::Vector2f(50.f, 50.f), sf::Color::Yellow, 5.f, "img.jpg")
{
   ...
}

Another bug

void ImageButton::draw(sf::RenderWindow* w)
{
    w->draw(this->background);
    w->draw(this->frame);
}

you're drawing your frame after the background, and your frame's fill color by default is white

Solution 1: draw frame first and draw background next

Solution 2: set your frame fill color alpha to 0

Button::Button(sf::Vector2f size, sf::Vector2f pos, sf::Color outlineColor, float sizeOutline)
{
    frame.setPosition(pos);
    frame.setSize(size);
    frame.setOutlineColor(outlineColor);
    frame.setFillColor(sf::Color(0, 0, 0, 0)); // <----
    frame.setOutlineThickness(sizeOutline);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...