我父到的QGraphicsItem一个QGraphicsTextItem。 我想QGraphicsTextItem总是直接驻留在的QGraphicsItem以上,但我也希望文本保持相同的大小时,比例因子低于1,即文本保持它在1的比例因子的大小,即使父图形项目规模较小。 我发现,在设定QGraphicsItem::ItemIgnoresTransformations
标志为真时,比例因子小于1不保留大小的伎俩。
但我似乎无法找到一个方法来获取文本的位置始终保持的QGraphicsItem以上。 有没有办法做到这一点? 我试着用deviceTransform ()
函数,但文本仍移出的QGraphicsItem,因为我滚出。 更糟糕的是,一些文字项启动“微动”,即他们开始不断改变自己的立场非常轻微,因此它看起来就像他们在颤抖。 如果这是我需要使用的功能,我想我不知道如何正确使用它。
在我的QGraphicsItem的构造我添加了一个QGraphicsTextItem:
fTextItem = new QGraphicsTextItem(getName(), this);
fTextItem->setFlag(QGraphicsItem::ItemIgnoresTransformations);
下面是从的QGraphicsItem的涂料功能的代码段
qreal lod = painter->worldTransform().m22();
if(lod <= 1.0) {
fTextItem-setFlag(QGraphicsItem::ItemIgnoresTransformations);
fTextItem->setPos(fTextItem->deviceTransform(view-viewportTransform()).inverted().map(view->mapFromScene(mapToScene(0,0))));
} else {
fTextItem->setFlag(QGraphicsItem::ItemIgnoresTransformations, false);
fTextItem->setPos(0, 0);
}
Answer 1:
免责声明:这可能是矫枉过正你正在尝试做的。 我们在我们的项目,使得这解决方案的最简单的给我们一些额外的限制。
我们不得不做的一个项目类似的东西,它结束了最简单的为我们不使用ItemIgnoresTransformations
,而是推出我们自己的转变。 下面是我们用它来创建一个翻译只(无缩放)转换为在特定位置绘制项主要功能。 你也许可以修改它为您的使用。
static QTransform GenerateTranslationOnlyTransform(
const QTransform &original_transform,
const QPointF &target_point) {
// To draw the unscaled icons, we desire a transform with scaling factors
// of 1 and shearing factors of 0 and the appropriate translation such that
// our icon center ends up at the same point. According to the
// documentation, QTransform transforms a point in the plane to another
// point using the following formulas:
// x' = m11*x + m21*y + dx
// y' = m22*y + m12*x + dy
//
// For our new transform, m11 and m22 (scaling) are 1, and m21 and m12
// (shearing) are 0. Since we want x' and y' to be the same, we have the
// following equations:
// m11*x + m21*y + dx = x + dx[new]
// m22*y + m12*x + dy = y + dy[new]
//
// Thus,
// dx[new] = m11*x - x + m21*y + dx
// dy[new] = m22*y - y + m12*x + dy
qreal dx = original_transform.m11() * target_point.x()
- target_point.x()
+ original_transform.m21() * target_point.y()
+ original_transform.m31();
qreal dy = original_transform.m22() * target_point.y()
- target_point.y()
+ original_transform.m12() * target_point.x()
+ original_transform.m32();
return QTransform::fromTranslate(dx, dy);
}
使用时,把QPainter
变换传递给paint方法,做一些这样的:
painter->save();
painter->setTransform(GenerateTranslationOnlyTransform(painter->transform(),
some_point));
// Draw your item.
painter->restore();
Answer 2:
我的建议是继承QGraphicsSimpleTextItem以这种方式:
class TextItem
: public QGraphicsSimpleTextItem
{
public:
TextItem(const QString &text)
: QGraphicsSimpleTextItem(text)
{
}
void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->translate(boundingRect().topLeft());
QGraphicsSimpleTextItem::paint(painter, option, widget);
painter->translate(-boundingRect().topLeft());
}
QRectF boundingRect() const
{
QRectF b = QGraphicsSimpleTextItem::boundingRect();
return QRectF(b.x()-b.width()/2.0, b.y()-b.height()/2.0,
b.width(), b.height());
}
};
QGraphicsSimpleTextItem *mText = new TextItem("Item");
scene()->addItem(mText);
mText->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
mText->setPos(itemToFollow->pos());
Answer 3:
添加到戴夫狄考文的回答,我觉得这是有益的补充,在某些情况下,你也应该保持对象的正确边界矩形(以及形状)。 对于我来说,我需要修改boundingRect()
有点太正确对象选择的行为。 请记住,对象的边框矩形将被调整和转变像往常一样,如果我们不使用ItemIgnoresTransformations
标志。 因此,我们还需要重新调整boundingRect保持独立观点的影响。
为了保持该视图无关边框原来是很容易:只要抓住从缩放因子deviceTransform(m_view->viewportTransform()).inverted().m11()
和繁殖这种不断给当地协调边框。 例如:
qreal m = this->deviceTransform(m_view->viewportTransform()).inverted().m11();
return QRectF(m*(m_shapeX), m*(m_shapeY),
m*(m_shapeR), m*(m_shapeR));
Answer 4:
大答案由Dave狄考文! 我有,我想在不同的缩放级别确定不同的比例因子的问题。 这是我做的:
void MyGraphicsItem::paint(QPainter * painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
//save painter for later operations
painter->save();
QTransform originalTransform = painter->transform();
QPointF originalCenter = rect().center();
qreal dx = originalTransform.m11() * originalCenter.x() + originalTransform.m21() * originalCenter.y() + originalTransform.m31();
qreal dy = originalTransform.m22() * originalCenter.y() + originalTransform.m12() * originalCenter.x() + originalTransform.m32();
//normally our target scale factor is 1, meaning the item has keeps its size, regardless of zoom
//we adjust the scale factor though when the item is smaller than one pixel in comparison to the background image
qreal factor = 1.0;
//check if scale factor if bigger that the item size, and thus it occupies less that a pixel in comparision to the background image
if (rect().width() < originalTransform.m11()) {
//calculate adjusted scale factor
factor = originalTransform.m11() / rect().width();
}
//adjust position according to scale factor
dx -= factor * originalCenter.x();
dy -= factor * originalCenter.y();
//set the new transform for painting
painter->setTransform(QTransform::fromScale(factor, factor) * QTransform::fromTranslate(dx, dy));
//now paint...
QGraphicsXYZItem::paint(painter, option, widget);
//restore original painter
painter->restore();
}
你需要太多调整边框在这种情况下:
QRectF MyGraphicsItem::boundingRect() const
{
QRectF rect = QGraphicsEllipseItem::boundingRect();
//this is a bit hackish, let me know if you know another way...
if (scene() != NULL && scene()->views().at(0) != NULL)
{
//get viewport transform
QTransform itemTransform = scene()->views().at(0)->transform();
QPointF originalCenter = rect.center();
//calculate back-projected original size of item
qreal realSizeX = rect.width() / itemTransform.m11();
qreal realSizeY = rect.height() / itemTransform.m11();
//check if scale factor is bigger that the item size, and thus it occupies less that a pixel in comparison
//to the background image and adjust size back to equivalent of 1 pixel
realSizeX = realSizeX < 1.0 ? 1.0 : realSizeX;
realSizeY = realSizeY < 1.0 ? 1.0 : realSizeY;
//set adjusted position and size according to scale factor
rect = QRectF(rect.center().x() - realSizeX / 2.0, rect.center().y() - realSizeY / 2.0, realSizeX, realSizeY);
}
return rect;
}
有了这个解决方案的项目在我的情况很好地工作。
Answer 5:
这里是我设计非常温和的复杂性的解决方案:
1)母公司获取boundingRect()并将其映射到场景2)取分的这个列表的最小X和Y,这是你的项目的真实产地,在场景坐标3)设置孩子的位置
在Pyside:
br = parent.mapToScene(parent.boundingRect())
realX = min([item.x() for item in br])
realY = min([item.y() for item in br])
child.setPos(parent.mapFromScene(realX, realY)) #modify according to need
Answer 6:
我找到了另一种解决方案,不涉及任何转换或手动缩放/定位搞乱。 有一个暗示QGraphicsItem::ItemIgnoresTransformations
标志说明:
QGraphicsItem::ItemIgnoresTransformations
项忽略继承变换(即, 其位置被固定仍然到其父 ,但父或视图旋转,缩放或剪切变换被忽略)。 [...]
这就是关键! 我们需要两个项目:父母将保持相对位置(没有设置任何标志),并且还要做父母的(0,0)点的图纸(含子项QGraphicsItem::ItemIgnoresTransformations
标志)。 就那么简单!
我封装这个功能集成到一个单一的类 - 这里是一些代码:
#include <QGraphicsItem>
#include <QPainter>
class SampleShape : public QGraphicsItem
{
private:
/* This class implements shape drawing */
class SampleShapeImpl : public QGraphicsItem
{
public:
SampleShapeImpl (qreal len, QGraphicsItem *parent = nullptr)
: QGraphicsItem(parent), m_len(len)
{
/* ignore transformations (!) */
setFlag(QGraphicsItem::ItemIgnoresTransformations);
}
QRectF boundingRect (void) const override
{
/* sample bounding rectangle */
return QRectF(-m_len, -m_len, m_len*2, m_len*2);
}
void paint (QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override
{
/* draw a shape, (0,0) is an anchor */
painter->drawLine(0, -m_len, 0, m_len);
painter->drawLine(-m_len, 0, m_len, 0);
// ...
}
private:
qreal m_len; // sample shape parameter
};
public:
/* This is actually almost an empty class, you only need to set
* a position and pass any parameters to a SampleShapeImpl class.
*/
SampleShape (qreal x, qreal y, qreal len, QGraphicsItem *parent = nullptr)
: QGraphicsItem(parent), m_impl(len, this) // <-- IMPORTANT!!!
{
/* set position at (x, y), view transformations will apply */
setPos(x, y);
}
QRectF boundingRect (void) const override
{
return QRectF(); // it's just a point, no size
}
void paint (QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override
{
// empty, drawing is done in SampleShapeImpl
}
private:
SampleShapeImpl m_impl;
};
文章来源: Maintaining relative child position after applying QGraphicsItem::ItemIgnoresTransformations