QGraphicsSceneMouseEvent is not called - c++

When I click on my scene - nothing happens. I tried many various methods with QMouseEvent and QGraphicsSceneMouseEvent, tried to set focus on my object and then try to click on it - with no result. I was also looking for solution on the Internet on posts from other people, but didn't found anything that would work for me. Where I make mistakes?
Here is some code below:
This is one of my windows, where I create scene, view and object - that I want make respond on my mouse events:
TrackWindow::TrackWindow(Timers *timer)
{
timeLineBar = new QGraphicsScene(this);
timeLineBarView = new QGraphicsView(timeLineBar);
timeLineBarView->setFixedHeight(20);
timeLineBarView->setAlignment(Qt::AlignTop|Qt::AlignLeft);
timeLineBarView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
timeLineBarView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
timeLineBarView->setStyleSheet("background-color: #333333; border:none;");
QVBoxLayout *timeLineLayout = new QVBoxLayout;
timeLineLayout->addWidget(timeLineBarView);
timeLineLayout->addWidget(tracksTimelineView);
timeline = new TimeLine(timer);
timeLineBar->addItem(timeline);
//timeline->setFlag(QGraphicsItem::ItemIsFocusable);
//timeline->setFocus();
}
Here is my Timeline class implementation:
TimeLine::TimeLine(Timers *t)
{
timer = new Timers;
timer = t;
timeLineWidth = 200000;
timeLineScale = 0.1;
}
QRectF TimeLine::boundingRect() const
{
return QRectF(0,0,timeLineWidth,18);
}
void TimeLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rect = boundingRect();
QPen pen(Qt::NoPen);
painter->setPen(pen);
painter->setBrush(QColor(200,200,200));
painter->drawRect(rect);
for(int i=0;i<200;i++)
{
painter->drawText(i*30,9,QString::number(i+1));
}
}
void TimeLine::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
timer->start();
}
}
And header of my class:
#ifndef TIMELINE_H
#define TIMELINE_H
#include <QObject>
#include <QColor>
#include <QRect>
#include <QGraphicsRectItem>
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include "timers.h"
class TimeLine: public QGraphicsRectItem
{
public:
TimeLine(Timers *t);
QRectF boundingRect() const;
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget);
float timeLineScale;
int timeLineWidth;
void mousePressEvent(QGraphicsSceneMouseEvent * event);
private:
Timers *timer;
protected:
void mouseReleaseEvent(QGraphicsSceneMouseEvent * event);
};
#endif // TRACK_H

The problem is caused by overwriting the boundingRect() method, how are you inheriting from QGraphicsRectItem it is correct to use setRect()
timeline.h
#ifndef TIMELINE_H
#define TIMELINE_H
#include "timers.h"
#include <QGraphicsRectItem>
class TimeLine : public QGraphicsRectItem
{
public:
TimeLine(Timers *t, QGraphicsItem *parent = 0);
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
private:
int timeLineWidth;
float timeLineScale;
Timers *timer;
};
#endif // TIMELINE_H
timeline.cpp
#include "timeline.h"
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QTimer>
TimeLine::TimeLine(Timers *t, QGraphicsItem *parent):QGraphicsRectItem(parent)
{
timer = t;
timeLineWidth=200000;
setRect(QRectF(0,0,timeLineWidth,18));
timeLineScale = 0.1;
}
void TimeLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
QRectF rect = boundingRect().toRect();
QPen pen(Qt::NoPen);
painter->setPen(pen);
painter->setBrush(QColor(200,200,200));
painter->drawRect(rect);
painter->setPen(Qt::red);
for(int i=0;i<200;i++)
{
painter->drawText(i*30,9,QString::number(i+1));
}
}
void TimeLine::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
timer->start();
}
Note: it is not necessary to create a Timers inside TimeLine: timer = new Timers; since afterwards you are changing the direction of the pointer and therefore that space is unusable besides that it is unnecessary.
In the following link you will find the project that you use to test the functionality.

Related

QGraphicsScene item is drawn at twice(x2) position

