Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fixed size QGraphicsItems in multiple views?

I'm visualizing a graph using Qt's graphics view framework. It looks something like this:

Example view from the program

Now, I want the size of the vertices, which I'm drawing as small filled circles, to remain constant relative to the zooming of the view. At the moment I'm accomplishing this by not having my vertices as items in the scene, but instead drawing them in the view's drawForeground(...) function, like this:

void View::drawForeground(QPainter *painter, const QRectF& rect) {
    painter->setMatrixEnabled(false);
    painter->setPen(Qt::NoPen);
    painter->setBrush(Qt::black);
    painter->setRenderHint(QPainter::Antialiasing);

    // Draw points.
    const QRectF biggerRect = rect.adjusted(-100, -100, 100, 100);
    const float radius = 2.0;
    foreach (const QPointF& point, m_points) {
        if (biggerRect.contains(point)) {
            painter->drawEllipse(QPointF(mapFromScene(point)), radius, radius);
        }
    }

    // ...
}

But this is kludgy and wrong since the vertices are conceptually part of my scene, and should be items in my QGraphicsScene. Also, as an example, I might want to temporarily hide a set of vertices, or transform them, which would be much easier to do if they were proper items in the scene. Last but not least, having the views draw the points breaks the model/view separation and forces the views to know about the points they are displaying (there may be more than one view).

Using this approach I also experienced trouble with the relative positions of vertices (non-items) and edges (items) ending up wrong when render(...)ing a view to a QSvgGenerator, probably due to my trick of disabling the transformation of the painter.

So, my question is: How can I have my vertices as QGraphicsItems added to my scene, while still having their sizes constant relative to the view, in each view showing the scene?

I have tried setting the QGraphicsItem::ItemIgnoresTransformations flag on the items. The documentation has this to say about the flag:

The item ignores inherited transformations (i.e., its position is still anchored to its parent, but the parent or view rotation, zoom or shear transformations are ignored). This flag is useful for keeping text label items horizontal and unscaled, so they will still be readable if the view is transformed. When set, the item's view geometry and scene geometry will be maintained separately. You must call deviceTransform() to map coordinates and detect collisions in the view. By default, this flag is disabled. This flag was introduced in Qt 4.3.

But setting this flag results in all view transformations being ignored, such that points will no longer appear to grow further apart when I zoom in, which is not what I want. I only want the item size (in on-screen pixels) to remain constant.

Since Merlin069 asked for this: The code I used when I tried this flag out was simply adding each vertex to my scene like this:

QGraphicsEllipseItem *item = scene->addEllipse(x - 2.0, y - 2.0, 4.0, 4.0);
item->setPen(Qt::NoPen);
item->setBrush(Qt::black);
item->setFlag(QGraphicsItem::ItemIgnoresTransformations);

Below is a screenshot of what I got then. Zooming in 2x, 4x, 8x the item sizes remained constant (yay), but so did the on-screen distance between the points :(

Another screenshot

Any tips/pointers on a solution to this are much appreciated!

like image 620
estan Avatar asked Nov 11 '22 18:11

estan


1 Answers

If you look at the docs for addEllipse it states: -

Creates and adds an ellipse item to the scene, and returns the item pointer. The geometry of the ellipse is defined by rect, and its pen and brush are initialized to pen and brush.

Note that the item's geometry is provided in item coordinates, and its position is initialized to (0, 0).

So what you're doing here is placing all the items at (0,0) , but the item's rects are changing. What you need to do is create the items and then set their positions.

like image 181
TheDarkKnight Avatar answered Nov 15 '22 13:11

TheDarkKnight