答案 0 :(得分:3)
要执行此任务,我们必须制作半透明背景,我们通过激活属性Qt::WA_TranslucentBackground
来实现,然后我们使用QPainterPath绘制矩形减去透明圆圈。
然后使用eventFilter来了解一些事件,例如当它们被显示时,如果你改变大小或位置。
然后创建一个结构来存储数据,在这种情况下是圆的中心,半径,文本的位置和文本本身。
然后添加next和return按钮,并在插槽中处理页面更改的逻辑。
<强> tutowidget.h 强>
#ifndef TUTOWIDGET_H
#define TUTOWIDGET_H
#include <QWidget>
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> pages;
int currentIndex = -1;
};
#endif // TUTOWIDGET_H
<强> tutowidget.cpp 强>
#include "tutowidget.h"
#include <QVBoxLayout>
#include <QButtonGroup>
#include <QPushButton>
#include <QEvent>
#include <QTimer>
#include <QPainter>
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<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked),
this, static_cast<void (TutoWidget::*)(int)>(&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));
}
示例:
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");
中
答案 1 :(得分:2)
开箱即用没有任何帮助。
您可以拥有一个通常隐藏的叠加窗口小部件,仅在“教程”模式下显示。您可以使用QPainterPath
轻松打孔,首先添加整个小部件的矩形,然后在想要打孔的位置添加一个圆,然后填充生成的路径。
您可以通过映射到教程覆盖小部件来获取gui元素的绝对位置。
我建议您实现一个抽象的Tutorial
类,或者至少为您希望拥有教程的每个小部件实现的指针/文本对的基本列表,然后在教程中注册该小部件的每个元素 - 指针到gui元素和教程文本。然后,当调用该窗口小部件的教程时,叠加窗口小部件变得可见,并允许迭代窗口小部件的特定元素,这些元素具有与之关联的信息,并在迭代时重绘以显示圆和文本。