I have a class, that inherits QGraphicsItem and this class needs to be inherited by another class that inherits QGraphicsLineItem and QGraphicsTextItem. When I do this it gives me the error class Line has no member named setLine
Following is the whole scenerio explained:
getEntity.h
#ifndef getEntity_H
#define getEntity_H
#include <QGraphicsItem>
class getEntity :public QObject , public QGraphicsItem
{
public:
getEntity(QObject* parent=0) : QObject(parent) {}
virtual ~getEntity() {}
virtual getEntity* my_clone() { return 0; }
};
#endif // getEntity_H
line.h
//This is my class that needs to inherits gEntity
#ifndef LINE_H
#define LINE_H
#include <QPainter>
#include <QGraphicsLineItem>
class Line : public QObject, public QGraphicsLineItem
{
Q_OBJECT
public:
Line(int, QPointF, QPointF);
QRectF boundingRect() const;
virtual void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget);
enum { Type = UserType + 2 };
int type() const;
int id;
QPointF start_p, end_p, move_p, check_p;
private:
QVector<QPointF> stuff;
};
#endif // LINE_H
line.cpp
#include "line.h"
Line::Line(int i, QPointF p1, QPointF p2)
{
// assigns id
id = i;
// set values of start point and end point of line
start_p = p1;
end_p = p2;
}
int Line::type() const
{
// Enable the use of qgraphicsitem_cast with line item.
return Type;
}
QRectF Line::boundingRect() const
{
qreal extra = 1.0;
// bounding rectangle for line
return QRectF(line().p1(), QSizeF(line().p2().x() - line().p1().x(),
line().p2().y() - line().p1().y()))
.normalized()
.adjusted(-extra, -extra, extra, extra);
}
void Line::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
// draws/paints the path of line
QPen paintpen;
painter->setRenderHint(QPainter::Antialiasing);
paintpen.setWidth(1);
if (isSelected())
{
// sets brush for end points
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::red);
painter->setPen(paintpen);
painter->drawEllipse(start_p, 2, 2);
painter->drawEllipse(end_p, 2, 2);
// sets pen for line path
paintpen.setStyle(Qt::DashLine);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawLine(start_p, end_p);
}
else
{ painter->save();
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawEllipse(start_p, 2, 2);
painter->drawEllipse(end_p, 2, 2);
painter->drawLine(start_p, end_p);
painter->restore();
}
}
cadgraphicscene.cpp
//Here it returns pointing to setLine method, when I inherit getEntity in Line class
if (mPaintFlag)
{
lineItem = new Line(++id, start_p, end_p);
lineItem->setLine(start_p.x(), start_p.y(), end_p.x(), end_p.y());
How the Line class can correctly inherit getEntity? Do help!
Related
I am having issues with a weird bug which occurs after you adjust the size of a QGraphicsItem.
Here is a YouTube video showing the issue: https://youtu.be/gp1lQTkPf54
In my application, a slider is used to adjust the horizontal zoom of all the regions on the QGraphicsScene. I have made sure to call prepareGeometryChange(); when I am changing the geometry of a region and call update(); but that has not helped. It seems to affect regions that are being rendered out of view from the user.
Code:
mainwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene *scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
RegionGraphicsItem *rgi = new RegionGraphicsItem(ui->graphicsView->scene());
itemList.append(rgi);
ui->graphicsView->scene()->addItem(rgi);
rgi->setHScaleFactor(ui->horizontalSlider->value());
}
void MainWindow::test() {
QWidget test;
test.show();
}
void MainWindow::on_horizontalSlider_valueChanged(int value)
{
for (int i = 0; i < itemList.size(); i++) {
itemList[i]->setHScaleFactor(value);
}
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "regiongraphicsitem.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QList<RegionGraphicsItem*> itemList;
private slots:
void on_pushButton_clicked();
void on_horizontalSlider_valueChanged(int value);
private:
void test();
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
regiongraphicsitem.cpp
#include "regiongraphicsitem.h"
RegionGraphicsItem::RegionGraphicsItem(QGraphicsScene *_scene) : QGraphicsItem()
{
regionColor = QColor::fromRgb(255,255,255);
setFlags(ItemIsMovable);
waveFormColor = regionColor.darker(80);
outlineColor = QColor("#0f0f0f");
selectedColor = selectedColor.lighter(30);
hScaleFactor = 100;
mainBrush = QBrush(regionColor);
mainPen = QPen(outlineColor, 1);
gridLength = 5;
height = 56;
oldPos = pos();
scene = _scene;
this->prepareGeometryChange();
gridLocation = 5;
setY((0 * 60) + 1);
}
QRectF RegionGraphicsItem::boundingRect() const
{
return QRectF(0, 0, float(gridLength * hScaleFactor), float(height));
}
void RegionGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);
QRectF rect = boundingRect();
painter->setBrush(mainBrush);
painter->setPen(mainPen);
painter->drawRoundedRect(rect, 5, 5);
painter->setPen(mainPen);
if (selected) {
painter->setBrush(QBrush(mainPen.color()));
painter->drawRoundedRect(QRect(rect.x(), rect.y(), rect.width(), 20), 5, 5);
painter->drawRect(QRect(rect.x(), rect.y() + 5, rect.width(), 15));
}
QFont font = scene->font();
font.setPixelSize(10);
font.setBold(true);
QFontMetricsF fontMetrics(font);
QString text = "TEST";
int heightFont = fontMetrics.boundingRect(text).height();
if (selected) {
painter->setPen(QPen(mainBrush.color(), 1));
}
painter->drawText(5, heightFont + 3, text);
if (pressed == false ) {
setX((gridLocation - 1) * hScaleFactor);
}
}
void RegionGraphicsItem::setHScaleFactor(int value) {
prepareGeometryChange();
hScaleFactor = value;
update();
}
regiongraphicsitem.h
#ifndef RegionGraphicsItem_H
#define RegionGraphicsItem_H
#include <QGraphicsItem>
#include <QColor>
#include <QBrush>
#include <QPen>
#include <QtGui/QPainter>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include <stdint.h>
class RegionGraphicsItem : public QGraphicsItem
{
public:
RegionGraphicsItem(QGraphicsScene *_scene);
float getGridLocation();
void setHScaleFactor(int value);
protected:
QColor outlineColor;
QColor selectedColor;
QColor regionColor;
QColor waveFormColor;
bool selected;
int penWidth;
int rounded;
QBrush mainBrush;
QBrush waveformBrush;
QPen mainPen;
int height;
float gridLength;
bool pressed = false;
QPointF oldPos, oldMousePos;
int oldTrackIndex;
float gridLocation;
QGraphicsScene *scene;
int oldHScaleFactor;
virtual QRectF boundingRect() const override;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
private:
int hScaleFactor;
};
#endif // RegionGraphicsItem_H
Steps to reproduce:
Add a RegionGraphicItem to the QGraphicsScene
Increase the slider until the region is off screen
Decrease the slider and the region will not be visible. <-- This is the issue.
I have a scene with a 12*4 grid with blocks of QGraphicsItems ,when i right click on the blocks I have a contexmenu that
can add icons inside the blocks my proplem is that
I can't fingure out how can I make those icons draggable to the other blocks inside the graphic scene ,I know there is the "Draggable Icons Example" but how can I implement that code to a graphic scene.
this is the mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsPathItem>
class QGraphicsSceneMouseEvent;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
bool eventFilter(QObject *, QEvent *);
~MainWindow();
private slots:
void showContextMenu(const QPoint&);
void addPixBlock();
private:
Ui::MainWindow *ui;
QGraphicsScene *scene;
QGraphicsItem *itemAt(const QPointF&);
int x;
int y;
QMenu *Menu;
QMenu *Submenu;
QAction *Picture;
QGraphicsPixmapItem* pix;
};
#endif // MAINWINDOW_H
the mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "block.h"
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
#include <QPainter>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene(this) ;
for(int row=-4;row<8;++row)
for(int column=0;column<4;++column)
{
Block *b = new Block;
scene->addItem(b);
b->setPos(row* 95,column*85);
}
ui->graphicsView->setScene(scene);
scene->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
QGraphicsItem* MainWindow::itemAt(const QPointF &pos)
{
QList<QGraphicsItem*> items = scene->items(QRectF(pos - QPointF(1,1),
QSize(3,3)));
foreach(QGraphicsItem *item, items)
if (item->type() > QGraphicsItem::UserType)
return item;
return 0;
}
bool MainWindow::eventFilter(QObject *o, QEvent *e)
{
QGraphicsSceneMouseEvent *me = (QGraphicsSceneMouseEvent*) e;
switch ((int) e->type()){
case QEvent::GraphicsSceneMousePress:{
switch ((int) me->button()){
case Qt::RightButton:{
QGraphicsItem *item = itemAt(me->scenePos());
if (item && item->type() == Block::Type){
x=item->scenePos().x();
y=item->scenePos().y();
showContextMenu(item->scenePos().toPoint());
}
break;
}
}
break;
}
}
return QObject::eventFilter(o, e);
}
void MainWindow::showContextMenu(const QPoint &pos)
{
Menu= new QMenu("Menu");
Submenu=Menu->addMenu(QIcon(":/img/pix.png"),"Pix");
Picture =Submenu->addAction(QIcon(":/img/pix.png"),"Pix");
connect(Picture, SIGNAL(triggered()), this, SLOT(addPixBlock()));
Menu->exec(QCursor::pos());
}
void MainWindow::addPixBlock()
{
QPixmap pixmap(":/img/pix.png");
pix = scene->addPixmap(pixmap.scaled(70,50));
pix->setPos(x,y);
}
the block.h
#ifndef BLOCK_H
#define BLOCK_H
#include <QGraphicsPathItem>
class QGraphicsSceneMouseEvent;
class Block : public QGraphicsPathItem
{
public:
enum { Type = QGraphicsItem::UserType + 3 };
int type() const { return Type; }
Block(QGraphicsItem *parent = 0);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget
*widget);
bool eventFilter(QObject *, QEvent *);
};
#endif // BLOCK_H
the Block.cpp
#include "block.h"
#include <QPainter>
#include <QtWidgets>
class QGraphicsSceneMouseEvent;
Block::Block(QGraphicsItem *parent)
: QGraphicsPathItem(parent)
{
QPainterPath p;
//<->,|,<->,|,roundness
p.addRoundedRect(0,0,80,50, 5, 5);
setPath(p);
setAcceptDrops(true);
setAcceptedMouseButtons(Qt::LeftButton);
}
void Block::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
painter->setPen(QPen(QColor(67, 141, 220)));
painter->setBrush(QColor(67, 141, 220,100));
painter->drawPath(path());
}
First of all if you want to place a QGraphicsPixmapItem on top of another item, a better option is to set it as your parentItem.
On the other hand we can use an event filter but a better option in this case is to implement a custom QGraphicsScene, and when pressing with the left key it allows to drag the item, for that we use QDrag and we pass the data of the item, then we overwrite the event dropEvent where we will obtain the item and establish a new parent.
graphicsscene.h
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
class QMenu;
class QAction;
class GraphicsScene : public QGraphicsScene
{
public:
using QGraphicsScene::QGraphicsScene;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void dropEvent(QGraphicsSceneDragDropEvent *event) override;
private:
QGraphicsPixmapItem *findPixmapItem(QGraphicsItem *item);
void createDrag(const QPointF &pos, QWidget *widget, QGraphicsItem *item);
void showContextMenu(const QPointF &pos);
void addPixBlock(QGraphicsItem *item);
QMenu *menu;
QMenu *submenu;
QAction *picture;
QGraphicsPixmapItem *pix;
};
#endif // GRAPHICSSCENE_H
graphicsscene.cpp
#include "graphicsscene.h"
#include <QDrag>
#include <QGraphicsItem>
#include <QGraphicsSceneMouseEvent>
#include <QMenu>
#include <QMimeData>
#include <QWidget>
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
auto its = items(QRectF(event->scenePos() - QPointF(1,1), QSize(3,3)));
auto val = std::find_if(its.constBegin(), its.constEnd(), [](auto const& it){
return it->type() > QGraphicsItem::UserType;
});
if(val == its.constEnd())
return;
if(event->button() == Qt::RightButton){
showContextMenu(event->scenePos());
}
else{
createDrag(event->scenePos(), event->widget(), *val);
}
}
void GraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
{
QByteArray byteArray = event->mimeData()->data("Item");
QGraphicsPixmapItem * item = *reinterpret_cast<QGraphicsPixmapItem**>(byteArray.data());
QGraphicsItem *item_parent = itemAt(event->scenePos(), QTransform());
item->setParentItem(item_parent);
}
QGraphicsPixmapItem *GraphicsScene::findPixmapItem(QGraphicsItem *item){
auto chs = item->childItems();
auto val = std::find_if(chs.constBegin(), chs.constEnd(), [](auto const& it){
return static_cast<QGraphicsPixmapItem *>(it) != Q_NULLPTR;
});
return val == chs.constEnd() ? Q_NULLPTR : static_cast<QGraphicsPixmapItem *>(*val);
}
void GraphicsScene::createDrag(const QPointF &pos, QWidget *widget, QGraphicsItem *item){
QGraphicsPixmapItem *pix = findPixmapItem(item);
if(pix == Q_NULLPTR)
return;
QByteArray byteArray(reinterpret_cast<char*>(&pix),sizeof(QGraphicsPixmapItem*));
QDrag *drag = new QDrag(widget);
QMimeData * mimeData = new QMimeData;
mimeData->setData("Item",byteArray);
drag->setMimeData(mimeData);
drag->setHotSpot(pos.toPoint()-pix->scenePos().toPoint());
drag->setPixmap(pix->pixmap());
drag->start();
}
void GraphicsScene::showContextMenu(const QPointF &pos)
{
QGraphicsItem *item = itemAt(pos, QTransform());
menu= new QMenu("Menu");
submenu = menu->addMenu(QIcon(":/img/pix.png"),"Pix");
picture = submenu->addAction(QIcon(":/img/pix.png"),"Pix");
connect(picture, &QAction::triggered, [item, this](){
addPixBlock(item);
});
menu->exec(QCursor::pos());
}
void GraphicsScene::addPixBlock(QGraphicsItem *item)
{
if(findPixmapItem(item))
return;
QPixmap pixmap(":/img/pix.png");
pix = addPixmap(pixmap.scaled(70,50));
if(pix->parentItem() != item)
pix->setParentItem(item);
}
Then we establish that new scene and add the Blocks.
The complete example can be found in the following link
I want to implement arc in QGraphicsScene. I want that on clicking of three points my arc should be drawn such that on clicking of three points arc is drawn where first point will be starting of arc, second will be any point on arc and third will be end point of arc. I have tried studing drawArc function but got confused with startangle and spanangle. I was unable to set them dynamically. Please suggest me some way to proceed.
I tried the solution to embend it in my project but got the following error:
error: cannot allocate an object of abstract type 'arc'
arcItem = new arc(++id, startP, midP, endP);
Can you please help me out to solve the problem. I am giving a part of code to my project.
In mousepress event of cadgraphicsscene I have done following thing.
cadgraphicsscene.cpp
void CadGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
// mousePressEvent in the graphicsScene
if(mouseEvent->button() == Qt::LeftButton)
{
switch (entityMode)
{
case ArcMode:
if (mFirstClick)
{
startP = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = true;
}
else if (!mFirstClick && mSecondClick)
{
midP = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = false;
mThirdClick = true;
}
else if (!mSecondClick && mThirdClick)
{
endP = mouseEvent->scenePos();
mThirdClick = false;
mPaintFlag = true;
}
if (mPaintFlag)
{
arcItem = new arc(++id, startP, midP, endP);
itemList.append(arcItem);
mUndoStack->push(new CadCommandAdd(this, arcItem));
setFlags();
}
}
}
}
arc.cpp
#include "arc.h"
arc::arc(int i, QPointF point1, QPointF point2, QPointF point3)
{
// assigns id
id = i;
p1 = point1;
p2 = point2;
p3 = point3;
lineBC(point2, point3);
lineAC(point1, point3);
lineBA(point2, point1);
rad = qAbs(lineBC.length()/(2*qSin(qDegreesToRadians(lineAC.angleTo(lineBA)))));
bisectorBC(lineBC.pointAt(0.5), lineBC.p2());
bisectorBC.setAngle(lineBC.normalVector().angle());
bisectorBA(lineBA.pointAt(0.5), lineBA.p2());
bisectorBA.setAngle(lineBA.normalVector().angle());
bisectorBA.intersect(bisectorBC, ¢er);
ellipse = new QGraphicsEllipseItem(center.x() - rad, center.y() - rad, rad*2, rad*2);
lineOA(center, point1);
lineOC(center, point3);
}
arc::arc(int i, QLineF start, QLineF end)
{
// assigns id
id = i;
lineOA.angle() = start;
lineOC.angle() - lineOA.angle() = end;
}
int arc::type() const
{
// Enable the use of qgraphicsitem_cast with arc item.
return Type;
}
void arc::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
QPen paintpen;
painter->setRenderHint(QPainter::Antialiasing);
paintpen.setWidth(1);
if (isSelected())
{
// sets brush for end points
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::red);
painter->setPen(paintpen);
paintpen.setStyle(Qt::DashLine);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawArc(ellipse->boundingRect(),lineOA.angle(),lineOC.angle() - lineOA.angle());
}
else
{
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawArc(ellipse->boundingRect(),lineOA.angle(),lineOC.angle() - lineOA.angle());
}
}
arc.h
include <QGraphicsItem>
#include "qmath.h"
class arc : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
arc(int, QPointF, QPointF, QPointF);
arc(int, QLineF, QLineF);
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget);
enum { Type = UserType + 6 };
int type() const;
int id;
QPointF startP, midP, endP, p1, p2, p3,center;
QLineF lineBC;
QLineF lineAC;
QLineF lineBA;
QLineF lineOA;
QLineF lineOC;
QLineF bisectorBC;
QLineF bisectorBA;
QGraphicsEllipseItem *ellipse;
qreal rad;
private:
QVector<QPointF> stuff;
};
#endif // ARC_H
Please help me out to solve the error.
This sounds like it could be solved with some relatively simple math:
https://www.google.com/search?q=define%20circle%20three%20points
https://math.stackexchange.com/a/213678
https://www.khanacademy.org/math/geometry/triangle-properties/perpendicular_bisectors/v/three-points-defining-a-circle
Here is my translation of the math into Qt goodness
// m_points is a QList<QPointF>
// use math to define the circle
QLineF lineBC(m_points.at(1), m_points.at(2));
QLineF lineAC(m_points.at(0), m_points.at(2));
QLineF lineBA(m_points.at(1), m_points.at(0));
qreal rad = qAbs(lineBC.length()/(2*qSin(qDegreesToRadians(lineAC.angleTo(lineBA)))));
QLineF bisectorBC(lineBC.pointAt(0.5), lineBC.p2());
bisectorBC.setAngle(lineBC.normalVector().angle());
QLineF bisectorBA(lineBA.pointAt(0.5), lineBA.p2());
bisectorBA.setAngle(lineBA.normalVector().angle());
QPointF center;
bisectorBA.intersect(bisectorBC, ¢er);
qDebug() << rad << center;
QT QGraphicsScene Drawing Arc
QPainterPath* path = new QPainterPath();
path->arcMoveTo(0,0,50,50,20);
path->arcTo(0,0,50,50,20, 90);
scene.addPath(*path);
Putting all of this together into a nice little project turns into this:
https://github.com/peteristhegreat/ThreePointsCircle
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QGraphicsView>
#include <QGraphicsScene>
#include "graphicsscene.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QGraphicsView * view = new QGraphicsView;
GraphicsScene * scene = new GraphicsScene();
view->setScene(scene);
view->setSceneRect(-300,-300, 300, 300);
this->resize(600, 600);
this->setCentralWidget(view);
}
MainWindow::~MainWindow()
{
}
graphicsscene.h
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPointF>
#include <QList>
class GraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit GraphicsScene(QObject *parent = 0);
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent);
virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent);
signals:
public slots:
private:
QList <QPointF> m_points;
};
#endif // GRAPHICSSCENE_H
graphicsscene.cpp
#include "graphicsscene.h"
#include <QDebug>
#include <QGraphicsEllipseItem>
#include <QGraphicsPathItem>
#include <QPainterPath>
#include "qmath.h"
GraphicsScene::GraphicsScene(QObject *parent) :
QGraphicsScene(parent)
{
this->setBackgroundBrush(Qt::gray);
}
void GraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
qDebug() << Q_FUNC_INFO << mouseEvent->scenePos();
QGraphicsScene::mouseDoubleClickEvent(mouseEvent);
}
void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
qDebug() << Q_FUNC_INFO << mouseEvent->scenePos();
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
qDebug() << Q_FUNC_INFO << mouseEvent->scenePos();
QGraphicsScene::mousePressEvent(mouseEvent);
}
void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * me)
{
qDebug() << Q_FUNC_INFO << me->scenePos();
int radius = 20;
QGraphicsEllipseItem * ellipse = this->addEllipse(me->scenePos().x() - radius, me->scenePos().y() - radius, radius*2, radius*2);
ellipse->setBrush(Qt::white);
m_points.append(me->scenePos());
if(m_points.size() == 3)
{
// use math to define the circle
QLineF lineBC(m_points.at(1), m_points.at(2));
QLineF lineAC(m_points.at(0), m_points.at(2));
QLineF lineBA(m_points.at(1), m_points.at(0));
qreal rad = qAbs(lineBC.length()/(2*qSin(qDegreesToRadians(lineAC.angleTo(lineBA)))));
QLineF bisectorBC(lineBC.pointAt(0.5), lineBC.p2());
bisectorBC.setAngle(lineBC.normalVector().angle());
QLineF bisectorBA(lineBA.pointAt(0.5), lineBA.p2());
bisectorBA.setAngle(lineBA.normalVector().angle());
QPointF center;
bisectorBA.intersect(bisectorBC, ¢er);
qDebug() << rad << center;
bool drawCircle = true;
QGraphicsEllipseItem * ellipse = new QGraphicsEllipseItem(center.x() - rad, center.y() - rad, rad*2, rad*2);
if(drawCircle)
this->addItem(ellipse);
// add arc
// this->addItem(path);
QPainterPath path;
QLineF lineOA(center, m_points.at(0));
QLineF lineOC(center, m_points.at(2));
path.arcMoveTo(ellipse->boundingRect(),lineOA.angle());
path.arcTo(ellipse->boundingRect(), lineOA.angle(), lineOC.angle() - lineOA.angle());
QGraphicsPathItem * pathItem = new QGraphicsPathItem(path);
pathItem->setPen(QPen(Qt::red,10));
this->addItem(pathItem);
if(!drawCircle)
delete ellipse;
m_points.clear();
}
QGraphicsScene::mouseReleaseEvent(me);
}
A Subclass of QGraphicsItem, that takes 3 points, and intersects the three with an arc of a circle. The second point is always in the middle. (Selectablity and other properties haven't been fully implemented or tested).
Note: Qt Creator includes more advanced examples of subclassed QGraphicsItems such as Colliding Mice, and 40,000 chips examples.
http://qt-project.org/doc/qt-5/examples-graphicsview.html
Also to enable QObject signals and slots and properties from a QGraphicsItem, you should use QGraphicsObject.
Note: added onto github here.
arcgraphicsitem.h
#ifndef ARCGRAPHICSITEM_H
#define ARCGRAPHICSITEM_H
#include <QGraphicsItem>
#include <QLineF>
#include <QPointF>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QWidget>
class ArcGraphicsItem : public QGraphicsItem
{
public:
ArcGraphicsItem();
ArcGraphicsItem(int i, QPointF point0, QPointF point1, QPointF point2);
~ArcGraphicsItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
int type() const { return Type;}
int id() {return m_id;}
QPainterPath shape() const;
protected:
private:
void init();
enum { Type = UserType + 6 };
int m_id;
QPointF startP, midP, endP, p1, p2, p3, center;
QLineF lineBC;
QLineF lineAC;
QLineF lineBA;
QLineF lineOA;
QLineF lineOB;
QLineF lineOC;
QLineF bisectorBC;
QLineF bisectorBA;
qreal startAngle;
qreal spanAngle;
QRectF circle;
QRectF boundingRectTemp;
qreal rad;
};
#endif // ARCGRAPHICSITEM_H
arcgraphicsitem.cpp
#include "arcgraphicsitem.h"
#include "qmath.h"
#include <QPen>
#include <QDebug>
#include <QPainterPath>
ArcGraphicsItem::ArcGraphicsItem(int i,
QPointF point1,
QPointF point2,
QPointF point3)
: m_id(i), p1(point1), p2(point2), p3(point3)
{
init();
}
ArcGraphicsItem::ArcGraphicsItem()
{
p1 = QPointF(0,0);
p2 = QPointF(0,1);
p3 = QPointF(1,1);
m_id = -1;
init();
}
ArcGraphicsItem::~ArcGraphicsItem()
{
}
void ArcGraphicsItem::init()
{
lineBC = QLineF(p2, p3);
lineAC = QLineF(p1, p3);
lineBA = QLineF(p2, p1);
rad = qAbs(lineBC.length()/(2*qSin(qDegreesToRadians(lineAC.angleTo(lineBA)))));
bisectorBC = QLineF(lineBC.pointAt(0.5), lineBC.p2());
bisectorBC.setAngle(lineBC.normalVector().angle());
bisectorBA = QLineF(lineBA.pointAt(0.5), lineBA.p2());
bisectorBA.setAngle(lineBA.normalVector().angle());
bisectorBA.intersect(bisectorBC, ¢er);
circle = QRectF(center.x() - rad, center.y() - rad, rad*2, rad*2);
lineOA = QLineF(center, p1);
lineOB = QLineF(center, p2);
lineOC = QLineF(center, p3);
startAngle = lineOA.angle();
spanAngle = lineOA.angleTo(lineOC);
// Make sure that the span angle covers all three points with the second point in the middle
if(qAbs(spanAngle) < qAbs(lineOA.angleTo(lineOB)) || qAbs(spanAngle) < qAbs(lineOB.angleTo(lineOC)))
{
// swap the end point and invert the spanAngle
startAngle = lineOC.angle();
spanAngle = 360 - spanAngle;
}
int w = 10;
boundingRectTemp = circle.adjusted(-w, -w, w, w);
}
QRectF ArcGraphicsItem::boundingRect() const
{
// outer most edges
return boundingRectTemp;
}
void ArcGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QPen paintpen;
painter->setRenderHint(QPainter::Antialiasing);
paintpen.setWidth(1);
// Draw arc
if(isSelected())
{
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
}
else
{
paintpen.setStyle(Qt::DashLine);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
}
QPainterPath path;
path.arcMoveTo(circle,startAngle);
path.arcTo(circle, startAngle, spanAngle);
// Draw points
if (isSelected())
{
// sets brush for end points
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::red);
painter->setPen(paintpen);
qreal ptRad = 10;
painter->drawEllipse(p1, ptRad, ptRad);
painter->drawEllipse(p2, ptRad, ptRad);
painter->drawEllipse(p3, ptRad, ptRad);
}
painter->setBrush(Qt::NoBrush);
painter->drawPath(path);
}
QPainterPath ArcGraphicsItem::shape() const
{
QPainterPath path;
path.arcMoveTo(circle,startAngle);
path.arcTo(circle, startAngle, spanAngle);
return path;
}
Hope that helps
I'm using QGraphicView to show game map that consist QGraphicsPixmapItems. I need to show tooltip on mouse hover at QGraphicsPixmapItem.
For saving QGraphicsPixmapItem position I using MazeItem:
#ifndef MAZEITEM_H
#define MAZEITEM_H
#include <QPoint>
#include <QGraphicsItem>
class MazeItem
{
private:
QPoint myPosition;
QString myToolTip;
public:
MazeItem();
QPoint position() const;
QString toolTip() const;
void setToolTip(const QString &toolTip);
void setPosition(const QPoint &position);
QPoint getPosition();
QGraphicsPixmapItem * pixmap;
};
#endif // MAZEITEM_H
I have widget class to display game map:
#include <QWidget>
#include <QtGui>
#include <QGraphicsView>
#include <QToolTip>
#include "mazeitem.h"
class MazeGUI : public QWidget
{
Q_OBJECT
private:
QGraphicsView * graphicsView;
QGraphicsScene * graphicsScene;
QString sceneString;
int imageSize;
QList<MazeItem> mazeItems;
void addItem(int x, int y, QPixmap picture);
bool event(QEvent *event);
int itemAt(const QPoint &pos);
public:
explicit MazeGUI(QWidget *parent = 0);
void setScene(QString sceneString);
signals:
public slots:
void redraw();
};
#endif // MAZEGUI_H
In constructor I set mouse tracking.
MazeGUI::MazeGUI(QWidget *parent) :
QWidget(parent)
{
setMouseTracking(true);
...
}
This is how I add new maze item.
void MazeGUI::addItem(int x, int y, QPixmap picture)
{
MazeItem mazeItem;
mazeItem.setPosition(QPoint(x, y));
mazeItem.setToolTip("text");
mazeItem.pixmap = this->graphicsScene->addPixmap(picture);
mazeItem.pixmap->setPos(y, x);
mazeItems.append(mazeItem);
}
And this I have from Qt tutorials,
bool MazeGUI::event(QEvent *event)
{
if (event->type() == QEvent::ToolTip) {
// HERE - it never goes here!!
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
int index = itemAt(helpEvent->pos());
if (index != -1) {
QToolTip::showText(helpEvent->globalPos(), mazeItems[index].toolTip());
} else {
QToolTip::hideText();
event->ignore();
}
return true;
}
return QWidget::event(event);
}
int MazeGUI::itemAt(const QPoint &pos)
{
for (int i=0; i < mazeItems.size(); ++i)
{
if (mazeItems[i].getPosition() == pos)
return i;
}
return -1;
}
Was adding the tooltip on wrong object:
Instead of:
mazeItem.setToolTip("text");
It should be:
mazeItem.pixmap->setToolTip("text");
How exactly can I subclass QGraphicsLayoutItem?
I write a class that subclass QGraphicsLayoutItem and reimplement sizeHint and setGeometry but when I add my custom item to linear or grid layout. It does not shown?
What is missing?
Here is my trial.
//basicitem.h
#include <QGraphicsWidget>
#include <QtCore/QRectF>
#include <QtGui/QPainter>
#include <QtGui/QBrush>
#include <QtGui/QPen>
#include <QtCore/QSizeF>
class BasicItem : public QGraphicsWidget
{
public:
BasicItem(qreal x1,qreal y1,qreal x2,qreal y2);
~BasicItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
private:
qreal x1,y1,x2,y2;
};
//basicitem.cpp
#include "basicitem.h"
#include <math.h>
BasicItem::BasicItem(qreal x1, qreal y1, qreal x2, qreal y2)
{
this->x1 = x1;
this->y1 = y1;
this->x2 = x2;
this->y2 = y2;
}
BasicItem::~BasicItem()
{
}
QRectF BasicItem::boundingRect() const
{
return QRectF(x1,y1,abs(x2-x1),5);
}
void BasicItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(QPen(QBrush(Qt::yellow),4,Qt::SolidLine,Qt::FlatCap,Qt::BevelJoin));
painter->drawLine(x1,y1,x2,y2);
}
QSizeF BasicItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(which);
Q_UNUSED(constraint);
return QSizeF(abs(x2-x1),5);
}
//compositeitem.h
#include <QGraphicsItemGroup>
#include <QGraphicsLayoutItem>
#include <QSizeF>
#include <QList>
#include "basicitem.h"
class CompositeItem:public QGraphicsItemGroup,public QGraphicsLayoutItem
{
public: CompositeItem(QList<BasicItem *> children);
~CompositeItem();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
void setGeometry(const QRectF &rect);
void updateGeometry();
};
//compositeitem.cpp
#include "compositeitem.h"
CompositeItem::CompositeItem(QList<BasicItem *> children)
{
BasicItem *child;
foreach(child,children)
{
addToGroup(child);
}
}
CompositeItem::~CompositeItem()
{
}
QSizeF CompositeItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(which);
Q_UNUSED(constraint);
//Arbitrary values but big enough
return QSizeF(300,300);
}
void CompositeItem::setGeometry(const QRectF &rect)
{
Q_UNUSED(rect);
QGraphicsLayoutItem::setGeometry(QRectF(0,0,300,300));
}
void CompositeItem::updateGeometry()
{
QGraphicsLayoutItem::updateGeometry();
}
//mainwindow.cpp - important parts
...
QGraphicsScene *scene = new QGraphicsScene;
ui->graphicsView->setScene(scene);
BasicItem *basic1 = new BasicItem(10,400,110,400);
BasicItem *basic2 = new BasicItem(10,400,110,500);
QList<BasicItem *> basicItemList;
basicItemList.push_back(basic1);
basicItemList.push_back(basic2);
CompositeItem *ci = new CompositeItem(basicItemList);
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout;
layout->addItem(ci);
QGraphicsWidget *container = new QGraphicsWidget;
container->setLayout(layout);
scene->addItem(container);
...
May be it will be useful, just a small example from my working project:
GraphicsLayoutItem::GraphicsLayoutItem( QGraphicsItem *parent ) :
QGraphicsItemGroup(parent),
QGraphicsLayoutItem(),
{
addToGroup(item_);
addToGroup(text_item_);
setGraphicsItem(this);
}
GraphicsLayoutItem::~GraphicsLayoutItem()
{
removeFromGroup( item_ );
removeFromGroup( text_item_ );
delete item_;
delete text_item_;
setGraphicsItem(0);
}
void GraphicsLayoutItem::setGeometry( const QRectF &r )
{
prepareGeometryChange();
QGraphicsLayoutItem::setGeometry(r);
setPos(r.topLeft());
}
QRectF GraphicsLayoutItem::boundingRect() const
{
return QRectF(QPointF(0, 0), geometry().size());
}
QSizeF GraphicsLayoutItem::sizeHint( Qt::SizeHint which, const QSizeF &constraint )
const
{
switch ( which )
{
case Qt::MinimumSize:
case Qt::PreferredSize:
return this->boundingRect().size();
case Qt::MaximumSize:
return QSizeF(parentItem()->boundingRect().width(),
MyOptions::DefaultHeight);
default:
return this->boundingRect().size();
}
return constraint;
}