调整和旋转 QGraphicsItem 会导致形状奇怪 [英] Resizing and rotating a QGraphicsItem results in odd shape
问题描述
我无法理解如何将缩放和旋转应用于 QGraphicsItem
.
我需要能够应用旋转和缩放(不一定保持纵横比)并且我得到了完全出乎意料的结果.
旋转必须围绕项目中心.我这样做似乎没有问题 - 但是如果我尝试调试边界矩形,我会得到看似错误的值.
如果我不保持纵横比,而不是旋转,我会得到一个非常奇怪的歪斜,我一直在努力寻找原因并纠正它.我希望任何人都可以找到解决方案.
对于许多项目 - 如矩形 - 我的解决方案是放弃调整大小 - 只需用给定大小的新项目替换该项目.
调整大小的(黑色)文本应该与参考(红色)具有相同的高度 - 但要高得多;
边界矩形不再是矩形 - 它是倾斜的;
角度看起来比45小很多;
还添加了调整大小但未旋转的参考:
请帮助我理解为什么会发生这种行为以及我能做些什么.
我曾尝试研究 QGraphicsRotation
,但我不知道如何应用它......我得到的只是移动而不是旋转.
如文档所述,项目的变换以特定顺序在数学上应用 - 这是您将变换矩阵相乘的顺序,并且从概念上讲,与您通常想到的顺序相反.
- 应用了
transform
.通过在转换期间应用翻译,原点必须包含在转换本身中. - 应用
转换
- 每个转换都可以指定自己的中心. rotation
然后scale
被应用,两者都相对于transformOriginPoint
.
当您将transform
设置为缩放,并设置rotation
时,在缩放之前执行旋转.缩放适用于旋转结果 - 它只是在您的情况下水平拉伸旋转版本.
您需要以某种方式强制执行相反的操作顺序.唯一的两种方法是:
以正确的顺序堆叠转换并将它们传递给
transform
,或者.将正确转换的列表传递给
transformations
.
我将演示如何以交互方式执行此操作,您可以使用滑块调整变换参数.
使用transform
获得正确的结果:
QGraphicsItem * item = ....;Q变换t;QPointF xlate = item->boundingRect().center();t.translate(xlate.x(), xlate.y());t.旋转(角度);t.scale(xScale, yScale);t.translate(-xlate.x(), -xlate.y());项目-> setTransform(t);
使用transformations
获得正确的结果:
QGraphicsItem * item = ....;QGraphicsRotation 腐烂;QGraphicsScale 比例尺;自动居中 = item->boundingRect().center();rot.setOrigin(QVector3D(center));scale.setOrigin(QVector3D(center()));item->setTransformations(QList<QGraphicsTransform*>() << &rot << &scale);
最后,例子:
//https://github.com/KubaO/stackoverflown/tree/master/questions/graphics-transform-32186798#include 结构控制器{上市:QSlider 角度、xScale、yScale;控制器(QGridLayout 和网格,int col){角度.setRange(-180, 180);xScale.setRange(1, 10);yScale.setRange(1, 10);grid.addWidget(&angle, 0, col + 0);grid.addWidget(&xScale, 0, col + 1);grid.addWidget(&yScale, 0, col + 2);}模板 void connect(F && f) { connect(f, f, std::forward(f));}template 无效连接(Fa&& a,Fx&& x,Fy&& y){QObject::connect(&angle, &QSlider::valueChanged, std::forward(a));QObject::connect(&xScale, &QSlider::valueChanged, std::forward(x));QObject::connect(&yScale, &QSlider::valueChanged, std::forward(y));}QTransform xform(QPointF xlate) {Q变换t;t.translate(xlate.x(), xlate.y());t.rotate(angle.value());t.scale(xScale.value(), yScale.value());t.translate(-xlate.x(), -xlate.y());返回 t;}};int main(int argc, char **argv){auto text = QStringLiteral("Hello, World!");QApplication app(argc, argv);QGraphicsScene场景;QWidget w;QGridLayout布局(&w);QGraphicsView 视图(&scene);控制器左(布局,0),右(布局,4);layout.addWidget(&view, 0, 3);auto ref = new QGraphicsTextItem(text);//一个引用,未调整大小ref->setDefaultTextColor(Qt::red);ref->setTransformOriginPoint(ref->boundingRect().center());ref->setRotation(45);场景.addItem(ref);auto leftItem = new QGraphicsTextItem(text);//从左边控制leftItem->setDefaultTextColor(Qt::green);场景.addItem(leftItem);auto rightItem = new QGraphicsTextItem(text);//从右侧控制rightItem->setDefaultTextColor(Qt::blue);场景.addItem(rightItem);QGraphicsRotation 腐烂;QGraphicsScale 比例尺;rightItem->setTransformations(QList<QGraphicsTransform*>() << &rot << &scale);rot.setOrigin(QVector3D(rightItem->boundingRect().center()));scale.setOrigin(QVector3D(rightItem->boundingRect().center()));left.connect([leftItem, &left]{ leftItem->setTransform(left.xform(leftItem->boundingRect().center()));});right.connect([&rot](int a){ rot.setAngle(a); },[&scale](int s){ scale.setXScale(s);}, [&scale](int s){ scale.setYScale(s);});right.angle.setValue(45);right.xScale.setValue(3);right.yScale.setValue(1);view.ensureVisible(scene.sceneRect());w.show();返回 app.exec();}
I can't understand how scaling and rotation are applied to QGraphicsItem
.
I need to be able to apply rotation and scaling (not necessarily keeping aspect ratio) and I get fully unexpected results.
Rotation must be around the item center. I seem to have no problem doing that - yet if I try to debug the bounding rectangle, I get seemingly wrong values.
If I don't keep aspect ratio, instead of rotation I get a very weird skew, and I have been struggling for quite a while to find the cause and correct it. I hope anybody can find a solution.
For many items - like rectangles - my solution was to give up on resize - and just replace the item with a new one of given size. I even did that for pixmap (though it probably will affect performance a lot).
But I don't know how to do that for text, or a few other types (svg...).
I am trying to understand how scaling is applied, on rotated items, and how to get it applied correctly.
The code below is an experiment where I scale and rotate a text item, and the result... see attached image
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsTextItem>
void experimentScaling(QGraphicsScene* s)
{
QGraphicsTextItem* ref = new QGraphicsTextItem(); // a reference, not resized
ref->setPlainText("hello world");
s->addItem(ref);
ref->setDefaultTextColor(Qt::red);
ref->setRotation(45);
QGraphicsTextItem* t = new QGraphicsTextItem(); // text item to be experimented on
t->setPlainText("hello world");
s->addItem(t);
QTransform transform; // scale
transform.scale(10, 1);
t->setTransform(transform);
t->update();
QPointF _center = t->boundingRect().center();
qDebug("%f %f %f %f", t->boundingRect().left(), t->boundingRect().top(), t->boundingRect().right(), t->boundingRect().bottom()); // seems to be unscaled...
t->setTransformOriginPoint(_center); // rotation must be around item center - and seems to work even though the bounding rect gives wrong values above
t->setRotation(45); // skewed
t->update();
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene s;
QGraphicsView view(&s);
s.setSceneRect(-20, -20, 800, 600);
view.show();
experimentScaling(&s);
return app.exec();
}
Reference (red) text rotated 45 degrees, text rotated 45 degrees and resized 10,1:
The resized (black) text should have the same height as the reference (red) - yet is much taller;
The bounding rectangle is no longer a rectangle - it is skewed;
The angle looks much smaller than 45;
Added a resized but not rotated reference as well:
Please help me understand why this behavior is happening and what can I do about it.
I have tried looking into QGraphicsRotation
but I can't figure out how to apply it... All I get is a move instead of rotation.
As documented, the item's transformations are mathematically applied in a certain order - this is the order you'd be multiplying the transform matrices in and is, conceptually, the reverse of the order you'd normally think of.
- The
transform
is applied. The origin point must be included in the transform itself, by applying translations during the transform. - The
transformations
are applied - each of them can specify its own center. rotation
thenscale
are applied, both relative totransformOriginPoint
.
When you set transform
to scaling, and set rotation
, the rotation is performed before scaling. The scaling applies to the rotated result - it simply stretches the rotated version horizontally in your case.
You need to somehow enforce the reverse order of operations. The only two ways to do that are:
Stack the transforms in correct order and pass them to
transform
, or.Pass a list of correct transformations to
transformations
.
I'll demonstrate how to do it either way, in an interactive fashion where you can adjust the transform parameters using sliders.
To obtain the correct result using transform
:
QGraphicsItem * item = ....;
QTransform t;
QPointF xlate = item->boundingRect().center();
t.translate(xlate.x(), xlate.y());
t.rotate(angle);
t.scale(xScale, yScale);
t.translate(-xlate.x(), -xlate.y());
item->setTransform(t);
To obtain the correct result using transformations
:
QGraphicsItem * item = ....;
QGraphicsRotation rot;
QGraphicsScale scale;
auto center = item->boundingRect().center();
rot.setOrigin(QVector3D(center));
scale.setOrigin(QVector3D(center()));
item->setTransformations(QList<QGraphicsTransform*>() << &rot << &scale);
Finally, the example:
// https://github.com/KubaO/stackoverflown/tree/master/questions/graphics-transform-32186798
#include <QtWidgets>
struct Controller {
public:
QSlider angle, xScale, yScale;
Controller(QGridLayout & grid, int col) {
angle.setRange(-180, 180);
xScale.setRange(1, 10);
yScale.setRange(1, 10);
grid.addWidget(&angle, 0, col + 0);
grid.addWidget(&xScale, 0, col + 1);
grid.addWidget(&yScale, 0, col + 2);
}
template <typename F> void connect(F && f) { connect(f, f, std::forward<F>(f)); }
template <typename Fa, typename Fx, typename Fy> void connect(Fa && a, Fx && x, Fy && y) {
QObject::connect(&angle, &QSlider::valueChanged, std::forward<Fa>(a));
QObject::connect(&xScale, &QSlider::valueChanged, std::forward<Fx>(x));
QObject::connect(&yScale, &QSlider::valueChanged, std::forward<Fy>(y));
}
QTransform xform(QPointF xlate) {
QTransform t;
t.translate(xlate.x(), xlate.y());
t.rotate(angle.value());
t.scale(xScale.value(), yScale.value());
t.translate(-xlate.x(), -xlate.y());
return t;
}
};
int main(int argc, char **argv)
{
auto text = QStringLiteral("Hello, World!");
QApplication app(argc, argv);
QGraphicsScene scene;
QWidget w;
QGridLayout layout(&w);
QGraphicsView view(&scene);
Controller left(layout, 0), right(layout, 4);
layout.addWidget(&view, 0, 3);
auto ref = new QGraphicsTextItem(text); // a reference, not resized
ref->setDefaultTextColor(Qt::red);
ref->setTransformOriginPoint(ref->boundingRect().center());
ref->setRotation(45);
scene.addItem(ref);
auto leftItem = new QGraphicsTextItem(text); // controlled from the left
leftItem->setDefaultTextColor(Qt::green);
scene.addItem(leftItem);
auto rightItem = new QGraphicsTextItem(text); // controlled from the right
rightItem->setDefaultTextColor(Qt::blue);
scene.addItem(rightItem);
QGraphicsRotation rot;
QGraphicsScale scale;
rightItem->setTransformations(QList<QGraphicsTransform*>() << &rot << &scale);
rot.setOrigin(QVector3D(rightItem->boundingRect().center()));
scale.setOrigin(QVector3D(rightItem->boundingRect().center()));
left.connect([leftItem, &left]{ leftItem->setTransform(left.xform(leftItem->boundingRect().center()));});
right.connect([&rot](int a){ rot.setAngle(a); },
[&scale](int s){ scale.setXScale(s); }, [&scale](int s){ scale.setYScale(s); });
right.angle.setValue(45);
right.xScale.setValue(3);
right.yScale.setValue(1);
view.ensureVisible(scene.sceneRect());
w.show();
return app.exec();
}
这篇关于调整和旋转 QGraphicsItem 会导致形状奇怪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!