How can I redefine where (0,0) of a QGraphicsItem is? - c++

I've a custom QGraphicsItem which draws nothing but is parent to other QGraphicsItems (like QGraphicsRectItem and so on). My top-level item has (0,0) somewhere "inside" the children Items. This is very inconvenient. I would like to shift the origin to the upper left corner of childrenBoundingRect().
In the picture I've (0,0) of my top-level item somewhere inside of my children items (solid arrow). I would like to shift the origin to the dashed lines. How can I do that?
As result I expect that positioning of the top-level item will be more convenient.

Examples for overriding QGraphicsItem often show the boundingRect() function originating from (0,0). Changing this will change the origin. So, for example, to change it to the centre, where width and height are variables stored internally in the class, you can do this: -
QRectF boundingRect() const
{
return (-width / 2, -height / 2, width, height);
}

Related

Reimplement resize event

My widget is frameless because of the sleek looks and so I need to reimplement the resize behaviour.
If I drag the bottom right corner it already works with this code:
void mouseMoveEvent(QMouseEvent *event) {
resize(event->pos().x(), event->pos().y());
}
But what about all the other corners? For example the bottom left corner.
As one expects, it should behave as if the top right corner of the widget would be fixed.
But in the resize function, the upper left corner is fixed, because there is the event.pos()==0.
My idea was to resize the window and then move it, so that it looks as if it would not move, but only change size around the upper left corner. As this leads to flickering and even not the perfect result, is there a better way?
EDIT: Solution:
a) You can define in mousePressEvent:
offset = event->pos();
initialFixedCornerPosX = this->width()+this->pos().x();
initialFixedCornerPosY = this->pos().y();
and in mouseMoveEvent
int x = event->globalX();
int y = event->globalY();
int x_w = offset.x();
int y_w = offset.y();
setGeometry(x-x_w,initialFixedCornerPosY,initialFixedCornerPosX-x+x_w,y-initialFixedCornerPosY);
or
b) in mouseMoveEvent
QRect rect = geometry();
rect.setBottomLeft(event->globalPos());
setGeometry(rect);
To both resize and move the window in one step without flickering, you should use QWidget::setGeometry(QRect) by providing a modified rectangle previously fetched using the corresponding getter function QWidget::geometry().
QRect rect = geometry();
// (then modify...)
setGeometry(rect);
To modify a corner of a QRect, you could either modify each edge or the corners directly. Depending on the rest of your logic, one makes more sense than the other. I'd prefer the second of the following two options:
Example using corners:
If you detect that the user drags the bottom left corner, use
rect.setBottomLeft(event->pos());
However, you of course need to consider edges too, and if you consider corners as separate cases this results in eight cases to be considered in the mouse event.
Example using only edges:
If you detect that the mouse is on the left edge (it might be as well on the top or bottom corner, which are only special cases, so for now we ignore that):
rect.setLeft(event->pos().x());
and if you detect it is on the bottom edge, then
rect.setBottom(event->pos().y());
so if both cases are true, this effectively moves the corner of the rect. So you only need to consider four cases to drag all edges and corners of your window! This assumes that you have a single widget which handles the resize (i.e. your top level widget, which has a margin on the layout to have the children not touch the window edge), and do not add a widget for each corner / edge.

QGraphicsView and QGraphicsScene coordinate systems

