In Graphic scene how to make overlapped object transparent? - qt

In graphics view m setting scene in that adding objects (by dropping ), i can move these items by mouse, when i moved one object on another object moved object should be transparent. how can i make it?

I don't believe you actually want full transparency since it will make it impossible to visually recognize the transparent object later on. Reduced opacity - yes.
As for your question: each item inside your scene has a bounding rectangle (or other type of bounding area). You can easily get it by calling boundingRect() of your item. The returned QRectF has (just like QRect) has the bool QRect::intersects(const QRect &rectangle) const function, which takes another rectangle and checks if a collision is present.
Whenever you move your mouse while dragging an item you need to iterate either through all or just a subset of all items in your scene (by subset I mean just the items in a specific region to increase the performance) and check for collision. If a collision is detected, you can alter either the item you are dragging or the item underneath it.
Of course to make sure that one item covers another one you also need to check the Z value. The easiest way to do that is if you keep all currently not being dragged items at the same Z level and then, whenever you drag one, increase it's Z level by one so that it is "above" the others.

Related

How to easily recognize searched item in a dense QGraphicsScene?

I have a QGraphicsScene with many QGraphicsItem like circle, rectangle, polylines, arc etc.
Every QGraphicsItem has a name. And I have a Search feature which highlights searched items using that name. When scene contains fewer items, highlighted items are seen properly. But when scene contains many items ( 100 + ) then identifying the highlighted item becomes difficult. For that I need to scroll up - down or left - right to check where is that highlighted item is.
So I want my highlighted item to be easily recognizable.
For that I was suggested, some approach like
Take searched item in front
Or
Add some marker
But I do not know, how to implement it , which Qt class should I use etc.
QGraphicsScene displays items depending on their stacking, i.e., when you call .items(), the first item in the QList is the topmost item on the scene.
The ordering of the items is depending on their respective Z-values which you can set for the QGraphicsItem by calling .setZValue()
You can read more about this on the following link: https://doc.qt.io/qt-5/qgraphicsitem.html#sorting
As for your question on how to put them in front. If you implemented your own children classes of QGraphicsItem, you can add a method or a slot to toggle them "on-top". E.g., all of the items usually have a Z-order of 0, so your method could just set it to 1 when the item is highlighted and revert it to 0 when it's not.

How to shift the pixels of part of a QGraphicsItem?

I would like to know whether it is possible to shift part of a drawing by copying its pixels rather than redrawing it.
I work in an embedded environment, where performance is a key factor. We use Qt 4.8.
I have a set of real-time data points that I want to draw. I define the following class:
class SetOfDataPoints : public QGraphicsItem
{
public:
<constructor>
QRectF boundingRect() const { ... }
void paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget = NULL) { ... }
<other methods>
};
At regular intervals, I read a new data point, add it to the instance of SetOfDataPoints, and shift the SetOfDataPoints to the left (by calling QGraphicsItem::moveBy() on the SetOfDataPoints), so the new data point becomes visible. As a result, SetOfDataPoints::paint() gets called, and in that method I have to draw the entire set of data points. The drawing currently consists only of line segments that connect the data points, but will become more elaborate in the future.
Now, it feels inefficient to redraw the whole set of data points, when most of the graph is actually just shifted to the left. I would like to shift the pixels of the unchanged part of the graph to the left, and draw only the one line segment that connects the last two points. At least I would like to try, and measure how much that improves performance.
Is there a way to do that in Qt 4.8?
This won't work in general:
Your item doesn't exist as any pixels until it's rendered. You don't know how many pixels it is drawn on, or even if there are any, since there are 0 or more views your scene is shown on, and the item might be visible to various extent on these views.
There are transformations applied to your item. It doesn't have to be rectangular.
Your item is composited with the items below it, unless it is completely opaque.
Your item, shown on a view, is composited with the backing store of the widget the view is on.
You can optimize for special cases. If your item is not cached, then it's always painted on a view, and the widget argument of paint will point to that widget. You then have direct access to the backing store, and the painter gives you the transformation used to go from item coordinates to the backing store's device coordinates. You can then inspect the path on the widget tree from the view to the window for opacity. If all intervening widgets paint opaque, and your item has an orientation-preserving transformation, you can certainly do a blit on the image, and redraw only a small part of the item.
If your item is cached, it should then be cached in device coordinates. You can do the blitting too, as you're painting on a pixmap. That pixmap is then composited onto the backing store of the window the view is on. There's a separate cache pixmap for each view.
When blitting, you must always recognize how much of the previous pixels are correct. For each view or cache pixmap, you should keep a region that is valid. That region initally should be empty.

What is the meaning of "the item's view geometry and scene geometry will be maintained separately"?

The documentation for the QGraphicsItem::ItemIgnoresTransformations flag says
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. Note: With this flag set you can still scale the item itself, and that scale transformation will influence the item's children.
Of course I have read the QGraphicsItem details, the QGraphicsScene details, the QGraphicsView details, and the Graphics View Framework.
There are also several questions about the ItemIgnoresTransformations flag like Fixed size QGraphicsItems in multiple views?
But I still do not understand the sentence in bold face. What does it mean ?
The problem that rose this concern is described in PyQt: Moving multiple items with different ItemIgnoresTransformations flags, but maybe this question was too long, or too pyqt oriented at first sight. And it was more about moving items. So here I'm trying to better focus.
Imagine situation that parent is rotated 45 degrees or even have some sheer. Since current item ignores this transformation it stays strait (not rotated).
Now ask question how this impacts on item size and position? Parent may maintain geometry of item (for example by using layout) but it doesn't take into account this flag, so some geometry (which is in parent units) will be set but effectively items scene rect may appear different since item ignores transformation and it is not rotated squeezed zoomed as a parent.
So from parent point of view geometry has some value but form scene point of view it is different.
It would be best if you try to see how it works in practice It is hard to describe problem clearly.

Shadow Effects with QGraphicsRectItem in Qt

I have a QGraphicsRectItem over a scene. I intend to drag and drop this window over the scene. When the rect item reaches the left boundary end I have to show it appearing from the right end. Currently I am using two objects and hiding and showing them by calculating the boundary of scene which involves lot of calculations.
Is there any better way to achieve the same effect using just a single object?
Thank You
You could use a single item that spans the entire scene, and draw the rectangle (or 2 parts of it) in it's paint method.
But then you would lose the optimization of the BSP tree, your item would redraw even if some unrelated area repaints. If this is just 1 item, I guess it would not have much impact.
You would need to implement your own dragging with mousemove event and the like, though this is not much code, you just need to get it right.

QGraphicsView background

Hi i'm trying to get a photoshop-like behaviour for my QGraphicsScene
The grid in the background should not resize with the call of scale. And I must be able to save the picture with QPixmap::grabWidget(view) but without the background grid. I can probably do it with removing the background layer just before saving the picture, but i'm not sure if its cleanest way to do it.
Any ideas ?
thx.
Question 1
The grid in the background should not resize with the call of scale.
Use the QGraphicsItem::ItemIgnoresTransformations 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.
In order to set this flag use the setFlag function when creating the grid item.
Question 2
I must be able to save the picture with QPixmap::grabWidget(view) but without the
background grid.
Call the hide function on the grid item before calling the grabWidget. After you have grabbed it you show it again by calling the show function.

Resources