0

我想动态调整 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。

您有什么建议可以修复我的代码吗?谢谢!

4

0 回答 0