我想动态调整 QGraphicsTextItem 对象的大小并将文本保留在左上角。我试图以多种方式解决这个问题,但没有成功,所以我包含了 IMO 最接近工作版本的代码版本。
文本文件
#include <QApplication>
#include <QRectF>
#include <QAbstractTextDocumentLayout>
#include <qmath.h>
#include "ltext.h"
LText::LText(QGraphicsTextItem *parent) : QGraphicsTextItem(parent)
{
setNeededFlags();
QString *text = new QString("Text");
setPlainText(*text);
setFont(QFont("Arial", 42));
m_rect = QRectF();
}
QRectF LText::boundingRect() const
{
if (QRectF(0, 0, 0, 0) == m_rect)
return QGraphicsTextItem::boundingRect();
return m_rect;
}
void LText::updateRect(const QRectF rect)
{
prepareGeometryChange();
setPos(mapToScene(rect.topLeft()));
m_rect.moveTo(0, 0);
m_rect.setSize(rect.size());
update(m_rect);
}
void LText::setNeededFlags()
{
setFlags(QGraphicsItem::ItemIsSelectable |
QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemSendsGeometryChanges |
QGraphicsItem::ItemIsFocusable);
}
文本文件
#ifndef LTEXT_H
#define LTEXT_H
#include <QGraphicsTextItem>
#include <QTextDocument>
class LText : public QGraphicsTextItem
{
Q_OBJECT
public:
enum { Type = UserType + QGraphicsTextItem::Type };
LText(QGraphicsTextItem *parent = nullptr);
int type() const override { return Type; }
QRectF boundingRect() const override;
void setNeededFlags();
void updateRect(const QRectF rect);
signals:
void signalRectChanged();
private:
QRectF m_rect;
};
#endif // LTEXT_H
大小gripitem.cpp
/*
* SizeGripItem - A size grip QGraphicsItem for interactive resizing.
* Copyright (c) 2011 Cesar L. B. Silveira
*/
#include <QBrush>
#include <qmath.h>
#include "sizegripitem.h"
#include "ltext.h"
SizeGripItem::HandleItem::HandleItem(int positionFlags, SizeGripItem* parent)
: QGraphicsRectItem(-4, -4, 8, 8, parent),
positionFlags_(positionFlags),
parent_(parent)
{
setBrush(QBrush(Qt::lightGray));
setFlag(ItemIsMovable);
setFlag(ItemSendsGeometryChanges);
}
int SizeGripItem::HandleItem::positionFlags() const
{
return positionFlags_;
}
QVariant SizeGripItem::HandleItem::itemChange(GraphicsItemChange change,
const QVariant &value)
{
QVariant retVal = value;
if (change == ItemPositionChange)
{
retVal = restrictPosition(value.toPointF());
}
else if (change == ItemPositionHasChanged)
{
QPointF pos = value.toPointF();
switch (positionFlags_)
{
case TopLeft:
parent_->setTopLeft(pos);
break;
case Top:
parent_->setTop(pos.y());
break;
case TopRight:
parent_->setTopRight(pos);
break;
case Right:
parent_->setRight(pos.x());
break;
case BottomRight:
parent_->setBottomRight(pos);
break;
case Bottom:
parent_->setBottom(pos.y());
break;
case BottomLeft:
parent_->setBottomLeft(pos);
break;
case Left:
parent_->setLeft(pos.x());
break;
}
}
return retVal;
}
void SizeGripItem::HandleItem::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
parent_->parentItem()->setFlag(ItemIsMovable, false);
QGraphicsRectItem::mousePressEvent(mouseEvent);
}
void SizeGripItem::HandleItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
parent_->parentItem()->setFlag(ItemIsMovable, true);
QGraphicsRectItem::mouseReleaseEvent(mouseEvent);
}
QPointF SizeGripItem::HandleItem::restrictPosition(const QPointF& newPos)
{
QPointF retVal = pos();
if (positionFlags_ & Top || positionFlags_ & Bottom)
retVal.setY(newPos.y());
if (positionFlags_ & Left || positionFlags_ & Right)
retVal.setX(newPos.x());
if (positionFlags_ & Top && retVal.y() > parent_->rect_.bottom())
retVal.setY(parent_->rect_.bottom());
else if (positionFlags_ & Bottom && retVal.y() < parent_->rect_.top())
retVal.setY(parent_->rect_.top());
if (positionFlags_ & Left && retVal.x() > parent_->rect_.right())
retVal.setX(parent_->rect_.right());
else if (positionFlags_ & Right && retVal.x() < parent_->rect_.left())
retVal.setX(parent_->rect_.left());
return retVal;
}
SizeGripItem::SizeGripItem(Resizer *resizer, QGraphicsItem* pItem, QObject* parent)
: QObject(parent),
resizer_(resizer)
{
setParentItem(pItem);
if (parentItem())
{
rect_ = parentItem()->boundingRect();
}
handleItems_.append(new HandleItem(TopLeft, this));
handleItems_.append(new HandleItem(Top, this));
handleItems_.append(new HandleItem(TopRight, this));
handleItems_.append(new HandleItem(Right, this));
handleItems_.append(new HandleItem(BottomRight, this));
handleItems_.append(new HandleItem(Bottom, this));
handleItems_.append(new HandleItem(BottomLeft, this));
handleItems_.append(new HandleItem(Left, this));
updateHandleItemPositions();
}
SizeGripItem::~SizeGripItem()
{
}
QRectF SizeGripItem::boundingRect() const
{
return rect_;
}
void SizeGripItem::paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget)
{
Q_UNUSED(painter);
Q_UNUSED(option);
Q_UNUSED(widget);
}
#define IMPL_SET_FN(TYPE, POS) \
void SizeGripItem::set ## POS (TYPE v) \
{ \
rect_.set ## POS (v); \
doResize(); \
}
IMPL_SET_FN(qreal, Top)
IMPL_SET_FN(qreal, Right)
IMPL_SET_FN(qreal, Bottom)
IMPL_SET_FN(qreal, Left)
IMPL_SET_FN(const QPointF&, TopLeft)
IMPL_SET_FN(const QPointF&, TopRight)
IMPL_SET_FN(const QPointF&, BottomRight)
IMPL_SET_FN(const QPointF&, BottomLeft)
void SizeGripItem::doResize()
{
if (resizer_)
{
(*resizer_)(parentItem(), rect_);
updateHandleItemPositions();
}
}
void SizeGripItem::updateHandleItemPositions()
{
foreach (HandleItem* item, handleItems_)
{
item->setFlag(ItemSendsGeometryChanges, false);
switch (item->positionFlags())
{
case TopLeft:
item->setPos(rect_.topLeft());
break;
case Top:
item->setPos(rect_.left() + rect_.width() / 2 - 1,
rect_.top());
break;
case TopRight:
item->setPos(rect_.topRight());
break;
case Right:
item->setPos(rect_.right(),
rect_.top() + rect_.height() / 2 - 1);
break;
case BottomRight:
item->setPos(rect_.bottomRight());
break;
case Bottom:
item->setPos(rect_.left() + rect_.width() / 2 - 1,
rect_.bottom());
break;
case BottomLeft:
item->setPos(rect_.bottomLeft());
break;
case Left:
item->setPos(rect_.left(),
rect_.top() + rect_.height() / 2 - 1);
break;
}
item->setFlag(ItemSendsGeometryChanges, true);
}
}
大小gripitem.h
#ifndef SIZEGRIPITEM_H
#define SIZEGRIPITEM_H
#include <QGraphicsItem>
#include <QGraphicsRectItem>
#include <QScopedPointer>
#include <QObject>
class SizeGripItem : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
private:
enum
{
Top = 0x1,
Bottom = 0x2,
Left = 0x4,
TopLeft = Top | Left,
BottomLeft = Bottom | Left,
Right = 0x8,
TopRight = Top | Right,
BottomRight = Bottom | Right
};
class HandleItem : public QGraphicsRectItem
{
public:
HandleItem(int positionFlags, SizeGripItem* parent);
int positionFlags() const;
protected:
virtual QVariant itemChange(GraphicsItemChange change,
const QVariant &value) override;
virtual void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
private:
QPointF restrictPosition(const QPointF& newPos);
int positionFlags_;
SizeGripItem* parent_;
};
public:
class Resizer
{
public:
virtual void operator()(QGraphicsItem* item,
const QRectF rect) = 0;
virtual ~Resizer() {}
};
SizeGripItem(Resizer* resizer = 0, QGraphicsItem* pItem = nullptr, QObject* parent = nullptr);
virtual ~SizeGripItem();
virtual QRectF boundingRect() const;
virtual void paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget = 0);
void setTopLeft(const QPointF& pos);
void setTop(qreal y);
void setTopRight(const QPointF& pos);
void setRight(qreal x);
void setBottomRight(const QPointF& pos);
void setBottom(qreal y);
void setBottomLeft(const QPointF& pos);
void setLeft(qreal x);
private:
void doResize();
void updateHandleItemPositions();
QList<HandleItem*> handleItems_;
QRectF rect_;
QScopedPointer<Resizer> resizer_;
};
#endif // SIZEGRIPITEM_H
尺寸调整器.cpp
class TextResizer : public SizeGripItem::Resizer
{
public:
virtual void operator()(QGraphicsItem* item, const QRectF rect)
{
LText* textItem =
qgraphicsitem_cast<LText*>(item);
if (textItem)
textItem->updateRect(rect);
}
};
我正在使用 Qt 5.15.2。
您有什么建议可以修复我的代码吗?谢谢!