How to zoom a whole QML2 scene in QQuickView? - c++

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.

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.

What is the best way to draw plots in Qt?

I am using Qt to draw a spectrogram like this:
.
I also want to be able to select regions of the graph and edit them, as well as scrolling and zooming around.
I am considering QGraphicsView class but not sure about its performance. As I know, the objects in QGraphicsView are stored individually and drawing a huge amount of dots might impact performance.
What Qt classes should I use to achieve this?
Definitely do not use the QGraphicsItem for every dot/mark. Good approach would be to generate a QPixmap representing your spectrogram and than place this pixmap into the QGraphicsScene as a single item (QGraphicsPixmapItem can be used for that).
To draw on the QPixmap use the QPainter. Maybe a little example will be useful:
const int spectrWidth = 1000;
const int spectrHeight = 500;
QPixmap spectrPixmap(spectrWidth, spectrHeight);
QPainter p(&spectrPixmap);
for (int ir = 0; ir < spectrHeight; ir++)
{
for (int ic = 0; ic < spectrWidth; ic++)
{
double data = getDataForCoordinates(ic, ir); // your function
QColor color = getColorForData(data); // your function
p.setPen(color);
p.drawPoint(ic, ir);
}
}
The getDataForCoordinates() and getColorForData() are just example functions demonstrating how it could work. You have probably different way how to obtain data and it's color.
EDIT
But if you do not need a zoom/pan functionality than even easier would be just to paint directly on the QWidget in the QWidget::paintEvent() and not using the QGraphicsView/QGraphicScene at all.
I would suggest you to use either QCustomPlot or Qwt for this purpose.
Both have very good documentation.
If you choose to work with Qwt take a look at QwtPlotSpectrogram Class.
QCustomPlot is external library, if you are looking for something native to QT then have a look at QPainter class.

2D plot of position and angle in Qt

I have made a controller for a car and I am currently trying to make a GUI for the controller in Qt.
The only thing I am lacking now is a visualization of the car's position and angle relative to its starting point.
I want to make something like this:
where the circle represents the car and the line in it represents its heading/angle.
An added bonus feature would be to have a fading trace of its path as it moves, but if I got the basics down, I should be able to sort that out myself.
I have tried looking at some plot examples, but couldn't extrapolate what I needed to solve my problem.
How would you recommend going about the implementation of something like this?
You say:
I have all the measurements
So let's assume that you have Euler angles such that you can filter out changes in roll and only consider changes in φ.
To do this you'll be looking to extend a QWidget adding a member φ, we'll name it: m_phi. We'll also need to add your QPixMap as a member, we'll call it m_px. And you'll be overriding the QWidget::paintEvent.
paintEvent(qPaintEvent* /*event*/) {
if(!m_px.isNull()) {
QPainter* p;
p.setRenderHint(QPainter::Antialiasing);
p.translate(width() / 2.0, height() / 2.0);
p.save();
p.rotate(m_phi);
QRect r = m_px.rect();
r.moveCenter(QPoint());
p.drawPixmap(r, m_px);
p.restore();
}
}

Qt 4.8.5 QGraphicsView::fitInView fails to fit exactly

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.

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.