Integrating SFML 2 with Qt5

Setting up a SFML 2 & QtCreator 5 development environment

I wanted to have an SFML rendering widget in a Qt application. There’s some resources online about how to do it, but the ones I found were outdated.

This was built with:

I won’t go into too much detail about the actual code, and rather the process of building & linking a QT/SFML app.

Very basic linking/compilation knowledge would help, but isn’t required. You should have a little bit of experience with QtCreator and SFML though.

First, grab the SFML Github repo, or you can find the SFML package using sudo apt-get. I compiled from source so I knew where the library path was.

If you don’t already have QtCreator installed, go ahead and get it from the Qt Project website or using apt-get. For this, I just used apt-get (I did download it from the Qt Project site, but that gave me a strange issue with the SFML::RenderWindow)

Now create a new Qt project. In the .pro file, you’re going to link to the SFML libraries:

LIBS += -L[PATH_TO_SFML]/lib -lsfml-graphics -lsfml-window -lsfml-system

Now, we’re going to create a custom Qt widget where SFML can render. The code is mostly based on Laurent Gomila’s tutorial, but there are some changes since that was written for SFML 1.6.

Our first class, QSFMLCanvas, will be a parent class for our SFML widgets. It overrides Qt’s natural rendering process so that SFML can be free to render on its own.

/* Header file */
#ifndef QSFMLCANVAS_H
#define QSFMLCANVAS_H

#include <SFML/Graphics.hpp>
#include <QWidget>
#include <QTimer>

class QSFMLCanvas : public QWidget, public sf::RenderWindow
{
  Q_OBJECT
  private:
  virtual void onInit() = 0;
  virtual void onUpdate() = 0;

  virtual QPaintEngine* paintEngine() const;

  virtual void showEvent(QShowEvent* e);

  virtual void paintEvent(QPaintEvent* e);

  QTimer mTimer;
  bool mInitialized;

  public:
  explicit QSFMLCanvas(QWidget *parent, const QPoint& position, const QSize& size, unsigned int frametime = 0);

  virtual ~QSFMLCanvas();

  signals:

  public slots:

};

#endif // QSFMLCANVAS_H

///////////////////////////////////////////////////////////////////////////////////////////////////

/* Source file */
#include "qsfmlcanvas.h"

QSFMLCanvas::QSFMLCanvas(QWidget *parent, const QPoint &position, const QSize &size, unsigned int frameTime) :
QWidget(parent), mInitialized(false)
{
  setAttribute(Qt::WA_PaintOnScreen);
  setAttribute(Qt::WA_OpaquePaintEvent);
  setAttribute(Qt::WA_NoSystemBackground);

  setFocusPolicy(Qt::StrongFocus);

  move(position);
  resize(size);

  mTimer.setInterval(frameTime);
}

#ifdef Q_WS_X11
#include <qt qx11info_x11.h="">
#include <x11 xlib.h="">#endif

void QSFMLCanvas::showEvent(QShowEvent* e)
{
  if(!mInitialized)
  {
    #ifdef Q_WS_X11
    XFlush(QX11Info::display());
    #endif

    sf::RenderWindow::create(winId());
    onInit();

    connect(&mTimer, SIGNAL(timeout()), this, SLOT(repaint()));
    mTimer.start();
    mInitialized = true;
  }
}

QPaintEngine* QSFMLCanvas::paintEngine() const
{
  return 0;
}

void QSFMLCanvas::paintEvent(QPaintEvent* e)
{
  onUpdate();
  sf::RenderWindow::display();
}

QSFMLCanvas::~QSFMLCanvas()
{
}

Our next class will inherit from the QSFLMCanvas class, and this is where we can start writing SFML related code as normal.

/* Header file */
#ifndef MYCANVAS_H
#define MYCANVAS_H

#include "qsfmlcanvas.h"

class MyCanvas : public QSFMLCanvas
{
  Q_OBJECT
  private:
  void onInit();
  void onUpdate();

  sf::Texture mTexture;
  sf::Sprite mSprite;
  sf::Image mImage;

  public:
  explicit MyCanvas(QWidget *parent, const QPoint& position, const QSize& size);

  signals:

  public slots:
};

#endif // MYCANVAS_H

///////////////////////////////////////////////////////////////////////////////////////////////////

/* Source file */
#include "mycanvas.h"

MyCanvas::MyCanvas(QWidget *parent, const QPoint& position, const QSize& size) :
QSFMLCanvas(parent, position, size)
{
}

void MyCanvas::onInit()
{
  /* put pic.png in your Build-Debug*** directory so that the program can find it*/
  mTexture.loadFromFile("pic.png");
  mSprite.setTexture(mTexture);
}

void MyCanvas::onUpdate()
{
  sf::RenderWindow::clear(sf::Color(0, 0, 0));
  draw(mSprite);
}

Now in our main.cpp, we create a QFrame to hold our MyCanvas widget in.

#include "mainwindow.h"
#include "mycanvas.h"
#include <QApplication>
#include <QFrame>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);

  QFrame frame;
  frame.show();

  MyCanvas SFMLView(&frame, QPoint(0, 0), QSize(100, 100));
  SFMLView.show();

  int ret = a.exec();

  return ret;
}

Hopefully the program compiles & is able to find the necessary libraries. I spent a few hours trying to get this to work (mostly due to the error I mentioned above). Setting up an environment is the least fun part of developing, and I hope that this helped at least a little bit.

Back