Evgenii Legotckoi
Evgenii LegotckoiҚаз. 18, 2015, 8:54 Т.Ж.

Qt/C++ - Оқулық 028. QPixmap көмегімен спрайт суреттерді қалай пайдалануға болады

После того, как мы нарисовали sprite в прошлом уроке по работе с Adobe Illustrator, настало время применить полученную картинку при работе с Qt и добавить её в программу с помощью QPixmap. Причем, мы сделаем анимированый sprite, и посмотрим, как происходит маленький анимированый взрыв на графической сцене нашего приложения на Qt.

Структура проекта для работы с QPixmap и sprite

Структура проекта sprite_example будет следующая:

  • sprite_example.pro - профайл проект;
  • widget.h - заголовочный файл основного окна приложения;
  • widget.cpp - файл исходных кодов основного окна приложения;
  • widget.ui - файл интерфейса;
  • sprite.h - заголовочный файл класса, предназначенного для нашего спрайта, в котором будет применяться QPixmap;
  • sprite.cpp - файл исходных кодов для работы с QPixmap;
  • sprite.qrc - ресурсный файл;
  • sprite_sheet.png - наш спрайт, который мы применим для анимации.

widget.ui

Ничего особенного в этом файле нет. Просто растягиваем по всему окно объект QGraphicsView, в который поместим QGraphicsScene .

widget.h

В этом файле мы объявим объект графической сцены, в который поместим объект с QPixmap, в котором будет анимированый sprite. Только не забудьте подключить заголовочный файл 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

В данном файле инициализируем графическую сцену и помещаем её в graphicsView, а также создаём объект спрайта и помещаем его на сцену.

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

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

    scene = new QGraphicsScene();       // Инициализируем графическую сцену

    ui->graphicsView->setScene(scene);  // Устанавливаем графическую сцену в graphicsView

    scene->addItem(new Sprite());       // Помещаем на сцену новый объект спрайта

}

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

sprite.h

А вот теперь поговорим о том, как же реализован анимированый sprite. Для этого нам понадобится заранее подготовленный спрайт, а вернее sprite sheet, который состоит из 15 кадров, расположенных в одну строку.

Технически, данный sprite sheet устанавливается в объект класса QPixmap, в котором он пролистывается слева направо с определенной периодичность. Для этого мы новый класс наследуем от QGraphicsItem и QObject, чтобы использовать сигналы и слоты . И в методе paint задаём отрисовку участка изображения sprite_sheet , который задан в ресурсном файле. Таймер управляет сменой кадров с помощью слота nextFrame(). По сигналу от таймера мы изменяем координату отрисовки участка спрайта и перерисовываем графический объект с новым кадром.

#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();   // Слот для пролистывания изображения в QPixmap

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

private:
    QTimer *timer;      // Таймер для пролистывания изображения в QPixmap
    QPixmap *spriteImage;   // В данный объект QPixamp будет помещён спрайт
    int currentFrame;   // Координата X, с которой начинает очередной кадр спрайта

};

#endif // SPRITE_H

sprite.cpp

В конструкторе класса проводим инициализацию таймера, а в методе paint отрисовываем нужный нам кадр из спрайта. Переключение кадров производится с помощью слота nextFrame().

#include "sprite.h"

Sprite::Sprite(QObject *parent) :
    QObject(parent), QGraphicsItem()
{
    currentFrame = 0;   // Устанавливаем координату текущего кадра спрайта
    spriteImage = new QPixmap(":sprite_sheet.png"); // Загружаем изображение спрайта в QPixmap

    timer = new QTimer();   // Создаём таймер для анимации спрайта
    // Подключаем сигнал от таймера к слоту перелистывания кадров спрайта
    connect(timer, &QTimer::timeout, this, &Sprite::nextFrame);
    timer->start(25);   // Запускаем спрайт на генерацию сигнала с периодичность 25 мс
}

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

