Qt/C++ - Lesson 028. How to use sprite picture with QPixmap?

QPixmap, Qt sprite, Qt, sprite, sprite QPixmap

Once we have drawn sprite last lesson on working with Adobe Illustrator , it's time to apply the resulting image when working with Qt and add it to the program using QPixmap . Moreover, we do Animated sprite, and see how the small explosion Animated graphics on the stage of our application on Qt.

The project structure to work with QPixmap and sprite

sprite_example project structure will be as follows:

  • sprite_example.pro - the profile of the project;
  • widget.h - header file of the main application window;
  • widget.cpp - file source code of the main application window;
  • widget.ui - interface file;
  • sprite.h - class header file that is used for our sprite, which will be applied QPixmap;
  • sprite.cpp - file source code to work with QPixmap;
  • sprite.qrc - resource file;
  • sprite_sheet.png - our sprite, which we will use for the animation.

widget.ui

Nothing special in this file is not present. Just stretch a box around the object QGraphicsView , which put QGraphicsScene .

widget.h

In this file, we will declare the object of graphic scenes, which put an object with a QPixmap , which will Animated sprite. Just do not forget to include the header file sprite.h.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QGraphicsScene>
#include <QTimer>
#include <QList>
#include <QPixmap>

#include "sprite.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
    QGraphicsScene *scene;  
};

#endif // WIDGET_H

widget.cpp

In this file, we initialize the graphical scene and put it in graphicsView , as well as create a sprite object and place it on the stage.

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    scene = new QGraphicsScene();       // Init graphics scene

    ui->graphicsView->setScene(scene);  // Set grapihcs scene into graphicsView

    scene->addItem(new Sprite());       // We put on the scene a new sprite object

}

Widget::~Widget()
{
    delete ui;
}

sprite.h

And now let's talk about how well implemented Animated sprite. For this we need a prepared sprite, or rather the sprite sheet, which consists of 15 frames, arranged in a single row.

Technically, this sprite sheet is set to QPixmap class object in which it scrolls from left to right with a certain periodicity. To this end, we are a new class inherit from QGraphicsItem and QObject , to use signals and slots . And in the method of drawing the paint Asking sprite_sheet image area, which is defined in the resource file. The timer controls the change of the frame using nextFrame() slot. At a signal from timer we change the coordinate of the drawing area of the sprite and redraw a graphic object with the new frame.

#ifndef SPRITE_H
#define SPRITE_H

#include <QObject>
#include <QGraphicsItem>
#include <QTimer>
#include <QPixmap>
#include <QPainter>

class Sprite : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    explicit Sprite(QObject *parent = 0);

signals:

public slots:

private slots:
    void nextFrame();   // Slot for turning images into QPixmap

private:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    QRectF boundingRect() const;

private:
    QTimer *timer;      // Timer for turning images into QPixmap
    QPixmap *spriteImage;   // In this QPixmap object will be placed sprite
    int currentFrame;   // Coordinates X, which starts the next frame of the sprite

};

#endif // SPRITE_H

sprite.cpp

In the class constructor initializes the timer and the method of paint we draw the right frame of the sprite. Switching is performed using frames nextFrame() slot.

#include "sprite.h"

Sprite::Sprite(QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    currentFrame = 0;   // Sets the coordinates of the current frame of the sprite
    spriteImage = new QPixmap(":sprite_sheet.png"); // Load the sprite image QPixmap

    timer = new QTimer();   // Create a timer for sprite animation
    connect(timer, &QTimer::timeout, this, &Sprite::nextFrame);
    timer->start(25);   // Run the sprite on the signal generation with a frequency of 25 ms
}

QRectF Sprite::boundingRect() const
{
    return QRectF(-10,-10,20,20);
}

void Sprite::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    /* In the graphic renderer we draw the sprite
     * The first two arguments - is the X and Y coordinates of where to put QPixmap
     * The third argument - a pointer to QPixmap
     * 4 and 5 of the arguments - The coordinates in the image QPixmap, where the image is displayed
     * By setting the X coordinate with the variable currentFrame we would like to move the camera on the sprite
     * and the last two arguments - the width and height of the displayed area, that is, the frame
     * */
    painter->drawPixmap(-10,-10, *spriteImage, currentFrame, 0, 20,20);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}

void Sprite::nextFrame()
{
    /* At a signal from the timer 20 to move the point of rendering pixels
     * If currentFrame = 300 then zero out it as sprite sheet size of 300 pixels by 20
     * */
    currentFrame += 20;
    if (currentFrame >= 300 ) currentFrame = 0;
    this->update(-10,-10,20,20); 
}

Result

As a result, you get the app in the middle of the window which will be blinking an explosion the size of 20 by 20 pixels.

Video

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
Support the author Donate
V

Подскажите пожалуйста ( я новичок совсем) Можно ли организовать спрайт без этого окошка (как в fl studio fruity dance)?

Не знаю, какой-там конкретно эффект и если честно не хочется fl studio ради того, чтобы посмотреть устанавливать, но из того, что увидел в интернете.

Предполагаю, что то, что вы хотите сделать, в данном случае нужно реализовывать точно также с окном, но с одним существенным отличием. Нужно полностью отключить обрамление окна, а в нём отрисовывать спрайт в виджете с прозрачным фоном.

Вот в этой статье было что-то похожее. Там я отключал обрамление окна и кастомизировал виджеты.

Обратите внимание вот на эти строчки

this->setWindowFlags(Qt::FramelessWindowHint);      // Отключаем оформление окна
this->setAttribute(Qt::WA_TranslucentBackground);   // Делаем фон главного виджета прозрачным
V

Спасибо большое! Очень помогли!

V

А возможно всё кроме спрайта сделать прозрачным?

