天天看點

QT5.14.2 官方例子 - Qt Widgets 9: painting\affine(仿射)

系列總連結:

QT5.14.2 官方例子 - 學習系列

https://blog.csdn.net/qq_22122811/article/details/108007519

項目位置:

Examples\Qt-5.14.2\widgets\painting\affine

注:在Examples下的路徑

項目子產品:widgets\painting

項目描述:

示範了QPainter中仿射變換的工作原理。(圖檔,文字進行大小,旋轉)

項目效果:

QT5.14.2 官方例子 - Qt Widgets 9: painting\affine(仿射)

官網講解:

Affine Transformations | Qt Widgets 5.14.2

https://doc.qt.io/qt-5.14/qtwidgets-painting-affine-example.html

可以在使用QPainter繪制的任何類型的圖形上執行轉換。用于顯示矢量圖形、圖像和文本的轉換可以通過以下方式進行調整:

拖動每幅畫中心的紅色圓,将其移動到一個新的位置。

拖動移位的紅色圓将導緻目前繪圖圍繞中心圓旋轉。旋轉也可以通過旋轉滑塊控制。

縮放由縮放滑塊控制。

每條圖紙都可以用剪切滑塊進行剪切。

思路解析:

1.布局:

QT5.14.2 官方例子 - Qt Widgets 9: painting\affine(仿射)

左邊為:XFormView,其繼承于ArthurFrame,ArthurFrame繼承于QWidget

右邊為:QGroupBox對象;

QHBoxLayout *viewLayout = new QHBoxLayout(this);
    viewLayout->addWidget(view);
    viewLayout->addWidget(mainGroup);
           

邏輯了解:

1.初始化顯示的狀态,左邊展示圖檔,矢量圖,文字等的變化,右邊為具體設定項

XFormWidget::XFormWidget(QWidget *parent)
    : QWidget(parent), textEditor(new QLineEdit)
{
    setWindowTitle(tr("Affine Transformations"));

    // 建立左側XFormView視圖對象
    view = new XFormView(this);
    view->setMinimumSize(200, 200);

    // 建立右側Affine Transformations, Type, Others btn的布局
    QGroupBox *mainGroup = new QGroupBox(this);
    mainGroup->setFixedWidth(180);
    mainGroup->setTitle(tr("Affine Transformations"));

    QGroupBox *rotateGroup = new QGroupBox(mainGroup);
    rotateGroup->setTitle(tr("Rotate"));
    QSlider *rotateSlider = new QSlider(Qt::Horizontal, rotateGroup);
    rotateSlider->setRange(0, 3600);
    rotateSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);

    QGroupBox *scaleGroup = new QGroupBox(mainGroup);
    scaleGroup->setTitle(tr("Scale"));
    QSlider *scaleSlider = new QSlider(Qt::Horizontal, scaleGroup);
    scaleSlider->setRange(1, 4000);
    scaleSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);

    QGroupBox *shearGroup = new QGroupBox(mainGroup);
    shearGroup->setTitle(tr("Shear"));
    QSlider *shearSlider = new QSlider(Qt::Horizontal, shearGroup);
    shearSlider->setRange(-990, 990);
    shearSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);

    QGroupBox *typeGroup = new QGroupBox(mainGroup);
    typeGroup->setTitle(tr("Type"));
    QRadioButton *vectorType = new QRadioButton(typeGroup);
    QRadioButton *pixmapType = new QRadioButton(typeGroup);
    QRadioButton *textType= new QRadioButton(typeGroup);
    vectorType->setText(tr("Vector Image"));
    pixmapType->setText(tr("Pixmap"));
    textType->setText(tr("Text"));

    QPushButton *resetButton = new QPushButton(mainGroup);
    resetButton->setText(tr("Reset Transform"));

    QPushButton *animateButton = new QPushButton(mainGroup);
    animateButton->setText(tr("Animate"));
    animateButton->setCheckable(true);

    QPushButton *showSourceButton = new QPushButton(mainGroup);
    showSourceButton->setText(tr("Show Source"));
#if QT_CONFIG(opengl)
    QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
    enableOpenGLButton->setText(tr("Use OpenGL"));
    enableOpenGLButton->setCheckable(true);
    enableOpenGLButton->setChecked(view->usesOpenGL());
