首页
学习
活动
专区
圈层
工具
发布

白方SFML
EN

Stack Overflow用户
提问于 2021-01-23 10:52:28
回答 2查看 339关注 0票数 1

当我试图显示一个纹理按钮时,我在SFML C++上遇到了白方问题。我有一个ImageButton.h,它继承了Button.h。纹理已成功加载(签入调试器)。但最后,我看到了一个白方。如何解决这个问题?

Button.h

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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);
}

程序h

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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();
}

截图

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-01-23 14:17:33

代码语言:javascript
复制
programm::programm()
{
    ...
    this->b = ImageButton(...); //< this line cause the bug
}

您正在通过从本地this->b分配来初始化图像按钮ImageButton。现在,sprite将具有本地实例纹理的纹理引用,并且当本地实例“死亡”时,纹理将被释放。您需要保持纹理的生命周期。

解决方案1:重写赋值操作符并在那里设置纹理,如下所示

代码语言:javascript
复制
ImageButton& operator=(const ImageButton& ref) {
        backTexture = ref.backTexture;
        background = ref.background;
        background.setTexture(backTexture);
        return *this;
}

解决方案2:创建一个TextureManager并使其成为您所有程序的纹理API,通过它维护您的纹理生存期。

解决方案3:在programm构造函数处初始化图像按钮

代码语言:javascript
复制
programm::programm()
    :b (sf::Vector2f(50.f, 50.f), sf::Vector2f(50.f, 50.f), sf::Color::Yellow, 5.f, "img.jpg")
{
   ...
}

另一个bug

代码语言:javascript
复制
void ImageButton::draw(sf::RenderWindow* w)
{
    w->draw(this->background);
    w->draw(this->frame);
}

您正在根据背景绘制框架,默认情况下,框架的填充颜色为白色

解决方案1:先绘制框架,然后绘制背景

解决方案2:将框架填充颜色α设置为0

代码语言:javascript
复制
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);
}
票数 2
EN

Stack Overflow用户

发布于 2021-01-23 12:39:05

您和其他人(关于reddit就这样其他地方)所面临的问题是由sf::Sprite的构造函数和赋值操作符的实现方式造成的:由于开发人员决定不实现专门的函数,并且没有将它们设置为私有函数,所以编译器提供了默认设置,它们不知道m_texture指针的语义,因此执行二进制副本。这可能不是最好的方法,而是它被记录在案

因此,如果您在类中使用sf::Sprite成员而没有采取特殊的复制措施,编译器将假定默认赋值语义,从而调用sf::Sprite类的(无效)赋值语义。在ImageButton中创建的本地ImageButton对象调用ImageButton的默认赋值。

代码语言:javascript
复制
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");
}

成员Sprite b从本地ImageButton中的Sprite接管指针texture,该指针的生存期仅限于programm构造函数的范围。除此之外,成员sprite中的b保存对破坏的纹理对象的引用,该对象导致未定义的行为(另请参阅sf::Sprite类参考(SFML / Learn / 2.4.1文档)):

如果源纹理被破坏,而sprite试图使用它,则该行为是未定义的。

顺便说一下,我建议在program类中直接使用program,而不是通过指针,这样您就可以将代码更改为类似的代码(注意,我使用了button而不是b,为了简洁起见,我缩短了内联实现)。

代码语言:javascript
复制
class programm
{
public:
    programm():
        window(sf::VideoMode(600, 600), "Novel Editor", sf::Style::Close);
        button(sf::Vector2f(50.f, 50.f), sf::Vector2f(50.f, 50.f), 
        sf::Color::Yellow, 5.f, "images\\putin.png")
    {
        window->setPosition(sf::Vector2i(0, 0));
        window->setFramerateLimit(60);
    }
    // ...
private:
    // ...
    sf::RenderWindow window;
    ImageButton button;
};

另一个选项是为您的ImageButton类提供一个专门的赋值操作符(ImageButton)或复制构造函数,该构造函数负责纹理对象的深度复制。

或者,您可以考虑为sf::Sprite实现一个包装类来解决这个问题,并将其用于您的应用程序。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65858332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档