Qt 4.8.5 QGraphicsView::fitInView fails to fit exactly - c++

I Have a problem trying to fit my content (stretch) of a scene into my QDeclarativeView. I load a QML file the common way. I overrode the showEvent and resizeEvent method with the code below:
QGraphicsItem* rootItem = this->scene()->items.at(0);
QRectF rootRect = rootItem->sceneBoundingRect(); // it gives me a QRectF(0,0,1920,1080)
this->fitInView(rootRect, Qt::IgnoreAspectRatio); // Aspect doesn't matters.
The problem is that it keeps showing a little white border (almost 4 pixels) around the content. I've tested in 1920x1080, 1920x1200 and 1440x900 and all those resolutions on my desktop shows the content with the same problem. Even out of fullscreen mode it keeps the little white border.
Just to make sure it was nothing from the content, I have set the view's background brush to black and the white border became black (in other words, the content is being scaled down too much to fit in view).
Subtracting values from rectangle hardcoding is not an option once it's varying the background portion depending on the content size. (It should adapt dynamically).
Any suggestions?

Just encountered the problem as well. Since the bug is not about to be solved, I'll post my partial solution. I subclassed QGraphicsView and added a method myFitInView(), that does the required scaling and centering automatically.
I guess if you need more performance you could also directly fill the the matrix, but I don't need this and therefore scale and center seperately.
Also, any previous view transformations are lost with this approach, but you could probably account for that as well, by getting the current matrix and modifying/multiplying it accordingly.
void MyGraphicsView::myFitInView(QRectF const &rect)
{
QRectF viewRect = frameRect();
double scaleX = viewRect.width() / rect.width();
double scaleY = viewRect.height() / rect.height();
QTransform trans;
trans.scale(scaleX, scaleY);
setTransform(trans, false);
centerOn(rect.width() / 2, rect.height() / 2);
}

seems like a bug in Qt: https://bugreports.qt-project.org/browse/QTBUG-11945.
my ugly workaround for that is
QRectF removeMargin11945(const QRectF& sceneRect, const QSize& viewerSize){
const int bugMargin = 2;
const double mx = sceneRect.width()/viewerSize.width()*bugMargin;
const double my = sceneRect.height()/viewerSize.height()*bugMargin;
return sceneRect.adjusted(mx, my, -mx, -my);
}
What makes it particularly ugly is that sometimes it is not required and things just work fine, be careful to distinguish those cases.

Related

Is there any way to smoothly scale and draw a section of a QPixmap that's defined by a QRectF?

I'm working on a Qt 5 mac application and I'm looking for a method to smoothly scale and render a fractional section of a QPixmap as defined by a QRectF.
What I want to do actually is exactly what void QPainter::drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect) is supposed to do:
QRectF sourceRect = ...;
QRectF targetRect = ...;
painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing);
painter.drawPixmap(targetRect, pixmap, sourceRect);
However, as mentioned in this thread and this bug report, QPainter::SmoothPixmapTransform is ignored and this method does not work.
Short of writing my own efficient bilinear scaling method from scratch (which I am not inclined to do), is there any other method I can use to accomplish the same thing?
QPixmap::scaled() only allows scaling to integer dimensions, and provides no way to crop out a section defined by a QRectF, so that's a non-starter.
Just tossing out ideas here, but is it possible to somehow use OpenGL to render the portion of the image I want at the right scale and then render it back into a QImage or QPixmap? This kind of scaling is one of the most basic things OpenGL can do very easily and quickly, but I don't have any experience using OpenGL in a Qt desktop app so far so I'm not sure if this is possible.

Drawing an arc correctly with Qt5 painter

I am trying to draw an arc at the edge of the bounding rectangle. This is important since I want it to scale with the control. However, This leads to the edges getting clipped off when using boundingRect() as an argument for the drawArc().
QBrush brush(QColor("#007430"));
painter->setBrush(brush);
QPen pen;
pen.setStyle(Qt::SolidLine);
float lineWidth1 = 6.0;
pen.setWidthF(lineWidth1);
painter->setPen(pen);
painter->setRenderHint(QPainter::Antialiasing);
painter->drawArc(boundingRect(), 45*16, 270*16);
To make it work correctly, I must pass in a rectangle that is 1/2 of the pen width smaller on each side. Is there a more direct way to do this in QT without manual calculating/adjusting?
QRectF arcRect(0 + lineWidth1/2,
0 + lineWidth1/2,
boundingRect().width() - lineWidth1,
boundingRect().height() - lineWidth1);
painter->drawArc(arcRect, 45*16, 270*16);
I am sorry to bring you the real answer which unfortunately is no, there is no automatic way to scale to bounding box of drawing operations with QPainter in Qt5. You will therefore have to calculate this in your own code on a per case basis.
On the bright side, this calculation is not very hard, and by doing it yourself you are certain to maintain full control over the process.