#endif
    QPushButton *whatsThisButton = new QPushButton(mainGroup);
    whatsThisButton->setText(tr("What's This?"));
    whatsThisButton->setCheckable(true);

    QHBoxLayout *viewLayout = new QHBoxLayout(this);
    viewLayout->addWidget(view);
    viewLayout->addWidget(mainGroup);

    QVBoxLayout *rotateGroupLayout = new QVBoxLayout(rotateGroup);
    rotateGroupLayout->addWidget(rotateSlider);

    QVBoxLayout *scaleGroupLayout = new QVBoxLayout(scaleGroup);
    scaleGroupLayout->addWidget(scaleSlider);

    QVBoxLayout *shearGroupLayout = new QVBoxLayout(shearGroup);
    shearGroupLayout->addWidget(shearSlider);

    QVBoxLayout *typeGroupLayout = new QVBoxLayout(typeGroup);
    typeGroupLayout->addWidget(vectorType);
    typeGroupLayout->addWidget(pixmapType);
    typeGroupLayout->addWidget(textType);
    typeGroupLayout->addSpacing(4);
    typeGroupLayout->addWidget(textEditor);

    QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
    mainGroupLayout->addWidget(rotateGroup);
    mainGroupLayout->addWidget(scaleGroup);
    mainGroupLayout->addWidget(shearGroup);
    mainGroupLayout->addWidget(typeGroup);
    mainGroupLayout->addStretch(1);
    mainGroupLayout->addWidget(resetButton);
    mainGroupLayout->addWidget(animateButton);
    mainGroupLayout->addWidget(showSourceButton);
#if QT_CONFIG(opengl)
    mainGroupLayout->addWidget(enableOpenGLButton);
#endif
    mainGroupLayout->addWidget(whatsThisButton);

    connect(rotateSlider, &QSlider::valueChanged, view, &XFormView::changeRotation);
    connect(shearSlider, &QSlider::valueChanged, view, &XFormView::changeShear);
    connect(scaleSlider, &QSlider::valueChanged, view, &XFormView::changeScale);

    connect(vectorType, &QRadioButton::clicked, view, &XFormView::setVectorType);
    connect(pixmapType, &QRadioButton::clicked, view, &XFormView::setPixmapType);
    connect(textType, &QRadioButton::clicked, view, &XFormView::setTextType);
    connect(textType, &QRadioButton::toggled, textEditor, &XFormView::setEnabled);
    connect(textEditor, &QLineEdit::textChanged, view, &XFormView::setText);

    // 如果左邊視圖釋放"旋轉,大小,斷裂"改變的信号,則對應的滑塊得跟着變更比對的值
    // 加&是表示傳遞的是信号(槽)的位址
    connect(view, &XFormView::rotationChanged, rotateSlider, &QSlider::setValue);
    connect(view, &XFormView::scaleChanged, scaleSlider, &QAbstractSlider::setValue);
    connect(view, &XFormView::shearChanged, shearSlider, &QAbstractSlider::setValue);

    connect(resetButton, &QPushButton::clicked, view, &XFormView::reset);
    connect(animateButton, &QPushButton::clicked, view, &XFormView::setAnimation);
    // 如果點選"what's this",則view描述使能打開,支援文本說明
    connect(whatsThisButton, &QPushButton::clicked, view, &ArthurFrame::setDescriptionEnabled);

    // 矢量點不是目前類區域定義的對象,需要通過view->hoverPoints(),以成員(view)的成員(view->hoverPoints())的形式聯系起來
    // 如果點選"what's this",則令萦繞點向量不顯示(setDiabled),因為太醜了。。。
    connect(whatsThisButton, &QPushButton::clicked, view->hoverPoints(), &HoverPoints::setDisabled);
    // view使能描述改變,比對改變萦繞點向量顯示更改
    connect(view, &XFormView::descriptionEnabledChanged, view->hoverPoints(), &HoverPoints::setDisabled);
    // view使能描述改變,比對改變"what's this"狀态更改
    connect(view, &XFormView::descriptionEnabledChanged, whatsThisButton, &QPushButton::setChecked);
    connect(showSourceButton, &QPushButton::clicked, view, &XFormView::showSource);
#if QT_CONFIG(opengl)
    connect(enableOpenGLButton, &QPushButton::clicked, view, &XFormView::enableOpenGL);
#endif

    // view加載需要顯示的源檔案
    view->loadSourceFile(":res/affine/xform.cpp");
    // view加載需要顯示的網頁
    view->loadDescription(":res/affine/xform.html");

    // defaults
    view->reset();
    vectorType->setChecked(true);
    textEditor->setText("Qt Affine Transformation Example");
    textEditor->setEnabled(false);

    // animateClick和click的差別:
    // 執行動畫點選:立即按下按鈕,并在毫秒之後釋放(預設是100毫秒)。
    // 在釋放按鈕之前再次調用此函數将重置釋放計時器。
    // 與單擊關聯的所有信号都會相應地發出。
    animateButton->animateClick();
}
           

最後由animateButton執行槽函數animateClick(),左側視圖開啟動态展示,右側滑塊動态滑動,等等;

2.點選: 下面的三個slider(滑塊),分别實作圖檔的旋轉,縮放,拉拽:

QT5.14.2 官方例子 - Qt Widgets 9: painting\affine(仿射)

