Qt

2017-12-05 24 views
0

のアプリチュートリアルを表示Qtアプリケーションがあり、初めてユーザーがアプリケーションにアクセスしたときに少しチュートリアルを表示します。このような何か:Qt

enter image description here

どのように私はQtの上でこのような何かを行うことができますか?

私はWindowsでQt 5.4を使用しています。

+0

でありますそのレイアウトを手動で設定して、その領域の高さと幅を設定します)。半透明のイメージをラベルに置きます。ラベルには、必要なものが表示されます。イメージをコードで描画することも、別々に描画してディスク/リソースからロードすることもできます。または、QLabelの代わりに、必要に応じて半透明に描画するpaintEventでカスタムQWidgetを使用します。 – hyde

+0

画面をグレーアウトしたい場合は、[半透過ポップアップ](https://doc.qt.io/qt-5/qml-qtquick-controls2-popup.html)を使用できます。あなたはそのサークルを完全に透明にする方法を必ずしも明確にしていません。しかし、ハイデが言っていたように、ボタンの上に赤い円またはアニメーションの目を引くテキストを描くこともできます。 –

+0

ReturnとNextはボタンですか? – eyllanesc

答えて

3

このタスクを実行するには、半透明の背景を作成し、属性Qt::WA_TranslucentBackgroundをアクティブにしてから、それからQPainterPathを使用して透明円を引いた長方形を描画します。

次に、サイズや位置を変更すると、eventFilterを使用して、表示されたときのようなイベントを知ることができます。

次に、データ(この場合は円の中心、半径、テキストの位置およびテキスト自体)を格納する構造体が作成されます。

次に、次のボタンと戻りボタンが追加され、ページの変更のロジックがスロットで処理されます。

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 &center, 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 &center, 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"); 

enter image description here

enter image description here

完全な例では、それは全体のウィジェットを埋め、上になるように、中央のウィジェットの子としてQLabelを追加します(あなたはおそらくそれを置くことをしたくない、次のlink

+0

レイアウトのGUI要素として点を追加すると、位置が変更される可能性があります。私が示唆したアプローチを使用して、要素ポインタを追加し、実際の要素位置を見つけるために座標をマッピングする方がよい。 「戻り値」はおそらく前のページに行くのではなく、チュートリアルを終了するために役立つので、最初のページにも表示する必要があります。最後に、完全な実装では、円のxy位置とウィンドウのサイズに応じて、より論理的な方法でテキストの位置を決定する必要があります。 – dtech

+0

@dtech私はあなたのポイントを理解しています。私の意図はトータルソリューションを提供することではなく、それを行う方法のサンプルをいくつか与えました。私がすでに考えていたポイントですが、後で修正するためでした。質問は出発点を持っています:P – eyllanesc

+0

そして、私のポイントは、コードと努力の量で、あなたは完全な解決策に向かうかもしれません;) – dtech

2

これを実行するのに役立つものは何もありません。

通常は非表示になり、「チュートリアル」モードでのみ表示されるオーバーレイウィジェットを使用できます。 QPainterPathを使用して簡単に穴を開けることができます。まず、ウィジェット全体の矩形を追加してから、穴を描く場所に円を追加して、その結果のパスを塗りつぶします。

gui要素の絶対位置を取得するには、チュートリアルオーバーレイウィジェットにマッピングします。

私は、あなたがチュートリアルをしたいそれぞれのウィジェットに実装するポインタ/テキストペアの抽象的なリストまたは少なくとも基本的なリストを実装し、そのウィジェットの各要素をチュートリアルに登録することをお勧めします要素とチュートリアルのテキストです。その後、そのウィジェットのチュートリアルが呼び出されると、オーバーレイウィジェットが表示され、関連付けられた情報を持つウィジェットの特定の要素を反復することができ、反復で再描画して円とテキストを表示できます。