Graphics View framework for Qt learning (realizing startup animation)

Posted by amylou on Wed, 16 Feb 2022 02:24:05 +0100

catalogue

1, Realization effect

2, Brief introduction to elements, views and scenes

1. Interrelationship

2. Header file

         3. Implementation process

3, Code implementation

1. Customize an Item (element)

1.1. Create a new class myItem, which inherits from QGraphicsItem

1.2. myItem header file (. h)

1.3 overloaded constructor

1.4 # boundingRect function and paint function implementation

1.5. Implementation of advance function

1.6 complete code (. cpp)

2. Customize a view

2.1. Create a new class, WelcomeWin, which inherits from QGraphicsView

2.2. Welcome win header (. h)

2.3. Welcome win complete code (. cpp)

4, Main function test

1, Realization effect

If the elements collide, it indicates that the startup is successful.

2, Brief introduction to elements, views and scenes

1. Interrelationship

Primitives: included in the scene. A scene can have multiple primitives.

View: it is equivalent to a small window used to observe the scene. The view can have multiple scenes.

Scene: it is equivalent to a curtain with many elements (primitives).

2. Header file

#Include < qgraphicsitem > / / element

#Include < qgraphicsview > / / view

#Include < qgraphicsscene > / / scene

3. Implementation process

The general process is as follows: new element - > new scene - > scene adding element - > New View - > view associated scene.

3, Code implementation

1. Customize an Item (element)

1.1. Create a new class myItem, which inherits from QGraphicsItem

Remember to tick QObject, because signals and slots will be used later.

1.2. myItem header file (. h)

The custom Item class mainly overrides the boundingRect function, paint function and advance function. boundingRect is used to return a rectangular box of collision size, which has an impact on subsequent collision detection. The paint function is mainly used for drawing primitives to realize user-defined primitives. The advance function is used to move elements.

And customized a signal: void MyItemcolliding(), which is mainly used to transmit the signal after two primitives collide, and then the primitives disappear and start up successfully.

Because the signal is used, Q should be added_ Object macro and inherit it from QObject, otherwise an error may appear later.

#ifndef MYITEM_H
#define MYITEM_H

#include <QObject>
#include <QString>
#include <QGraphicsItem>

class myItem : public QObject, public QGraphicsItem
{
    Q_OBJECT
public:
    myItem();
    myItem(int x,int y,QString file,int pos);
    QRectF boundingRect() const override;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;

private:
    int x,y,w,h,role;
    QString file;

public slots:
    void advance(int phase) override;

signals:
    void MyItemcolliding();
};

#endif // MYITEM_H

1.3 overloaded constructor

Int # x, int # y: position (coordinates) of the entity

QString file: the path of the picture to be loaded by the element

int role: the type of element. This example is mainly used to define police and thieves

myItem::myItem(int x, int y, QString file, int role)
{
    this->x=x;
    this->y=y;
    this->role=role;
    this->file=file;
    this->w=QImage(this->file).width();
    this->h=QImage(this->file).height();
    this->setPos(this->x,this->y);
}

1.4 # boundingRect function and paint function implementation

collidingItems() will return a linked list of colliding elements, that is, the elements in collision are stored in it. You can use the {isEmpty() function to judge whether the elements collide. The return value of isEmpty() function is bool type. If it is empty, it returns true; otherwise, it returns false.

QRectF myItem::boundingRect() const
{
    //qreal penWidth = 1; // Do not define the brush width, and directly replace it with 0

    return QRectF(0, 0, this->w, this->h);//Returns the rectangle of the collision
}


void myItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    //Indicates that the parameter is not used
    Q_UNUSED(option)
    Q_UNUSED(widget)

    if(collidingItems().isEmpty())//No collision with other drawing items
    {
        //Draw without collision, and the element disappears after collision (do not draw)
        painter->drawImage(QRectF(0,0,this->w,this->h),QImage(this->file));
    }

    //You can add an else, and the primitive collides with it and becomes another picture
}

1.5. Implementation of advance function

If collidingItems() is not empty, a custom signal will be sent when the collision occurs.

void myItem::advance(int phase)
{
    //If phase is 0, it means that the movement will begin, and then return
    if(!phase)
    {
        return;
    }
    if(!collidingItems().isEmpty())
    {
        emit MyItemcolliding();//Transmit signal after collision
    }
    if(this->role == 1)//Police, move fast
    {
        moveBy(-5,0);//Move left 5
    }
    else if(this->role == -1)//Thief, move slowly
    {
        moveBy(-2,0);//Move left 2
    }

}

