系列總連結:
QT5.14.2 官方例子 - 學習系列
https://blog.csdn.net/qq_22122811/article/details/108007519
項目位置:
Examples\Qt-5.14.2\widgets\painting\affine
注:在Examples下的路徑
項目子產品:widgets\painting
項目描述:
示範了QPainter中仿射變換的工作原理。(圖檔,文字進行大小,旋轉)
項目效果:

官網講解:
Affine Transformations | Qt Widgets 5.14.2
https://doc.qt.io/qt-5.14/qtwidgets-painting-affine-example.html
可以在使用QPainter繪制的任何類型的圖形上執行轉換。用于顯示矢量圖形、圖像和文本的轉換可以通過以下方式進行調整:
拖動每幅畫中心的紅色圓,将其移動到一個新的位置。
拖動移位的紅色圓将導緻目前繪圖圍繞中心圓旋轉。旋轉也可以通過旋轉滑塊控制。
縮放由縮放滑塊控制。
每條圖紙都可以用剪切滑塊進行剪切。
思路解析:
1.布局:
左邊為: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(滑塊),分别實作圖檔的旋轉,縮放,拉拽:
代碼: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繼承關系:
其他積累:
Q_PROPERTY:Qt自有的屬性結構,
Qt中類的屬性是給腳本和元對象系統用的,比如QtScript,QML,或者QObject::property/setProperty……,主要就是用來進行屬性封裝,在具體的腳本,庫,qml開發中必須使用。
具體可檢視:http://note.youdao.com/noteshare?id=10ee53b525aa40f8f52290cf819b798e&sub=834CE6B6B0464B6FBC547426ACBECB20
舉一反三:
無
借鑒思路:
1.對圖檔大小的處理;
2.對圖檔旋轉的思路;
3.對圖檔進行拉拽的思路;
4.圖檔動畫效果;