I am making an application where I need to draw figures (i.e. rectangles) above a picture and resize the whole scene. I'm using QGraphicsView
and QGraphicsScene
. I can't figure out why but when I was using fitIntoView()
I was unable to draw figures on top of a picture (they probably were drawn behind the picture or outside the bounds).
Now I'm using QPixmap.scaled()
to make the image fit in the QGraphicsScene
. It works fine except when I need to display a big image and then zoom it in. Because I scaled the image to fit, it became smaller and when I call QGraphicsView.scale()
the image scales as small one and I can't find a way to "scale back" the image to original size.
In the zoom part of code I tried to replace pixmap with its not scaled copy but I can't scale it with the same proportions as my figures scaling. Any help would be appreciated!
Here I load the image and scale it
QPixmap pix;
pix = pixmap->scaled(wid, hei,Qt::KeepAspectRatio, Qt::SmoothTransformation);
scn = new QGraphicsScene(pw);
pw->setScene(scn);
p = new QGraphicsPixmapItem(pix);
p->setPixmap(pix);
scn->addItem(p);
I draw figures like this
rect = new QGraphicsRectItem(x,y,w,h);
rect->setPen(QPen(getColor(), 1, Qt::SolidLine, Qt::FlatCap));
scn->addItem(rect);
And here's how I zoom
pw->scale(scaleFactor_,scaleFactor_);
Update:
Now I have a QWidget
with kind of toolbar on the top, the rest of free space is filled with a custom QGraphicsView
. This is a derived class for grabbing mouse events, there's nothing more but overrides of event handlers. I'm adding PainterGraphicsView in my widget's constructor:
pw = new PainterGraphicsView();
ui->gridLayout_3->addWidget(pw);
I'm recreating the scene every time I load a new image into it:
scn = new QGraphicsScene(pw);
pw->setScene(scn);
QRect r = QRect(0,0, pw->width()-5, pw->height()-5);
scn->setSceneRect(r);
After I loaded an image I can draw figures on top of it, it looks like this:
And the scaled contents look like this:
As you can see, figures scaled together with a pixmap and this is exactly how I need it to work. The only thing I have to fix is the low quality of scaled pixmap. As I already said, I tried to replace pixmap with the original one in my ZoomIn method, but I can't do it saving figures' position.
void DrawerWidget::on_btZoom_clicked()
{
p->setPixmap(pix); //p is QGraphicsPixmapItem, pix is an original pixmap
p->setScale(0.5); //how can I scale the pixmap together with figures?? How to calculate the required scale?
pw->scale(scaleFactor_,scaleFactor_);
}
Update 2:
A short explanation on my drawing figures method: (though I personally don't think that this is the issue, I'm interested is there a way to scale QGraphicsPixmapItem using setScale() to fit in QGraphicsView size)
I'm getting start_
and end_
coordinates from mouse events arguments (QMouseEvent *e)
end_=pw->mapToScene(e->pos());
start_=pw->mapToScene(e->pos());
I add the figure on mousepress:
rect = new QGraphicsRectItem(start_.x(),start_.y(),1,1);
scn->addItem(rect);
And I redraw the figure on mouse move
rect->setRect(Graphics::GetFigure(start_.x(),start_.y(),end_.x(),end_.y()));
GetFigure is a method for calculating the figure's rect, here's main part of it:
static QRectF GetFigure(double startX, double startY, double finalX, double finalY)
{
QRectF shape;
shape.setX(startX);
shape.setY(startY);
shape.setWidth(qFabs(finalX - startX));
shape.setHeight(qFabs(finalY - startY));
return shape;
}
The scaling operation is destructive, once you scale down you end up with less data than you started with.
IF you want to be able to restore the original size keep a copy of the original pixmap.
You can create the QGraphicsPixmapItem
from the original, non-scaled pixmap and then use QGraphicsPixmapItem::setScale(qreal)
to change the size on level graphics item, not on level pixmap data. This way scaling should not be destructive, and you should not lose quality if you scale it up to the original size.
IF you want to scale multiple items (and not run into different transformation origin problems) you have a few options:
Item transformations accumulate from parent to child
createItemGroup()
: The items are all reparented to the group, and their positions and transformations are mapped to the group
I think your problem is that you set the scene rect as the QGraphicsView
rect. This is not correct because the window reference system is different from the scene reference system.
You don't need to set the scene rect, because the scene rect grows automatically when you add some items. If you want to limit the scene rect to the pixmap rect, you can set the scene rect as the QPixampItem
bounding rect.
You don't need to scale the original pixmap. To scale your view, simply call QGrapicsView::scale
. You can also call QGrapicsView::fitInView
to fit the image in the view.
If you need to add some rects drawn by user (i.e. in window coordinates), you can use QGraphiscView::mapToScene
to map the window coordinates to scene coordinates
I suggest to read the documentation about reference systems: The Graphics View Coordinate System
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With