代碼:XFormWidget類中:

changeRotation:更改旋轉

changeShear:更改斷裂

changeScale:更改大小,比例

connect(rotateSlider, &QSlider::valueChanged, view, &XFormView::changeRotation);
    connect(shearSlider, &QSlider::valueChanged, view, &XFormView::changeShear);
    connect(scaleSlider, &QSlider::valueChanged, view, &XFormView::changeScale);
           

=》

slider滑動,XFormView類中,執行相應槽 :

void XFormView::changeRotation(int r)
{
    setRotation(qreal(r) / 10);
}

void XFormView::changeScale(int s)
{
    setScale(qreal(s) / 1000);
}

void XFormView::changeShear(int s)
{
    setShear(qreal(s) / 1000);
}
           

=》

void XFormView::setShear(qreal s)
{
    m_shear = s;
    update();
}

void XFormView::setScale(qreal s)
{
    m_scale = s;
    update();
}

void XFormView::setRotation(qreal r)
{
    qreal old_rot = m_rotation;
    m_rotation = r;

    QPointF center(pts->points().at(0));
    QMatrix m;
    m.translate(center.x(), center.y());
    m.rotate(m_rotation - old_rot);
    m.translate(-center.x(), -center.y());
    pts->setPoints(pts->points() * m);

    update();
}
           
void XFormView::paint(QPainter *p)
{
    // 儲存目前繪畫家指針入堆(stack)
    p->save();
    //p->setRenderHint(QPainter::Antialiasing);
    // 表示引擎應該使用平滑的像素圖轉換算法(如雙線性)而不是最近鄰算法。
    //p->setRenderHint(QPainter::SmoothPixmapTransform);

    // 根據目前類型繪畫圖形,文本
    switch (m_type) {
    case VectorType:
        drawVectorType(p);
        break;
    case PixmapType:
        drawPixmapType(p);
        break;
    case TextType:
        drawTextType(p);
        break;
    }

    // 使繪畫家指針出堆(stack)
    p->restore();
}
           

=》

drawVectorType(QPainter* painter): 繪制向量類型圖

drawTextType(QPainter *painter): 繪制文本類型

drawPixmapType(QPainter *painter): 繪制圖檔

對上述繪制過程的詳細分析,暫時不進以深入,等後續有需要再進行深入。。。

函數積累:

1.QList<T> QObject::findChildren(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const

介紹:傳回具有給定名稱的此對象的所有可轉換為T類型的子對象,或者如果沒有這樣的對象,傳回一個空清單。。。。

XFormWidget xformWidget(nullptr);
    QStyle *arthurStyle = new ArthurStyle;
    xformWidget.setStyle(arthurStyle);
    
    // 擷取xformWidget的子控件清單
    const QList<QWidget *> widgets = xformWidget.findChildren<QWidget *>();
    for (QWidget *w : widgets) 
    {
        // 設定每個子控件的風格
        w->setStyle(arthurStyle);
        // 設定接受觸摸事件
        w->setAttribute(Qt::WA_AcceptTouchEvents);
    }
           

類積累:

1.QStyle

QStyle類是一個抽象基類,它封裝了GUI的外觀和感覺

具體使用可參考:

https://blog.csdn.net/wangyanphp/article/details/38532801

三種方法來重新定義Qt内置視窗部件的外觀:

1)子類化QStyle或者一個預定義的風格,這種方法很好用,Qt本身就是用這種方法為它所支援的不同平台提供基于平台的外觀的

2)子類化個别的視窗部件類,并且重新實作它的繪制和滑鼠事件處理器。

3)Qt 樣式表

2.QGroupbox

QGroupBox為建構分組框提供了支援。分組框通常帶有一個邊框和一個标題欄,作為容器部件來使用,在其中可以布置各種視窗部件。布局時可用作一組控件的容器,但是需要注意的是,内部必須使用布局控件(如QBoxLayout)進行布局。

QGroupBox繼承關系:

QT5.14.2 官方例子 - Qt Widgets 9: painting\affine(仿射)
QT5.14.2 官方例子 - Qt Widgets 9: painting\affine(仿射)

其他積累:

Q_PROPERTY:Qt自有的屬性結構,

Qt中類的屬性是給腳本和元對象系統用的,比如QtScript,QML,或者QObject::property/setProperty……,主要就是用來進行屬性封裝,在具體的腳本,庫,qml開發中必須使用。

具體可檢視:http://note.youdao.com/noteshare?id=10ee53b525aa40f8f52290cf819b798e&sub=834CE6B6B0464B6FBC547426ACBECB20

舉一反三:

借鑒思路:

1.對圖檔大小的處理;

2.對圖檔旋轉的思路;

3.對圖檔進行拉拽的思路;

4.圖檔動畫效果;