void Sprite::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    /* В отрисовщике графического объекта отрисовываем спрайт
     * Разберём все параметры данной функции
     * Первых два аргумента - это координат X и Y куда помещается QPixmap
     * Третий аргумент - это указатель на QPixmap
     * 4 и 5 аргументы - Координаты в В изображении QPixmap, откуда будет отображаться изображение
     * Задавая координату X с помощью перемнной currentFrame мы будем как бы передвигать камеру
     * по спрайту
     * и последние два аргумента - это ширина и высота отображаем части изображение, то есть кадра
     * */
    painter->drawPixmap(-10,-10, *spriteImage, currentFrame, 0, 20,20);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}

void Sprite::nextFrame()
{
    /* По сигналу от таймера передвигаем на 20 пикселей точку отрисовки
     * Если currentFrame = 300 то обнуляем его, поскольку размер sprite sheet 300 пикселей на 20
     * */
    currentFrame += 20;
    if (currentFrame >= 300 ) currentFrame = 0;
    this->update(-10,-10,20,20); // и перерисовываем графический объект с новым кадром спрайта
}

Итог

В результате у Вас получится приложение, в середине окна которого будет находится моргающий взрыв размером 20 на 20 пикселей. Демонстрацию работы приложения Вы можете увидеть в видеоуроке.

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

V
  • Жел. 11, 2018, 2:25 Т.Қ.

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

Evgenii Legotckoi
  • Жел. 11, 2018, 4:01 Т.Қ.

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

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

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

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

this->setWindowFlags(Qt::FramelessWindowHint);      // Отключаем оформление окна
this->setAttribute(Qt::WA_TranslucentBackground);   // Делаем фон главного виджета прозрачным
V
  • Жел. 14, 2018, 9:06 Т.Қ.

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

V
  • Жел. 22, 2018, 12:30 Т.Қ.

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

Evgenii Legotckoi
  • Жел. 22, 2018, 1:53 Т.Қ.

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

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

V
  • Жел. 22, 2018, 2:58 Т.Қ.

Извините, но дилемма в том что - Спрайт должен быть сам по себе без заднего окна и виджета. ( вот то что я хочу сделать-

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

Evgenii Legotckoi
  • Жел. 23, 2018, 4:28 Т.Қ.

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

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

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

V
  • Қаң. 14, 2019, 4:23 Т.Ж.

С Новым годом!
Всё оказалось проще:
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 файла)
\\\
Как сделать так чтобы курсор мышки не реагировал на прозрачное диалоговое окно и я мог спокойно нажимать на ярлыки позади него

Evgenii Legotckoi
  • Қаң. 15, 2019, 10:09 Т.Ж.

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

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

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

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

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

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

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

ЯК
  • Жел. 25, 2020, 9:03 Т.Ж.

А как вы сделали папку ресурсы ?

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
m
  • molni99
  • Қаз. 26, 2024, 1:29 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:20ұпай,
  • Бағалау ұпайлары-10

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

  • Нәтиже:42ұпай,
  • Бағалау ұпайлары-8
Соңғы пікірлер
i
innorwallҚар. 8, 2024, 3:29 Т.Қ.
EVILEG - 4 жыл онлайн buy priligy Pelleted food this way of administration is less stressful for the mice, and a few vendors offer a commercially available chow
i
innorwallҚар. 8, 2024, 8:51 Т.Ж.
Джанго - Сабақ 036. Әлеуметтік желілер арқылы аутентификацияны қалай қосуға болады. Байланыста buy priligy online usa In addition, it might not be effective at the doses recommended, because of your previous tolerance to a similar type of drug
i
innorwallҚар. 8, 2024, 7:40 Т.Ж.
Qt/C++ - 039-сабақ. QSqlTableModel жүйесінде жолды бағандағы мән бойынша бояу әдісі priligy results This slowing of eGFR decline was observed in patients with and without low eGFR and in those with and without type 2 diabetes
i
innorwallҚар. 8, 2024, 2:45 Т.Ж.
QML - Урок 002. QML Android жүйесіндегі пайдаланушы түймесі 2007; 14 2 270 83 priligy dapoxetine 60mg Testicular imaging is sort of a unique niche right now, Гў
Енді форумда талқылаңыз
i
innorwallҚар. 8, 2024, 7:08 Т.Ж.
добавить qlineseries в функции School of Nursing, Long Island University, Brooklyn Campus, Brooklyn, NY, USA priligy dapoxetine 30mg
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Бізді әлеуметтік желілерде бақылаңыз