(warning crossposted on: https://forum.qt.io/topic/105158/qgraphicsscene-item-is-drawn-at-twice-x2-position)
In the following code I am creating a custom widget which has a subclass of QGraphicsScene embeded in it. My aim is to click and add a point to the scene. A point is my subclass of QGraphicsItem (GIPoint). I want to move that point around and later connect it to other points and make a spline path.
The problem I am facing is that the point is not drawn at where I click but at a place which is formed by doubling the mouse-event's scenePos() coordinates. So if I click at (100,100) the point is drawn at (200,200). I suspect that I have misunderstood the coordinate system despite reading the documentation.
The question How to add item in a QGraphicsScene? seems relevant but the proposed solution to transform the mouse-event's coordinates via mapToScene(event->pos()); actually doubles up the position (before it will print that it draws on same position but it would then be x2. Now it also prints it as x2).
So I am asking additionally to point me to some simple-to-digest advice on how the widgets placement works. btw. is QRectF GIPoint::boundingRect() const {
return QRectF(pos().x(), pos().y(), 5, 5);
correct regarding the (x,y) coordinates of the rectangle?
My example code follows:
/* use the following pro:
QT += widgets core gui
CONFIG += debug console
SOURCES = example.cpp
TARGET = example
*/
#include <QGraphicsItem>
#include <QPainter>
#include <QWidget>
#include <QRectF>
#include <QPointF>
#include <QGraphicsScene>
#include <QStyleOptionGraphicsItem>
#include <QGraphicsSceneMouseEvent>
#include <QKeyEvent>
#include <QGraphicsView>
#include <QApplication>
#include <QOpenGLWidget>
#include <QMainWindow>
#include <QGridLayout>
#include <QDebug>
class GIPoint : public QGraphicsItem{
public:
GIPoint(QGraphicsItem * parent, const QPointF &position);
protected:
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
QRectF boundingRect() const override;
void paint(
QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget
);
};
class GraphicsSceneWidget : public QGraphicsScene {
public:
explicit GraphicsSceneWidget(QObject *parent);
~GraphicsSceneWidget();
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
};
class VectorGraphicsWidget : public QWidget {
public:
VectorGraphicsWidget(QWidget *parent);
~VectorGraphicsWidget();
private:
GraphicsSceneWidget *myGraphicsSceneWidget;
};
// implementation
GIPoint::GIPoint(
QGraphicsItem *parent,
const QPointF &position
) : QGraphicsItem(parent) {
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true);
setPos(position);
qWarning() << "GIPoint::GIPoint() : init at " << position;
}
QVariant GIPoint::itemChange(
GraphicsItemChange change,
const QVariant &value
){
if (change == QGraphicsItem::ItemPositionChange) {
qWarning("position changed");
}
return value;
}
QRectF GIPoint::boundingRect() const {
return QRectF(pos().x(), pos().y(), 5, 5);
// return QRectF(0,0, 5, 5);
}
void GIPoint::paint(
QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget
){
(void )option;
(void )widget;
QPointF xx = scenePos();
QRectF rect = QRectF(xx.x(), xx.y(), 10, 10);
qWarning() << "painting: scenePos " << scenePos() << ", rect " << rect;
QBrush brush = QBrush(Qt::black, Qt::SolidPattern);
//painter->fillRect(rect, brush);
painter->drawRect(rect);
}
GraphicsSceneWidget::GraphicsSceneWidget(QObject *parent)
: QGraphicsScene(parent)
{}
GraphicsSceneWidget::~GraphicsSceneWidget(){}
void GraphicsSceneWidget::mousePressEvent(
QGraphicsSceneMouseEvent *event
){
GIPoint *gip = new GIPoint(Q_NULLPTR, event->scenePos());
addItem(gip);
QGraphicsScene::mousePressEvent(event);
}
VectorGraphicsWidget::VectorGraphicsWidget(QWidget *parent) :
QWidget(parent)
{
myGraphicsSceneWidget = new GraphicsSceneWidget(this);
QGraphicsView *view = new QGraphicsView(myGraphicsSceneWidget);
myGraphicsSceneWidget->setSceneRect(QRectF(0, 0, 500, 500));
QGridLayout *centralLayout = new QGridLayout;
centralLayout->addWidget(view);
setLayout(centralLayout);
myGraphicsSceneWidget->addRect(
QRectF(0, 0, 100, 100),
QPen(Qt::black),
QBrush(Qt::green)
);
view->show();
}
VectorGraphicsWidget::~VectorGraphicsWidget() {
delete myGraphicsSceneWidget;
}
int main(int argc, char **argv){
QApplication app(argc, argv);
app.setApplicationName("test");
app.setOrganizationName("myorg");
app.setOrganizationDomain("myorg.com");
QMainWindow *w = new QMainWindow();
w->resize(500, 500);
w->setCentralWidget(new VectorGraphicsWidget(Q_NULLPTR));
w->show();
return app.exec();
}
The problem is that the boundingRect() and the paint() methods is respect the coordinate system of the item, not the scene. So the solution is not to use scenePos() in both methods but 0, 0:
QRectF GIPoint::boundingRect() const {
return QRectF(0, 0, 10, 10);
}
void GIPoint::paint(
QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget
){
(void )option;
(void )widget;
QRectF rect = QRectF(0, 0, 10, 10);
qWarning() << "painting: scenePos " << scenePos() << ", rect " << rect;
QBrush brush = QBrush(Qt::black, Qt::SolidPattern);
painter->fillRect(rect, brush);
painter->drawRect(rect);
}
Although I would recommend using QGraphicsRectItem as it implements what you have done.

How to draw rectangle on custom video widget t in QT?

I want to select an area on a custom video widget and draw rectangle on selected area.
So far I can select an area with QRubberband but I am having trouble with drawing the rectangle after releasing left click.
Whenever I click-drag then release to draw rectangle it gives this error:
QBackingStore::endPaint() called with active painter on backingstore paint device
The program has unexpectedly finished.
Here is my code:
myvideoobject.h
#ifndef MYVIDEOOBJECT_H
#define MYVIDEOOBJECT_H
#include <QObject>
#include <QVideoWidget>
#include <QRubberBand>
#include <QPainter>
#include <QPen>
#include <QPaintEvent>
#include <QRect>
#include <QMouseEvent>
#include <QDebug>
class MyVideoObject : public QVideoWidget
{
Q_OBJECT
public:
explicit MyVideoObject(QWidget *parent = 0);
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
void paintEvent(QPaintEvent *ev);
private:
QRubberBand* rubberBand;
QPainter* painter;
//QRect *rectangle;
QPoint origin;
QPoint endPoint;
};
#endif // MYVIDEOOBJECT_H
myvideoobject.cpp
#include "myvideoobject.h"
MyVideoObject::MyVideoObject(QWidget* parent) :
QVideoWidget(parent)
{
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(0,0,50,50);//ileride silebilrisin
}
void MyVideoObject::mouseMoveEvent(QMouseEvent *ev)
{
rubberBand->setGeometry(QRect(origin,ev->pos()).normalized());
}
void MyVideoObject::mousePressEvent(QMouseEvent *ev)
{
origin = ev->pos();
if(!rubberBand)
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(QRect(origin,QSize()));
rubberBand->show();
}
void MyVideoObject::mouseReleaseEvent(QMouseEvent *ev)
{
rubberBand->hide();
endPoint = ev->pos();
painter->begin(this);
painter->drawRect(QRect(origin,endPoint));
}
void MyVideoObject::paintEvent(QPaintEvent *ev)
{
QRect rect = ev->rect();
painter = new QPainter(this);
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::black);
painter->drawText(rect,Qt::AlignCenter,"Data");
painter->drawRect(rect);
//painter->setPen(Qt::red);
}
I didn't add mainwindow.cpp and mainwindow.h cuz there isn't much code in those other than selecting video with openfiledialog.
When you create a pointer: QPainter *painter, this can point to any memory since it has garbage. so when you do painter->begin(this) you are accessing uninitialized memory, that's why you get that error. On the other hand in a QWidget such as QVideoWidget should only be painted in the method paintEvent, the strategy is to have variables that save the state of what you want to paint, for example the QRect, and call update to paint it.
myvideoobject.h
#ifndef MYVIDEOOBJECT_H
#define MYVIDEOOBJECT_H
#include <QVideoWidget>
class QRubberBand;
class MyVideoObject : public QVideoWidget
{
public:
MyVideoObject(QWidget *parent = nullptr);
protected:
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
void paintEvent(QPaintEvent *ev);
private:
QRubberBand *rubberBand;
QPoint origin;
QRect rect;
};
#endif // MYVIDEOOBJECT_H
myvideoobject.cpp
#include "myvideoobject.h"
#include <QMouseEvent>
#include <QPainter>
#include <QRubberBand>
MyVideoObject::MyVideoObject(QWidget *parent):
QVideoWidget(parent),
rubberBand(nullptr){}
void MyVideoObject::mousePressEvent(QMouseEvent *ev)
{
origin = ev->pos();
if(!rubberBand)
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(QRect(origin,QSize()));
rubberBand->show();
QVideoWidget::mousePressEvent(ev);
}
void MyVideoObject::mouseMoveEvent(QMouseEvent *ev)
{
rubberBand->setGeometry(QRect(origin,ev->pos()).normalized());
QVideoWidget::mouseMoveEvent(ev);
}
void MyVideoObject::mouseReleaseEvent(QMouseEvent *ev)
{
rect = rubberBand->geometry();
update();
QVideoWidget::mouseReleaseEvent(ev);
}
void MyVideoObject::paintEvent(QPaintEvent *ev)
{
QVideoWidget::paintEvent(ev);
QPainter painter(this);
painter.save();
painter.setBrush(Qt::red);
if(!rect.isNull())
painter.drawRect(rect);
painter.restore();
}

How do I scale/resize a QGraphicsWidget based on the QGraphicScene?

I would like my QGraphicsWidget to scale its size based on the size of the scene. The QGraphicsWidget I have currently is a fixed size depending on the return value of sizeHint (QGraphicsWidget is always 200 x 200). Attached below is minimal example:
MainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include "RectangleWidget.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QGraphicsScene * m_scene;
QGraphicsView * m_view;
RectangleWidget * m_rectangleWidget;
};
#endif // MAINWINDOW_H
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_scene = new QGraphicsScene(this);
m_view = new QGraphicsView(m_scene, this);
m_view->setAlignment(Qt::AlignLeft | Qt::AlignTop);
m_rectangleWidget = new RectangleWidget();
m_scene->addItem(m_rectangleWidget);
setCentralWidget(m_view);
}
MainWindow::~MainWindow()
{
delete ui;
}
RectangleWidget.h:
#ifndef RECTANGLEWIDGET_H
#define RECTANGLEWIDGET_H
#include <QGraphicsLinearLayout>
#include <QGraphicsWidget>
class RectangleWidget: public QGraphicsWidget
{
public:
RectangleWidget(QGraphicsWidget* parent = nullptr);
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
void setGeometry(const QRectF &geom) override;
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override;
};
#endif // RECTANGLEWIDGET_H
RectangleWidget.cpp:
#include "rectanglewidget.h"
#include <QPainter>
RectangleWidget::RectangleWidget(QGraphicsWidget* parent)
{
}
void RectangleWidget::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget /*= 0*/)
{
Q_UNUSED(widget);
Q_UNUSED(option);
//Draw border
painter->drawRoundedRect(boundingRect(), 0.0, 0.0);
}
QRectF RectangleWidget::boundingRect() const
{
return QRectF(QPointF(0,0), geometry().size());
}
void RectangleWidget::setGeometry(const QRectF &geom)
{
prepareGeometryChange();
QGraphicsLayoutItem::setGeometry(geom);
setPos(geom.topLeft());
}
QSizeF RectangleWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
switch (which) {
case Qt::MinimumSize:
return QSizeF(200, 200);
default:
break;
}
return constraint;
}
Any help on this would be appreciated.
Background
Your QGraphicsWidget have to be aware of two things:
When it is added to a scene
In order to do that you have to reimplement QGraphicsWidget::itemChange and look for a change of type QGraphicsItem::ItemSceneHasChanged.
When the size of this scene changes
This could be done by connecting a slot or a lambda function to the QGraphicsScene::sceneRectChanged signal.
Solution
Based on the given explanation, my solution would be the following:
In RectangleWidget.h after QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override; add:
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
private:
QSize m_rectSize;
In RectangleWidget.cpp change return QSizeF(200, 200); to return m_rectSize; and add at the end:
QVariant RectangleWidget::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == ItemSceneHasChanged) {
connect(value.value<QGraphicsScene *>(), &QGraphicsScene::sceneRectChanged, [this](const QRectF &rect){
m_rectSize.setWidth(rect.size().width());
m_rectSize.setHeight(rect.size().height());
});
}
return QGraphicsWidget::itemChange(change, value);
}
Finally, in MainWindow.cpp after m_scene->addItem(m_rectangleWidget); set the sceneRect as follows:
m_scene->setSceneRect(0, 0, 100, 400);
Note: The rectangle will respond to the changes of the scene, not the view. So if you resize the window, the rectangle will not be resized.
Adjustment
This will make the rectangle exactly the same size as the scene. If you want a different ratio, say 0.5, instead of m_rectSize.setWidth(rect.size().width()); write m_rectSize.setWidth(rect.size().width() / 2);, respectively m_rectSize.setHeight(rect.size().height() / 2);.

How to mix mouseEnterEvent and mouseMove?

in my application I try to connect nodes with lines. I use a QGraphicsView with a QGraphicsScene and my own QGraphicsItems. Now if I click on an item I want to draw a line to another node. To give a visual feedback, the goal should change color if the mouse hovers over the goal. The basics works so far, but my problem is that if I drag a line with the mouse (via mouseMoveEvent), I do not get any hoverEvents any more. I replicated the behaviour with this code:
Header File:
#pragma once
#include <QtWidgets/Qwidget>
#include <QGraphicsItem>
#include <QGraphicsScene>
class HaggiLearnsQt : public QWidget
{
Q_OBJECT
public:
HaggiLearnsQt(QWidget *parent = Q_NULLPTR);
};
class MyScene : public QGraphicsScene
{
public:
MyScene(QObject* parent = 0);
void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent);
};
class MyItem : public QGraphicsItem
{
public:
MyItem(QGraphicsItem* parent = Q_NULLPTR);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
bool mouseOverItem;
};
Implementation:
#include "HaggiLearnsQt.h"
#include <QMessageBox>
#include <QFrame>
#include <QHBoxLayout>
#include <QGraphicsView>
MyScene::MyScene(QObject* parent)
{}
void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
MyItem::MyItem(QGraphicsItem* parent) : mouseOverItem(false)
{
setAcceptHoverEvents(true);
}
QRectF MyItem::boundingRect() const
{
return QRectF(-50, -50, 50, 50);
}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QBrush b = QBrush(Qt::black);
if(mouseOverItem)
b = QBrush(Qt::yellow);
painter->setBrush(b);
painter->drawRect(boundingRect());
}
void MyItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
mouseOverItem = true;
QGraphicsItem::hoverEnterEvent(event);
}
void MyItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
mouseOverItem = false;
QGraphicsItem::hoverLeaveEvent(event);
}
HaggiLearnsQt::HaggiLearnsQt(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout* layout = new QHBoxLayout(this);
MyScene* graphicsScene = new MyScene();
QGraphicsView* graphicsView = new QGraphicsView();
graphicsView->setRenderHint(QPainter::RenderHint::Antialiasing, true);
graphicsView->setScene(graphicsScene);
layout->addWidget(graphicsView);
graphicsView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
graphicsView->setMinimumHeight(200);
graphicsView->setMinimumWidth(200);
graphicsView->setStyleSheet("background-color : gray");
MyItem* myitem = new MyItem();
myitem->setPos(50, 50);
graphicsScene->addItem(myitem);
}
And the default main.cpp:
#include "HaggiLearnsQt.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
HaggiLearnsQt w;
w.show();
return a.exec();
}
If you run the code, a box appears in the middle of the window. If you hover over the box, it changes color. Now try to klick outside the box and drag wiht pressed button into the box. The box does not receive a hover and does not change color.
So my question is: Can I somehow change the item while I move the mouse with a pressed button?
You can get the hovered item passing mouseEvent->scenePos() to the QGraphicsScene::itemAt method inside the scene mouse move event handler.
Have a pointer to a MyItem instance, in MyScene:
class MyScene : public QGraphicsScene
{
MyItem * hovered;
//...
initialize it to zero in MyScene constructor:
MyScene::MyScene(QObject* parent)
{
hovered = 0;
}
then use it to track the current highlighted item (if there's one):
void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if(mouseEvent->buttons())
{
QGraphicsItem * item = itemAt(mouseEvent->scenePos(), QTransform());
MyItem * my = dynamic_cast<MyItem*>(item);
if(my != 0)
{
qDebug() << mouseEvent->scenePos();
if(!my->mouseOverItem)
{
my->mouseOverItem = true;
my->update();
hovered = my;
}
}
else
{
if(hovered != 0)
{
hovered->mouseOverItem = false;
hovered->update();
hovered = 0;
}
}
}
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
The line if(mouseEvent->buttons()) at the beginning prevents the check to be performed if no mouse button is held.
Don't forget to initialize mouseOverItem to false in MyItem constructor:
MyItem::MyItem(QGraphicsItem* parent) : mouseOverItem(false)
{
setAcceptHoverEvents(true);
mouseOverItem = false;
}

Qt: How to adjust QGraphicsItem to dynamicaly change size

I've this problem for several days. I have created QGraphicsItem and I want to stretch/adjust it's size to size of my QGraphicsView. I was using paint() method, but got with it problems with updating. Now I've used boundingRect() but it uses fixed size. When I set too big size it expand my scene and scrollbars are appearing. Is there way to adjust size of item to size of View?
EDIT: I want only adjust height of my object.
Here's some code:
Header of my Item:
#ifndef POINTER_H
#define POINTER_H
#include <QObject>
#include <QColor>
#include <QRect>
#include <QGraphicsLineItem>
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
class Pointer : public QGraphicsLineItem
{
public:
Pointer();
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget);
QRectF boundingRect() const;
int position;
void changePosition(int x);
};
#endif // TRACKPOINTER_H
Implementation of my Item:
#include "pointer.h"
Pointer::Pointer()
{
//this->setFlag(QGraphicsLineItem::ItemIsMovable);
//setFlag(QGraphicsLineItem::ItemIsFocusable);
//setFocus();
}
void Pointer::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QPen pen(Qt::red);
painter->setPen(pen);
painter->setBrush(QColor(77,77,77));
painter->drawLine(0,0,0,2000);
}
QRectF Pointer::boundingRect() const
{
return QRectF(0,0,2,600);
}
void Pointer::changePosition(int x)
{
//position = x;
setPos(x,0);
update();
}
And my Window:
Window::Window(Timers *timer, TrackPointer *tp)
{
Timeline = new QGraphicsScene(this);
TimelineView = new QGraphicsView(Timeline);
TimelineView->setAlignment(Qt::AlignTop|Qt::AlignLeft);
QVBoxLayout *timeLineLayout = new QVBoxLayout;
timeLineLayout->addWidget(TimelineView);
Pointer *pointer = new Pointer;
Timeline->addItem(pointer);
}
I have also problems with my scene: When my object moves somewhere away - it expand scene. Later when I bring my object back to it's starting position scene still is expanded and I have scrollbars to scroll my view around the scene. Is there way to decrease scene size using my object?
The promised example looks something like this:
MainWindow.h
#include <QMainWindow>
class QGraphicsView;
class QGraphicsRectItem;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
bool eventFilter(QObject *watched, QEvent *event) override;
private:
QGraphicsView *m_view;
QGraphicsRectItem *m_item;
};
MainWindow.cpp
#include "MainWindow.h"
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
m_view(new QGraphicsView(this)),
m_item(new QGraphicsRectItem(0, 0, 1, 1))
{
m_view->setScene(new QGraphicsScene());
m_view->setFrameStyle(QFrame::NoFrame);
m_view->setAlignment(Qt::AlignLeft | Qt::AlignTop);
m_view->setSceneRect(0, 0, 1, 1);
m_view->installEventFilter(this);
m_view->scene()->addItem(m_item);
setCentralWidget(m_view);
resize(600, 400);
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if ((watched == m_view) && (event->type() == QEvent::Resize))
m_item->setRect(m_view->viewport()->rect().adjusted(5, 5, -5, -5));
return QMainWindow::eventFilter(watched, event);
}
look into :QGraphicsView::fitInView
http://doc.qt.io/qt-4.8/qgraphicsview.html#fitInView
QPixmap *pixMap= new QPixmap();;
QGraphicsScene *scene=new QGraphicsScene();;
pixMap->loadFromData(jpegData);
scene->clear();
pixMapItem = scene->addPixmap(*pixMap);
ui->graphicsView->fitInView(scene->sceneRect(), Qt::KeepAspectRatio);
ui->graphicsView->show();
ui->graphicsView->viewport()->update();