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

10% refund of hotel reservation amount on Booking
10% refund of hotel reservation amount on Booking
We offer a link with a 10% return on the amount of the order when booking a hotel through Booking
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
TT
June 13, 2019, 7:01 p.m.
Taimoor Tanweer

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

  • Result:66points,
  • Rating points-1
TT
June 13, 2019, 6:51 p.m.
Taimoor Tanweer

C++ - Test 002. Constants

  • Result:75points,
  • Rating points2
ВМ
June 13, 2019, 12:30 p.m.
Ваня Мороз

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

  • Result:100points,
  • Rating points10
Last comments
i
June 17, 2019, 6:10 a.m.
ingenfly

Только по осям xAxis2, уAxis2 значения начинаются с 0. Почему-то xAxis2 и xAxis не синхронизированы по данным. Ну и QCustomPlot последний.
June 16, 2019, 8:21 p.m.
Евгений Легоцкой

Добрый день. Ну точно также добавляете ту же самую информацию на ось xAxis2, только добавляете другое форматирование customPlot->xAxis2->setDateTimeFormat("hh:mm"); если я ...
EF
June 14, 2019, 1:56 p.m.
Egor Fomin

Спасибо за ваш ответ, у меня получилось реализовать это. Тем не менее появилась другая проблема, поэтому опять надеюсь на вашу помощь. Скажем, я уже выставил точки и они соеденены. Когда я нач...
d
June 13, 2019, 2:47 p.m.
damix

Можно классу, который описывает точку, добавить сигнал, который подавать (emit), когда точка перемещается (переопределить mouseMoveEvent или mouseReleaseEvent). Так вот эти сигналы у каждой из...
i
June 13, 2019, 2:09 p.m.
ingenfly

Здравствайте! Подскажите, пожалуйста: customPlot->xAxis2->setTickLabels(true); //Здесь включается отображение данных на оси xAxis2. а можно как-то продублировать информацию cus...
Now discuss on the forum
June 20, 2019, 9:30 a.m.
IscanderChe

Вернулся к этой задачке только-только, поэтому и не ответил ничего раньше.Как переопределить mouseReleaseEvent(QMouseEvent* event) у QTableView, если QTableView задан в ui? Или задавать QTabl...
I
June 19, 2019, 1:41 p.m.
Intruder

Всем добрый день. При разборе XML файла наткнулся на тег вот такого плана: <TagName attribute1="value1" attribute2="value2" /> При попытке проверить на наличие такого элеме...
June 19, 2019, 12:55 p.m.
Михаиллл

Скажите пожалуйста, как его в таком случае перемещать и удалять?
June 18, 2019, 7:50 p.m.
Дмитрий

Большое спасибо! SDK заработал.К сожалению удалось продвинутся только на один шаг. При сборке чистого проекта NDK выдаёт следующие ошибки C:\Android\ndk-bundle/toolchains/arm-linux-andr...
June 18, 2019, 4:59 p.m.
Михаиллл

Добрый день.В этом учебнике представлен код INSTALLED_APPS = ( ... 'rest_framework', 'snippets.apps.SnippetsConfig',) На строчке 'snippets.apps.SnippetsConf...
Looking for a Job?
25,000.00 руб. - 30,000.00 руб.
Разработчик Qt/C++
Barnaul, Altai Krai, Russia

For registered users on the site there is a minimum amount of advertising

EVILEG
About
Services
Join us
© EVILEG 2015-2019
Recommend hosting TIMEWEB