系列总链接:
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.图片动画效果;