Вопрос

I have a QGraphicPixmapItem which holds a png image, present on the scene.

The Image itself is a rectangular image. My requirement is that, I should be able to resize/scale the image when I resize the rectangular image on mouse move event. I can resize the rectangle by dragging on any side of the rectangular image.

The problem is that, I am able to resize the rectangular image by dragging any of its sides but the original image is awefully distorted beyond recognition. The image basically turns into a lump of solid mass on continuous resizing( expanding/decreaing width or height). How to achieve the resizing/scaling of the image in Qt without damaging the original image too much? What I experienced is not pixilation but smethg worse.

The code below is a snapshot of mouseMoveEvent() of QGraphicsPixmapItem, implemented for resizing the rectangle by dragging right/left side of rectangle image.

 void PersonSizeGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
    {
        const QPointF event_pos = event->pos();
        const QPointF event_scene_pos = event->scenePos();

        QPixmap current_pixmap = this->pixmap();
        QImage current_image = current_pixmap.toImage();
        QRect current_image_rect = current_image.rect();

        QPoint current_top_left = current_image_rect.topLeft();
        QPoint current_bottom_right = current_image_rect.bottomRight();

        if((event->scenePos().x() > this->scene()->width()) || (event->scenePos().y() > this->scene()->height())
            || (event->scenePos().x() < 0) || (event->scenePos().y() < 0) )
        {
            return;
        }

        if( this->cursor().shape() == Qt::SizeHorCursor )
        {
            if(rect_right_condition)
            {
                        new_rect = QRect( current_top_left, QPoint( event->pos().x(), current_bottom_right.y()) );


                scaled_pixmap = QPixmap::fromImage(current_image.scaled(QSize(new_rect.width(),new_rect.height()),Qt::IgnoreAspectRatio,Qt::FastTransformation));

                setPixmap(scaled_pixmap);

     }

            if(rect_left_condition)
            {
                            new_rect = QRect( QPoint(event_pos.x(), 0), current_bottom_right );

    scaled_pixmap = QPixmap::fromImage(current_image.scaled(QSize(new_rect.width(),new_rect.height()),Qt::IgnoreAspectRatio,Qt::FastTransformation));
                setPixmap(scaled_pixmap);
                QPoint new_top_left = new_rect.topLeft();
                QPointF mapped_topLeft = mapToParent(QPointF(new_top_left.x(),new_top_left.y()));
                this->setPos(mapped_topLeft);
                rect_resize_occurred = true;


            }

        }
    }
Это было полезно?

Решение

The image basically turns into a lump of solid mass on continuous resizing( expanding/decreaing width or height).

This is normal. What you need to do is change the method for the effect you desire. Rather than constantly changing the same image, start with a source image of the maximum size you expect the user will require. This image will not be altered.

In the mouseMove function, update member variables to store the size of the image that you display.

Then, in the PersonSizeGraphicsItem's paint function, use drawImage to specify the source image and the target rect to draw the image at the size that was updated in mouseMoveEvent:-

void QPainter::drawImage(const QRectF & rectangle, const QImage & image);

So, by keeping the source image at its original size, you won't be distorting it more and more with each successive resize.

class PersonSizeGraphicsItem : public QGraphicsItem
{
    public:
        PersonSizeGraphicsItem(QGraphicsItem* parent);

    protected:
        void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
        void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0)

    private:
        QRectF m_imageRect;
        QImage m_image;
};

void PersonSizeGraphicsItem::mouseMoveEvent()
{
   // Update the image rect here
}

void PersonSizeGraphicsItem::paint(QPainter * painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    painter->drawImage(m_imageRect, m_image);
}

Другие советы

Reimplemented code based on Merlin069's answer:

PersonSizeGraphicsItem::PersonSizeGraphicsItem(const QPixmap &pixmap, QGraphicsScene *scene)
    :QGraphicsPixmapItem(pixmap, 0, scene)
{
    this->setFlag(QGraphicsItem::ItemIsMovable, true);
    this->setFlag(QGraphicsItem::ItemIsSelectable, true);
    this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
    this->setFlag(QGraphicsItem::ItemIsFocusable, true);
    this->setFocus(Qt::MouseFocusReason);
    this->setAcceptHoverEvents(true);
    //this->setScale(0.5);

    rect_left_condition = false;
    rect_right_condition = false;
    rect_top_condition = false;
    rect_bottom_condition = false;
    rect_resize_occurred = false;
    image_rect = QRect();
    image_rect =  this->pixmap().toImage().rect();
}

void PersonSizeGraphicsItem::setSourceImage(const QImage& source_image)
{
    this->source_image =  source_image;
}


void PersonSizeGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    const QPointF event_pos = event->pos();
    const QPointF event_scene_pos = event->scenePos();

    QPoint current_top_left = image_rect.topLeft();
    QPoint current_bottom_right = image_rect.bottomRight();

    if((event->scenePos().x() > this->scene()->width()) || (event->scenePos().y() > this->scene()->height())
        || (event->scenePos().x() < 0) || (event->scenePos().y() < 0) )
    {
        return;
    }

    if( this->cursor().shape() == Qt::SizeHorCursor )
    {
        if(rect_right_condition)
        {

        image_rect = QRect( current_top_left, QPoint( event->pos().x(), current_bottom_right.y()) );

        }

        if(rect_left_condition)
        {

            image_rect = QRect( QPoint(event_pos.x(), 0), current_bottom_right);

            QPoint new_top_left = image_rect.topLeft();
            QPointF mapped_topLeft = mapToParent(QPointF(new_top_left.x(),new_top_left.y()));
            this->setPos(mapped_topLeft);
            rect_resize_occurred = true;

            //qDebug() << "new rectangle top left**:" << this->pixmap().rect().topLeft();
        }

    }

    if( this->cursor().shape() == Qt::SizeVerCursor )
    {
        if(rect_bottom_condition)
        {

            image_rect = QRect(current_top_left, QPoint(current_bottom_right.x(), event->pos().y()));


    }

        if(rect_top_condition)
        {
            image_rect = QRect(QPoint(0, event_pos.y()), current_bottom_right);

                        QPoint new_top_left = image_rect.topLeft();
            QPointF mapped_topLeft = mapToParent(QPointF(new_top_left.x(),new_top_left.y()));
            this->setPos(mapped_topLeft);


        }
    }

    this->update();

}

void PersonSizeGraphicsItem::paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->drawImage(image_rect, source_image);
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top