1.6 complete code (. cpp)

#include "myitem.h"
#include <QPainter>

myItem::myItem()
{

}

myItem::myItem(int x, int y, QString file, int role)
{
    this->x=x;
    this->y=y;
    this->role=role;
    this->file=file;
    this->w=QImage(this->file).width();
    this->h=QImage(this->file).height();
    this->setPos(this->x,this->y);
}

QRectF myItem::boundingRect() const
{
    //qreal penWidth = 1; // Do not define the brush width, and directly replace it with 0
    return QRectF(0, 0, this->w, this->h);
}

void myItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    //Indicates that the parameter is not used
    Q_UNUSED(option)
    Q_UNUSED(widget)

    if(collidingItems().isEmpty())//No collision with other drawing items
    {
        //Draw without collision, and the element disappears after collision (do not draw)
        painter->drawImage(QRectF(0,0,this->w,this->h),QImage(this->file));
    }
    //You can add an else, and the primitive collides with it and becomes another picture
}

void myItem::advance(int phase)
{
    //If phase is 0, it means that the movement will begin, and then return
    if(!phase)
    {
        return;
    }
    if(!collidingItems().isEmpty())
    {
        emit MyItemcolliding();//Transmit signal after collision
    }
    if(this->role == 1)//Police, move fast
    {
        moveBy(-5,0);//Move left 5
    }
    else if(this->role == -1)//Thief, move slowly
    {
        moveBy(-2,0);//Move left 2
    }

}

2. Customize a view

2.1. Create a new class, WelcomeWin, which inherits from QGraphicsView

Remember to tick QObject.

 

2.2. Welcome win header (. h)

It includes two custom primitives, a timer, a scene, and a slot function. Add Q, too_ Object macro.

#ifndef WELCOMEWIN_H
#define WELCOMEWIN_H

#include <QObject>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QTimer>
#include "myitem.h"

class WelcomeWin : public QGraphicsView
{
    Q_OBJECT
public:
    WelcomeWin();

private:
    myItem *item1, *item2; //Add two custom items
    
    QTimer *timer;  //Timer for element movement
    
    QGraphicsScene *sence;  //scene

public slots:
    void timerStop(); //Slot function, which is used to turn off the timer and prompt that the startup is successful
};

#endif // WELCOMEWIN_H

2.3. Welcome win complete code (. cpp)

#include "welcomewin.h"
#include <QMessageBox>

WelcomeWin::WelcomeWin()
{
    timer=new QTimer;
    //New element
    item1=new myItem(this->width()-240,450,"image/thrief.png",-1);//-1 stands for thief
    item2=new myItem(this->width()+100,450,"image/police.png",1);//1 on behalf of the police

    //New scene
    sence=new QGraphicsScene;
    sence->setSceneRect(0,0,this->width()+459,this->height()+368);//Set the scene position, which can be adjusted according to your own background image

    //Adding elements to a scene
    sence->addItem(item1);
    sence->addItem(item2);

    //View associated scene
    this->setScene(sence);
    this->setFixedSize(800,550);
    
    this->setWindowTitle("Welcome");
    this->setBackgroundBrush(QBrush(QPixmap("image/start-background.jpeg")));//Set view background
    this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//Do not slide the bar horizontally
    this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//Do not slide the bar vertically

    this->setWindowFlags(Qt::FramelessWindowHint);//Set form borderless
    this->setWindowIcon(QIcon("image/police badge.png"));

    //timer
    connect(timer,SIGNAL(timeout()),sence,SLOT(advance()));//When the timer expires, the advance function of the element will be called and the element will move
    timer->start(30);//Timeout every 30 milliseconds

    connect(item2,SIGNAL(MyItemcolliding()),this,SLOT(timerStop()));//Element collisions send a MyItemcolliding() signal and associate slots
}

//Slot function implementation
void WelcomeWin::timerStop()
{
    this->timer->stop(); //Timer off 

    QMessageBox msgBox(this);  //Message prompt box

    msgBox.setWindowIcon(QIcon("image/Tips.png"));
    msgBox.setWindowTitle("Tip");
    msgBox.setStyleSheet("QMessageBox QLabel{min-width: 400px;"
                         " min-height: 100px;font:16pt; font-family:'Regular script';}");

    msgBox.setText("Boot successful");
    msgBox.exec();
    this->close();  //The boot is successful, and the current window is closed
}

4, Main function test

The test results are at the beginning of the article.

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

    WelcomeWin w;
    
    w.show();

    return a.exec();
}

Original is not easy, please indicate the source for reprint.

Topics: C++ Qt