create tutorial mode

后端 未结 2 550
逝去的感伤
逝去的感伤 2021-01-17 02:46

I have a Qt application and want to show a little tutorial when the user access the application for the first time. Something like this:

Ho

2条回答
  •  天涯浪人
    2021-01-17 03:10

    To perform this task we must make the translucent background, we do it by activating the attribute Qt::WA_TranslucentBackground, then we use QPainterPath to draw the rectangle minus the transparent circle.

    Then use eventFilter to know some events like when they are displayed, if you change the size or position.

    Then a structure is created to store the data, in this case the center of the circle, the radius, the position of the text and the text itself.

    Then the next and return buttons are added, and the logic of the page change is handled in the slot.

    tutowidget.h

    #ifndef TUTOWIDGET_H
    #define TUTOWIDGET_H
    
    #include 
    class QButtonGroup;
    
    class TutoWidget : public QWidget
    {
        Q_OBJECT
        struct Pages{
            QPoint center;
            int radius;
            QPoint  pText;
            QString text;
        };
    public:
        TutoWidget(QWidget *parent);
        void addPage(const QPoint ¢er, int radius, const QPoint &pText, const QString & text);
        bool eventFilter(QObject *watched, QEvent *event);
    protected:
        void paintEvent(QPaintEvent *);
    private slots:
        void onClicked(int id);
    private:
        QWidget *mParent;
        QButtonGroup *group;
        QVector pages;
        int currentIndex = -1;
    };
    
    #endif // TUTOWIDGET_H
    

    tutowidget.cpp

    #include "tutowidget.h"
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    TutoWidget::TutoWidget(QWidget *parent):QWidget(0)
    {
        setWindowFlags(Qt::FramelessWindowHint|Qt::Popup);
        setAttribute(Qt::WA_TranslucentBackground, true);
        mParent = parent;
        mParent->installEventFilter(this);
    
        QVBoxLayout *vlay = new QVBoxLayout(this);
        vlay->addItem(new QSpacerItem(20, 243, QSizePolicy::Minimum, QSizePolicy::Expanding));
        QHBoxLayout *hlay = new QHBoxLayout;
        vlay->addLayout(hlay);
        group = new QButtonGroup(this);
        const QStringList nameBtns{"Return", "Next"};
        for(int i=0; i < nameBtns.length(); i++){
            QPushButton* btn = new QPushButton(nameBtns[i]);
            btn->setFlat(true);
            group->addButton(btn, i);
            hlay->addWidget(btn);
        }
        connect(group, static_cast(&QButtonGroup::buttonClicked),
                this, static_cast(&TutoWidget::onClicked));
        hlay->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
        group->button(0)->hide();
    }
    
    void TutoWidget::addPage(const QPoint ¢er, int radius, const QPoint &pText, const QString &text)
    {
        pages << Pages{center, radius, pText, text};
        if(currentIndex == -1){
            currentIndex = 0;
            update();
        }
    }
    
    bool TutoWidget::eventFilter(QObject *watched, QEvent *event){
        if(watched == mParent){
    
            switch (event->type()) {
            case QEvent::Show:
                QTimer::singleShot(10,  this, &QWidget::show);
                break;
            case QEvent::Close:
                close();
                break;
            case QEvent::Move:
                move(mParent->mapToGlobal(QPoint(0, 0)));
                break;
            case QEvent::Resize:
                resize(mParent->size());
                break;
            default:
                break;
            }
        }
        return QWidget::eventFilter(watched, event);
    }
    
    void TutoWidget::paintEvent(QPaintEvent *){
        QPainter painter(this);
        painter.setPen(Qt::NoPen);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setBrush(QColor(100, 100, 100, 200));
        QPainterPath path;
        if(currentIndex != -1){
            QPoint center = pages[currentIndex].center;
            int radius = pages[currentIndex].radius;
            QString text = pages[currentIndex].text;
            QPoint pText = pages[currentIndex].pText;
            path.moveTo(center + radius/2*QPoint(1, 0));
            path.arcTo(QRect(center-radius/2*QPoint(1, 1),radius*QSize(1, 1)), 0, 360);
            path.addText(pText, font(), text);
        }
        path.addRect(rect());
        painter.drawPath(path);
    }
    
    void TutoWidget::onClicked(int id)
    {
        if(id == 0){
            if(currentIndex > 0)
                currentIndex--;
        }
        else if(id == 1){
            if(currentIndex < pages.count()-1)
                currentIndex++;
        }
        update();
        group->button(0)->setVisible(currentIndex!=0);
        group->button(1)->setVisible(currentIndex!=(pages.count()-1));
    }
    

    Example:

    tuto = new TutoWidget(this); // this is the widget
    tuto->addPage(QPoint(200, 200), 40, QPoint(100, 100), "some text1");
    tuto->addPage(QPoint(300, 300), 60, QPoint(200, 100), "some text2");
    tuto->addPage(QPoint(100, 200), 100, QPoint(200, 50), "some text3");
    tuto->addPage(QPoint(200, 100), 80, QPoint(100, 200), "some text4");
    

    The complete example is in the following link

提交回复
热议问题