"всё" - это что?

по факту я вам уже ответил и на этот вопрос.

V

Извините, но дилемма в том что - Спрайт должен быть сам по себе без заднего окна и виджета. ( вот то что я хочу сделать- https://youtu.be/pUHrZprN4_A) А у меня получается пока что лишь уменьшить виджет и сделать прозрачным окно,

Прошу прощения за надоедливые и банальные вопросы

Прошу прощения за надоедливые и банальные вопросы

Да не в этом дело.

По сути, там всё тоже самое, только отображайте спрайт в отдельном диалоговом окне, у которого будет полностью отключено обрамление и т.д. Просто используйте QDialog, чтобы спрайт отдельно крутился.

V

С Новым годом! Всё оказалось проще: MAIN.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QtGui/QGuiApplication>
#include <QScreen>



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

    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;



    return app.exec();
}



QML


import QtQuick 2.0
import QtQuick.Window 2.2

Window {
    flags: Qt.ToolTip | Qt.FramelessWindowHint | Qt.WA_TintedBackground |Qt.WindowStaysOnTopHint

    color: "#00000000"


visible: true
width: 100
height: 460
x: (Screen.width - width)
y: (Screen.height - height)




Rectangle {
    anchors.fill: parent
    color: "transparent"
}
AnimatedSprite {

    id: sprite;
    width: 100;
    height: 100;
    anchors.centerIn: parent;
     source: "Donald.png"
     frameX: 0
     frameY: 0
     frameRate: 18;
     frameWidth: 100
     frameHeight: 100
     frameCount: 24
     running: folse;

У меня всего 2 вопроса: \\ Как В файле QML менять значение с помощью переменной из Main frameX: 0 не через класс? ( желательно считывание из txt файла) \\\ Как сделать так чтобы курсор мышки не реагировал на прозрачное диалоговое окно и я мог спокойно нажимать на ярлыки позади него

Ну вы здесь тоже самое сделали, что я вам и советовал... только ещё QML за уши притянули.

frameX - только через класс устанавливать. В QML все объекты наследованы от QObject и там работа с классами идёт. Максимум использовать JavaScript встроенный в QML, но опять же без C++ и классов ничего вы не сделаете.

Как сделать так чтобы курсор мышки не реагировал на прозрачное диалоговое окно и я мог спокойно нажимать на ярлыки позади него

Это было бы проще реализовать через классические виджеты, также нужно лезть в API операционной системы. Я такое не делал, небоходимости не было. Могу сказать только, что нужно искать информацию по эмулированию кликов, чтобы перекинуть клик за окно приложения. В общем в три строки эо не делается.

Планомерно изучайте Qt, с ростом опыта разберётесь, как это сделать, но я могу вам только общее направление по этой задаче подсказать и кое-какие примеры, но вопросы у вас должны быть более гранулированными, а не так, "как написать программу, которая сделает то, что вы хотите". Серьёзно, для того, что вам нужно, требуется изучить больше, чем вот эта одна строка из вашего кода

flags: Qt.ToolTip | Qt.FramelessWindowHint | Qt.WA_TintedBackground |Qt.WindowStaysOnTopHint

значительно больше

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Donate

Hello, Dear Users of EVILEG!!!

If the site helped you, then support the development of the site financially, please.

You can do it by following ways:

Thank you, Evgenii Legotckoi

DK
April 1, 2020, 8:03 a.m.
Dmitry Kozhinov

C++ - Test 001. The first program and data types

  • Result:40points,
  • Rating points-8
A
March 30, 2020, 12:47 p.m.
Anna

C++ - Test 001. The first program and data types

  • Result:60points,
  • Rating points-1
A
March 29, 2020, 12:14 p.m.
Alexanderv66

C++ - Тест 003. Условия и циклы

  • Result:71points,
  • Rating points1
Last comments
April 3, 2020, 8:06 a.m.
Konstantin Grudnitskiy

Я надеюсь вы уже разобрались в чем дело, но если вдруг нет, то проблема состоит в том, что вы пытаетесь запустить программу из интерпретатора питона. Файл main.py это уже готова…
April 3, 2020, 6:18 a.m.
Konstantin Grudnitskiy

>>> text = 'hello world'>>> ' '.join(word for word in text.split()[:-1])'hello'>>> def remove_last_word(text):... return text and ' '.join(word for word in text.s…
March 27, 2020, 2:40 p.m.
Evgenij Legotskoj

Добрый день. В конце пятой статьи скачать можете.
March 27, 2020, 2:28 p.m.
mkdir _

Здравствуйте, а можно, пожалуйста, ссылку на целые исходники, если есть?
March 27, 2020, 4:36 a.m.
Evgenij Legotskoj

Скорее всего также, как и для установки всех остальных переменых в CMake, через использование set
Now discuss on the forum
April 5, 2020, 5:09 a.m.
IscanderChe

Попробуйте CQtDeployer или windeployqt.
April 5, 2020, 2:35 a.m.
Mihailll

Так работает console.log(textEmail.text) var str = textEmail.text; var n = str.search(/^((([0-9A-Za-z]{1}[-0-9A-z\.]{1,}[0-9A-Za-z]{1})|([0-9А-Яа-я]{1}[-0-9А-я\.]{1,}[…
April 3, 2020, 12:53 p.m.
BlinCT

Само собою на компе этого незаметно.
April 3, 2020, 8:48 a.m.
Intruder

Евгений, добрый день. Спасибо!
s
April 3, 2020, 7:52 a.m.
solmik

да вроде много чего установленно, если неправильный путь указать то же самое, пробовал запустить видео через плей лист (по примерам из док)и из него назад путь взять, не получилось
EVILEG
About
Services
© EVILEG 2015-2019
Recommend hosting TIMEWEB