in Qt 4.8 i have create a QGraphicsView and a DynamicRadarScene(derived from QGraphicsScene):
QGraphicsView* view = new QGraphicsView;
view->setMinimumSize(800, 600);
DynamicRadarScene* _scene = new DynamicRadarScene(mode, channel_types, this);
view->setScene(_scene);
What is the coordinate system of QGraphicsScene? (0,0) is from upper left corner?
How can i draw an item in the upper right corner of the scene (i have set it 800x600: view->setMinimumSize(800, 600);)?
If i resize the widget and so i resize the QGraphicsView, how can move the item i have drawn before to remain in the upper left corner?
Yes, the upper left corner is generally the coordinate of (0,0) in a graphics scene. What you need to consider is that a QGraphicsView is like a window looking into a world (the QGraphicsScene). You set the view to look at an area or the scene, which may be all or just part of the scene.
Once the scene and view are setup, you can then add QGraphicsItems / QGraphicsObjects or instances of classes derived from those by using functions such as QGraphicsScene::addItem. These items are positioned in the scene and draw themselves.
i (sic) resize the widget and so i resize the QGraphicsView
You can change the QGraphicsView position and dimensions, but then the items in the scene will remain in the same place within the scene. Usually you would set up the scene and view and then move / resize the graphics items / objects within the scene, often with the setPos function: QGraphicsItem::setPos(). This sets the position of the item, relative to its parent. If the item has no parent, it sets the position of the item in the scene.
QGraphicsScene has property sceneRect. If it is not set then it is auto adjusted depending on scene content. This can give a filling that origin of coordinating is in some strange place or even that it is mobile.
Set this property. See also this.

setTransformOriginPoint not working as expected

I inherited from the QGraphicsObject and created a new class that has a pixmap and sets its transform origin point to:
setTransformOriginPoint(boundingRect().center());
But when I call setRotation() on the my class (which is added to a QGraphicsView using the scene), the rotation doesn't use the center as the rotation anchor. How can I set the center to be the anchor of the rotation ? Thanks !
More information: calling setRotation() outside of a sceneEvent function it works, but inside a sceneEvent, upon a pinch gesture, the origin point doesn't work.
Draw pixmap at QRect(0, 0, pixmap.width(), pixmap.height(). Use this rectangle for bounding rect also. Use setPos to move the item around the scene. Use setTransformOriginPoint(pixmap.width() / 2, pixmap.height() / 2) to set the origin point. These coordinates are in the item coordinates, so they should point at the pixmap's center regardless of the item's position.

What is the viewport of a tree widget?

I'm trying to locate an item of a tree widget.
Looking up in the doc, I got:
QTreeWidgetItem * QTreeWidget::itemAt ( const QPoint & p ) const
Returns a pointer to the item at the coordinates p. The coordinates are relative to the tree widget's viewport().
The viewport() function does not give definition about viewport either.
So what is a tree widget's viewport ?
QTreeWidget inherits from QAbstractScrollArea, which is where the viewport is defined:
QAbstractScrollArea is a low-level abstraction of a scrolling area. The area provides a central widget called the viewport, in which the contents of the area is to be scrolled (i.e, the visible parts of the contents are rendered in the viewport).
The viewport is essentially the visible part of the tree.

Overlaying image within larger image using QGraphicsView or QGraphicsScene

I'm new to Qt, so I might mangle this question. Having said that-
I'm rendering an image within a subclassed QGraphicsView. I added the image to the scene as a Pixmap with addPixmap(). I'd like to overlay (blit) smaller images on top of the larger one in specific locations. I can add the smaller image to the scene as well by again calling addPixmap(), but it always displays in the upper left corner. I'd like to set those coordinates myself.
How can I accomplish this?
Thanks!
QGraphicsScene::addPixmap returns a pointer to the added QGraphicsPixmapItem. If you want to set its position, you can do something like this:
QGraphicsPixmapItem *item = scene->addPixmap(yourPixmap);
item->setPos(50, 50); // sets position to scene coordinate (50, 50)
If you want to overlay images on top of other images, make sure you know about z-values. See the QGraphicsItem documentation for details. Basically, the z-value determines the stacking order.
Lastly, familiarize yourself with parenting of QGraphicsItems. When a QGraphicsItem has a parent item, it means (among other things) that its coordinates are expressed in terms of its parents' coordinates. So if an item has a position of (0, 0), but it's the child of an item whose scene position is (50, 50), then the child item will be displayed at (50, 50). So, given the above example, you could then do:
QGraphicsPixmapItem *childItem = new QGraphicsPixmapItem(item);
This creates a new item, "childItem", whose parent is "item". Its coordinates are (0, 0), because they haven't been set yet, but its scene coordinates are (50, 50), because it is the child of "item". Note that when you specify an item's parent, you don't need to add the child item to the scene; it is implicitly added.