Qt - Using a QTransform (or similar), scale inner QRect to/from QGraphics

Some background -
Say you have QGraphicsScene, and only one view, which is a 1-1 scale with the scene.
You have a QRect A, which is represents an external view of the scene, with a pre-defined pixel size.
You have a QRect A1 which is a smaller rect inside of A.
How do you translate A1 to the scene, such that it is scaled correctly (i.e. if it's 1/4 of rect A, it will occupy 1/4 of the scene), and then undo that transform to scale a rect created in the scene to fit in rect A correctly?
I can do all this brute force, but I'm wondering if there's a way using Qt's built in classes...
After looking over some examples to try and find similar uses, I realized I'm totally missing the point - I can just set A/A1 directly to the scene, and scale the view (via the totally obvious but somehow completely overlooked until now QGraphicsView::fitInView(..)) to fit the rects inside. No rect transforms necessary. Total 'duh' moment. :)
I will need to transform mouse clicks and points in the view when interacting with it, but there is a whole nice set of mapTo* mapFrom* that will handle that nicely.
TL;DR - Use fitInView()

How to zoom a whole QML2 scene in QQuickView?

I have a QML2 document which is significantly larger than the display on which it's displayed with a QQuickView.
In QML1 and QtDeclarative it was possible to use QGraphicsView::fitInView to scale the whole scene (including correct MouseEvent mapping, etc).
Is there something similar for QML2 I just didn't find yet?
I came up with a solution that somehow behaves like QGraphicsView::fitInView(aRect, Qt::KeepAspectRatio).
void MyQuickView::fitInView(const QRectF & newRect)
{
QSizeF newSize = newRect.size();
qreal horizontalScale = size().width() / newSize.width();
qreal verticalScale = size().height() / newSize.height();
// You might want to use another origin
rootObject()->setTransformOrigin(QQuickItem::TopLeft);
rootObject()->setSize(newSize);
rootObject()->setScale(qMin(horizontalScale, verticalScale));
}
This does mostly the job, although I haven't thoroughly tested all of my old Qt4.8 code.

QGraphicsItem::setTransformOriginPoint bug when trying to scale image

I have created my own class by extending QGraphicsItem and I want to make it so that when someone does a wheel even while over this item, it scales.
This way, i can have multiple items in a scene, and scale each of them in and out as I please.
The problem is, I want the item to scale under the mouse cursor, much like google maps does. That is, a move forward will keep panning the image and scaling it, so taht the area in the vicinity around my mouse pointer is always in view.
void ImagePixmapItem::wheelEvent ( QGraphicsSceneWheelEvent * event ){
update();
qreal factor = 1.2;
if (event->delta() < 0)
factor = 1.0 / factor;
scale(factor, factor);
scaleFactor *=factor;
this->scene()->setSceneRect(0,0,this->boundingRect().width(), this->boundingRect().height());
}
This is the code I am using to do the scale. The problem is, it always seems to be scaling from the top left corner. Well, this is undesirable, beacuse if I scale in or out too much, eventually my area of interest around the mouse pointer has moved off the screen, and I have to either scroll manually or pan to the location, zoom, pan, etc, until i get to the desired level.
I tried to use the QGraphicsItem::setTransformOriginPoint, but no matter what values I put in there, it still seems to scale and such from the top left.
What can I add to that code I posted to get the desired effect?
I have achieved similar functionality in my Image-Manipulation application (scaling the view and having the area under my mouse stay in place and visible) but I scale the whole graphics-view not a specific item, so I don't know if this code can solve your problem.
Anyway, this is what I do in the constructor of my subclassed QGraphicsView (after I set the scene):
setTransformationAnchor(AnchorUnderMouse);
setResizeAnchor(AnchorViewCenter);
I also use the above functions, after each call to:
MyGraphicsView->setTransform(transform);
I'm not sure if this can help you, but I hope so.