Overlapping labels in Qt fridge magnets example - c++

I want to modify the fridge magnets example provided with Qt in a way that when I drag a label and drop it over another, it will push the label beneath the dragged label to the side, so they will never overlap one another.
I've seen how collision is detected in the colliding mice example, where it uses a QGraphicsScene to draw the QGraphicsItem mice on, and scene()->collidingItems(this) to see which mice are colliding.
The problem is that the fridge magnets example uses a class that inherits QWidget in place of QGraphicsScene, so there's no collidingItems() method to check when we have a collision.
How do I go about doing that?

You can get the location and size of each QWidget from geometry(), which returns a QRect. QRect has function intersects(), which will tell you if it intersects another QRect. After the drop is complete, iterate through all of the labels and check if any of them do intersect the new position.
(This will be easier if you modify dragwidget to keep a QList<DragLabel*> of each label on the dragwidget.)
QRect droppedRect = newLabel->geometry();
foreach(DragLabel* label, dragLabelList)
{
if (droppedRect.intersects(label->geometry())
{
// Add to the list of covered labels that need to be moved.
}
}
The harder part: If there is an intersection, move the old label out of the way.
Maybe try the following algorithm: Move the offending label out of the way in the direction that takes the least movement. Now check it against all the other labels. Any of those that are covered should be moved in the same direction. Repeat until all the labels are uncovered.

Related

Restrict movement area of QGraphicsItem inside of polygon area

I am trying to limit the movement of QGraphicsItem inside of a parent object inherited from QGraphicsPathItem that has an arbitrary complex shape (not square).
As I understand, I should extract each point of the moving object and check whether each of them is not contained in the parent QPainterPath. Then split the parent QPainterPath into small rectangle-shaped polygons and restrict movement area in the bounding box of each sub polygon.
So, I would like to know if there are any other options to exist. Thanks.
Maybe you can check on QGraphicsItem move event if it is still inside QGraphicsPathItem.
The check itself, you can do it with this QGraphicsItem method:
bool QGraphicsItem::collidesWithItem(const QGraphicsItem * other, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape) const
And to be sure that item is still fully enclosed inside its parent, set the mode to Qt::ContainsItemShape
If it is false, return QGraphicsItem to its previous position
EDIT: this check returns if QGraphicsItems shape is inside other QGraphicsItems shape, not its bounding box.

How to enable mouse popup in QtCharts?

I need a small popup be shown when the mouse hovers over series in my QtChart.
Highcharts (Javascript) has some really nice examples like this one:
How can I implement this QtCharts?
I cannot find any documentation on implementing popups.
As far as I know you will have to do it by yourself. I needed exactly the same and used a simple QWidget embedded in a QGraphicsProxyWidget that I added to the QGraphicsScene of the chart view.
QWidget *popup = new MyPopUpWidget;
QChartView v;
QGraphicsProxyWidget *proxy = v.scene()->addWidget(popup);
// if you want a drop shadow you can use QGraphicsDropShadowEffect
QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect();
shadow->setOffset(0, 4);
shadow->setBlurRadius(8);
proxy->setGraphicsEffect(shadow);
While this is nice and simple, the positioning of the popup is the actual work. All the simple solutions weren't good enough for me. For example there are signals if your mouse hits a QGraphicsItem (all line items of your charts are QGraphicsItems) but they are usually to small and you only want to react on the actual data points, not on the line segments.
You can override your mouseMove(QMouseMoveEvent *) function and always check your mouse position against all data points and adjust your popup (show/hide, positioning). If you have many points that will be slow, so I used a spatial grid and assigned data points to grid cells initially. Then you only need to check against points within the grid cells around your mouse position.
I didn't find a better solution.

How can I create a QPushButton with a custom (triangular) shape in Qt 5.5?

How can I create a triangular pushbutton in Qt? What is the most simplest way of executing this? I use the designer to create buttons and not code.
Also, I read somewhere that shapes may be changed as long as the frame of the button is still rectangular but I want the frame to adjust according to the shape as well. How can I achieve this?
More detail: I want to place lots of small triangular buttons next to each other with every other triangle flipped. Each triangle button has it's own function, etc (no overlapping borders accepted). Can anyone give me a descriptive explanation for how I might go about this?
The geometry on a QWidget is always a rectangle.
It would be possible to create a QPushButton derivative, override its paintevent and do some nasty painting considering its neighborhood etc. but it would be really a pain...
it is much easier to use a QGraphicsView, QGraphicsScene and add appropriate QGraphicsItem (maybe the QGraphicsPolygonItem?), add them and use their signals/slots or create a derived class for your purposes.
It is not that hard to override the mouseevents to recognize clicks and you can even use the QStyleSheets to let the "button" look like it gets pressed.

Qt: Custom QGraphicsItem not showing when boundingRect() center is out of view

I'm making a Diagram (Fluxogram) program and for days I'm stuck with this issue:
I have a custom QGraphicsScene that expands horizontally whenever I place an item to it's rightmost area. The problem is that my custom arrows (they inherit QGraphicsPathItem) disappear from the scene whenever it's boundingRect() center is scrolled off the view. Everytime the scene expands, both it's sceneRect() and the view's sceneRect() are updated as well.
I've:
set ui->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate)
the item flags QGraphicsItem::ItemIgnoresTransformations and QGraphicsItem::ItemSendsGeometryChanges, setActive(true) on the item as well, and everytime I add an arrow to the scene i call the update(sceneRect()) method. Still, everytime I scroll the view, as soon as the arrow's boundingRect() center moves away from the view, all the arrow disappears. If I scroll back and the boundingRect() center enters the view, all the arrow appears again.
Can someone give me a tip of what I might be missing? I've been using Qt's example project diagramscene as reference, so a lot of my code is similar (the "press item toolButton -> click on the scene" relation to insert items, the way they place the arrows to connect the objects,...).
In the meanwhile I'll try to make a minimal running example that can show what my issue is.
Your Arrow object inherits from QGraphicsPathItem, which I expect also implements the QGraphicsItem::shape function.
Override the shape function in your Arrow class, to return the shape of the item. This, along with the boundingRect is used to collision detection and detection of an item on-screen.
In addition, before changing the shape of an item by changing its boundingRect, you need to call prepareGeometryChange.
As the docs state: -
Prepares the item for a geometry change. Call this function before changing the bounding rect of an item to keep QGraphicsScene's index up to date.
So, in the Arrow class, store a QRectF called m_boundingRect and in the constructor: -
prepareGeometryChange();
m_boundingRect = QRectF(-x, -y, x*2, y*2);
Then return m_boundingRect in the boundingRect() function.
If this is still an issue, I expect it's something in QGraphicsPainterPath that's causing the problem, in which case, you can simply inherit from QGraphicsItem and store a QPainterPath with which you draw in the item's paint function and also return the painter path in shape().
You are making your life too complicated. Do not subclass QGraphicsPathItem just use it and update its path value every time position of anchors (from to) changes.

qt create simple rectangular board

I want to create a rectangular board using QT. This board will be updated when a step is performed. For example on step x, the text in cell 5,6 updates from "not explored" to "explored".
I have looked through the QT documentation and found the class QGraphicsView. How can i use QGraphicsItem to simulate a cell where text can be written?
I am also open for alternatives.
Technically this could also be done by customizing a QTableView/Widget, but QGraphicsScene is more robust for custom graphics and performance.
From a high level view, you can either create a composite object representing a "Cell" item, or you can subclass a QGraphicsItem and do all the custom painting yourself.
When creating a composite object, that would just be a QGraphicsItem "Cell" subclass which contains maybe a QGraphicsRectItem and a QGraphicsTextItem as members, set to the cell instance as a parent. This will keep the child items translating with the parent cell item.
When creating a completely custom QGraphicsItem, you would define all the painting inside of the paint() method, which would draw a rectangle, and text taken from a value set on the instance.