I have two QGraphicsPixmapItem
added to my QGraphicsScene
.
Now I want to add a QLine
connecting both of this QGraphicsPixmapItem
and should be able to move around with QLine
stretching like graph.
I have looked into this Elastic Nodes Example, but it's too complicated for me.
based on this: How to use itemChange from QGraphicsItem in Qt, I was able to solve my problem except I am struggling to replace QGraphicsEllipseItem
with QGraphicsPixmapItem
because of rect argument, which is needed in another function for calculating position.
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsEllipseItem>
#include <QGraphicsLineItem>
class CustomElipse : public QGraphicsEllipseItem
{
public:
CustomElipse (const QRectF& rect) : QGraphicsEllipseItem(rect) {
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
}
void addLine(QGraphicsLineItem *line, bool isPoint1) {
this->line = line;
isP1 = isPoint1;
}
QVariant itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionChange && scene()) {
// value is the new position.
QPointF newPos = value.toPointF();
moveLineToCenter(newPos);
}
return QGraphicsItem::itemChange(change, value);
}
void moveLineToCenter(QPointF newPos) {
// Converts the elipse position (top-left)
// to its center position
int xOffset = rect().x() + rect().width()/2;
int yOffset = rect().y() + rect().height()/2;
QPointF newCenterPos = QPointF(newPos.x() + xOffset, newPos.y() + yOffset);
// Move the required point of the line to the center of the elipse
QPointF p1 = isP1 ? newCenterPos : line->line().p1();
QPointF p2 = isP1 ? line->line().p2() : newCenterPos;
line->setLine(QLineF(p1, p2));
}
private:
QGraphicsLineItem *line;
bool isP1;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
CustomElipse *elipse1 = new CustomElipse(QRectF(30, 30, 15, 25));
scene.addItem(elipse1);
CustomElipse *elipse2 = new CustomElipse(QRectF(70, 70, 25, 15));
scene.addItem(elipse2);
QGraphicsLineItem *line = scene.addLine(QLineF(40, 40, 80, 80));
elipse1->addLine(line, true);
elipse2->addLine(line, false);
QGraphicsView view(&scene);
view.show();
return a.exec();
}
From the Qt Documentation of QGraphicsPixmapItem:
The QGraphicsPixmapItem class provides a pixmap item that you can add to a QGraphicsScene.
Here's an example with comments on the changes I made:
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include <QGraphicsLineItem>
#include <QPixmap>
class CustomElipse : public QGraphicsPixmapItem
{
public:
//Use a QPixmap instead of QRect
CustomElipse (const QPixmap& pixmap) : QGraphicsPixmapItem(pixmap)
{
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
}
void addLine(QGraphicsLineItem *line, bool isPoint1)
{
this->line = line;
isP1 = isPoint1;
}
QVariant itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionChange && scene())
{
// value is the new position.
QPointF newPos = value.toPointF();
moveLineToCenter(newPos);
}
return QGraphicsItem::itemChange(change, value);
}
void moveLineToCenter(QPointF newPos)
{
// Converts the elipse position (top-left)
// to its center position
//use pixmap's rect to calculate the offset
int xOffset = pixmap().rect().x() + pixmap().width()/2;
int yOffset = pixmap().rect().y() + pixmap().height()/2;
QPointF newCenterPos = QPointF(newPos.x() + xOffset, newPos.y() + yOffset);
// Move the required point of the line to the center of the elipse
QPointF p1 = isP1 ? newCenterPos : line->line().p1();
QPointF p2 = isP1 ? line->line().p2() : newCenterPos;
line->setLine(QLineF(p1, p2));
}
private:
QGraphicsLineItem *line;
bool isP1;
};
int main(int argc,char*argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
//I used an image of a green circle to test it
CustomElipse *elipse1 = new CustomElipse(QPixmap(":green.png"));
scene.addItem(elipse1);
CustomElipse *elipse2 = new CustomElipse(QPixmap(":green.png"));
scene.addItem(elipse2);
QGraphicsLineItem *line = scene.addLine(QLineF(40, 40, 80, 80));
elipse1->addLine(line, true);
elipse2->addLine(line, false);
QGraphicsView view(&scene);
view.show();
return a.exec();
}
Here's the result: