Custom widget is flickering and clipping while moving - c++

I'll give you a minimal reproduceable example that was a part of the more complex widget.
Here we just have a custom widget(called MovableItem) with a simple paintEvent. Widget is created, placed onto the central widget and moved to mouse position on MainWindow::mousePressEvent-s.
When moving, it seems like the widget is getting clipped at the side it's moving towards.
mainwindow.h
#include <QMainWindow>
#include <QMouseEvent>
#include <QPropertyAnimation>
#include "movableitem.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void mousePressEvent(QMouseEvent *event) override;
QWidget* mItem;
};
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
resize(640, 480);
QWidget* central_widget = new QWidget(this);
mItem = new MovableItem(central_widget);
mItem->move(20, 20);
setCentralWidget(central_widget);
}
void MainWindow::mousePressEvent(QMouseEvent *event) {
QPoint pos = event->pos();
QPropertyAnimation* anim = new QPropertyAnimation(mItem, "geometry");
anim->setDuration(750);
anim->setStartValue(QRect(mItem->x(), mItem->y(), mItem->width(), mItem->height()));
anim->setEndValue(QRect(pos.x(), pos.y(), mItem->width(), mItem->height()));
anim->start();
}
MainWindow::~MainWindow() {}
movableitem.h
#include <QWidget>
#include <QPainter>
#include <QPainterPath>
class MovableItem : public QWidget
{
Q_OBJECT
public:
MovableItem(QWidget *parent = nullptr);
QSize sizeHint() const override;
void paintEvent(QPaintEvent *event) override;
};
movableitem.cpp
#include "movableitem.h"
MovableItem::MovableItem(QWidget *parent) : QWidget(parent)
{
setParent(parent);
}
QSize MovableItem::sizeHint() const {
return QSize(150, 40);
}
void MovableItem::paintEvent(QPaintEvent *event) {
QRect r = rect();
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
path.addRoundedRect(r, 5, 5);
QBrush brush(QColor(217, 217, 217));
painter.fillPath(path, brush);
painter.drawPath(path);
}
Example
As you can see, movement is not fluid, but choppy. I have no idea what is happening. Am I doing something completely wrong ? Do I need to implement some additional functions, is double buffering needed, is this because of Qt's automatic clipping ? Should I rewrite it in QGraphicsView ?

Add mItem->repaint(); and mItem->update(); in mousePressEvent function
void MainWindow::mousePressEvent(QMouseEvent *event)
{
QPoint pos = event->pos();
QPropertyAnimation* anim = new QPropertyAnimation(mItem, "geometry");
anim->setDuration(750);
anim->setStartValue(QRect(mItem->x(), mItem->y(), mItem->width(), mItem->height()));
anim->setEndValue(QRect(pos.x(), pos.y(), mItem->width(), mItem->height()));
anim->start();
mItem->repaint();
mItem->update();
}
my out put is here :

Related

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);.

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();

Using QPainter to draw a line between QWidgets

I'm working on an application where I need to be able to draw a line between two QWidget objects. I have tried quite a few things, but my current attempt (which I think is in the right direction I just think I'm missing something) is to have the containing widget (which I called DrawWidget and which holds the QGridLayout that the QWidget objects are added to) override the paintEvent method and call the QPainter::drawLine() function.
The issues I'm having are that:
No matter how I try to get the position of the widgets, the endpoints of the line are always in the wrong place
Whenever I try to draw a second line, the first line that I drew gets erased.
Here is the paintEvent function of the containing widget:
void paintEvent(QPaintEvent *)
{
if (!drewSinceUpdate){
drewSinceUpdate = true;
QPainter painter(this);
painter.setPen(QPen(Qt::black));
painter.drawLine(start->geometry().center(), end->geometry().center());
}
}
I have tried many different ways to get the correct position of the widgets in the last line of paintEvent, which I will post some of the ways (I can't remember all of them):
painter.drawLine(start->pos(), end->pos());
painter.drawLine(start->mapToGlobal(start->geometry().center()), end->mapToGlobal(end->geometry().center()));
painter.drawLine(this->mapToGlobal(start->geometry().center()), this->mapToGlobal(end->geometry().center()));
painter.drawLine(start->mapTo(this, start->pos()), end->mapTo(this, end->pos()));
painter.drawLine(this->mapFrom(start, start->pos()), this->mapFrom(end, end->pos()));
And just to make my question clear, here is an example of what I am looking for, taken from QT Diagram Scene Example:
But this is what I end up getting:
Thank you for any help you can provide.
NOTE:
-start and end are both QWidget objects which I passed in using another method
-The hierarchy relevant to DrawWidget is:
QMainWindow
->QScrollArea
->DrawWidget
->QGridLayout
->Items <-- These are the things I want to connect
EDIT: To make a Complete and Verifiable example, here is the entirety of the relevant code.
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTextEdit>
#include <QPushButton>
#include <QScrollBar>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// Setting up the relevant hierarchy
ui->setupUi(this);
scrollArea = new QScrollArea();
setCentralWidget(scrollArea);
drawWidget = new DrawWidget();
gridLayout = new QGridLayout();
gridLayout->setSpacing(300);
drawWidget->setLayout(gridLayout);
scrollArea->setWidget(drawWidget);
scrollArea->setWidgetResizable(true);
AddItemSlot();
QApplication::connect(scrollArea->horizontalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(scrollHorizontal()));
}
// This is just creating a single one of the example widgets which I want to connect
QWidget* MainWindow::CreateNewItem(){
QWidget* itemWidget = new QWidget();
itemWidget->setStyleSheet("background-color: lightgray");
QHBoxLayout* singleItemLayout = new QHBoxLayout();
itemWidget->setLayout(singleItemLayout);
QTextEdit* textEdit = new QTextEdit(std::to_string(counter++).c_str());
textEdit->setStyleSheet("background-color:white;");
singleItemLayout->addWidget(textEdit);
QVBoxLayout* rightSidePanel = new QVBoxLayout();
rightSidePanel->setAlignment(Qt::AlignTop);
QPushButton* button1 = new QPushButton("Top Button");
QApplication::connect(button1, SIGNAL(clicked(bool)), this, SLOT(AddItemSlot()));
rightSidePanel->addWidget(button1);
QWidget* rightPanelWidget = new QWidget();
rightSidePanel->setMargin(0);
rightPanelWidget->setLayout(rightSidePanel);
singleItemLayout->addWidget(rightPanelWidget);
itemWidget->setLayout(singleItemLayout);
itemWidget->setMinimumWidth(400);
itemWidget->setFixedSize(400,200);
return itemWidget;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::scrollHorizontal()
{
scrollArea->ensureWidgetVisible(noteItems.back());
}
void MainWindow::AddItemSlot()
{
QWidget* w = CreateNewItem();
gridLayout->addWidget(w,currRow, currCol++);
if (!noteItems.empty()){
drawWidget->updateEndpoints(noteItems.back(), w);
}
noteItems.push_back(w);
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGridLayout>
#include <QWidget>
#include <QMainWindow>
#include <QScrollArea>
#include <drawwidget.h>
#include "drawscrollarea.h"
#include <vector>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void scrollHorizontal();
void AddItemSlot();
private:
Ui::MainWindow *ui;
QWidget* CreateNewItem();
int counter = 0, currCol = 0, currRow = 0;
std::vector<QWidget*> noteItems;
QScrollArea* scrollArea;
DrawWidget* drawWidget;
QGridLayout* gridLayout;
};
#endif // MAINWINDOW_H
DrawWidget.cpp:
#include "drawwidget.h"
#include <QDebug>
#include <QRect>
DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent)
{
}
void DrawWidget::paintEvent(QPaintEvent *)
{
if (!drewSinceUpdate){
drewSinceUpdate = true;
QPainter painter(this);
painter.setPen(QPen(Qt::black));
for (ConnectedPair pair : items){
const QWidget* from = pair.from;
const QWidget* to =pair.to;
QPoint start = from->mapToGlobal(from->rect().topRight() + QPoint(0, from->height()/2));
QPoint end = to->mapToGlobal(to->rect().topLeft() + QPoint(0, to->height()/2));
painter.drawLine(mapFromGlobal(start), mapFromGlobal(end));
}
}
}
void DrawWidget::updateEndpoints(QWidget* startIn, QWidget* endIn){
drewSinceUpdate = false;
items.push_back(ConnectedPair{startIn, endIn});
}
DrawWidget.h
#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H
#include <QWidget>
#include <QPainter>
#include <QtCore>
#include <vector>
class DrawWidget : public QWidget
{
Q_OBJECT
public:
explicit DrawWidget(QWidget *parent = nullptr);
void updateEndpoints(QWidget* startIn, QWidget* endIn);
virtual void paintEvent(QPaintEvent *);
signals:
private:
struct ConnectedPair {
const QWidget* from;
const QWidget* to;
};
std::vector<ConnectedPair> items;
bool drewSinceUpdate = true;
};
#endif // DRAWWIDGET_H
For this case we use the function mapToGlobal() and mapfromGlobal(), since pos() returns a position with respect to the parent and this can cause problems if the widget has different parents.
drawwidget.h
#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H
#include <QWidget>
class DrawWidget : public QWidget
{
Q_OBJECT
public:
explicit DrawWidget(QWidget *parent = nullptr);
void addWidgets(const QWidget *from, const QWidget *to);
protected:
void paintEvent(QPaintEvent *);
private:
struct WidgetsConnected {
const QWidget* from;
const QWidget* to;
};
QList<WidgetsConnected> list;
};
#endif // DRAWWIDGET_H
drawwidget.cpp
#include "drawwidget.h"
#include <QPainter>
DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent)
{
}
void DrawWidget::addWidgets(const QWidget * from, const QWidget * to)
{
list.append(WidgetsConnected{from , to});
update();
}
void DrawWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
for(const WidgetsConnected el: list){
const QWidget* from = el.from;
const QWidget* to = el.to;
QPoint start = from->mapToGlobal(from->rect().topRight() + QPoint(0, from->height()/2));
QPoint end = to->mapToGlobal(to->rect().topLeft() + QPoint(0, to->height()/2));
painter.drawLine(mapFromGlobal(start), mapFromGlobal(end));
}
}
The complete example can be found here.

Displacement in QGraphicsScene

I have such program: in my Widget I have qpushbuttons, qslider and qgraphicsview. I place qgraphicsscene in qgraphicsview. The problem is that when I click in QGraphicsscene and want to draw a Point, that was clicked, there is a displacement. When I click in center of QGraphicsScene there is not any problems.
if (mouseEvent->button() == Qt::LeftButton)
{
QPointF pos = mouseEvent->scenePos();
addEllipse(pos.x(), pos.y(), 5, 5, QPen(QColor(Qt::green)), QBrush(QColor(Qt::red)));
}
There is a screen too.
So, the question is how to avoid this moving of scene.
In the screen I have clicked in right bottom, but point was drawn in the center
Try this. In my computer it works without displacement
.*h
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QMouseEvent>
class GraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit GraphicsScene(QObject *parent = 0);
signals:
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
public slots:
};
#endif // GRAPHICSSCENE_H
*.cpp
#include "graphicsscene.h"
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
GraphicsScene::GraphicsScene(QObject *parent) :
QGraphicsScene(parent)
{
}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
qDebug() << "in";
if (mouseEvent->button() == Qt::LeftButton)
{
QPointF pos = mouseEvent->scenePos();
addEllipse(pos.x(), pos.y(), 5, 5, QPen(QColor(Qt::green)), QBrush(QColor(Qt::red)));
}
}
Using
GraphicsScene *scene = new GraphicsScene(this);
ui->graphicsView->setSceneRect(50,50,50,50);//for example
ui->graphicsView->setScene(scene);
ui->graphicsView->show();
view->setSceneRect(0, 0, 640, 480);
has helped me