MouseMoveEvent stops being called - qt

I'm using QCustomPlot (plot_ object) on QQuickPaintedItem (SinePlot class) so I can use it in QML. In mousePressEvent I collect initial point and in mouseMoveEvent I'm making calculations to add new points and updating cursor point:
void SinePlot::mousePressEvent(QMouseEvent* event)
{
prevPoint_ = event->globalPos();
}
void SinePlot::mouseMoveEvent(QMouseEvent* event)
{
QPointF tmp = event->globalPos();
qreal prop = (prevPoint_.x() - tmp.x()) / width();
if(prop > 0)
{
data_->shiftLeft(prop);
} else {
data_->shiftRight(prop);
}
plot_->xAxis->setRange(data_->minX, data_->maxX);
...
prevPoint_ = tmp;
update();
}
I have also trying to use pos() and localPos() but it does not make any difference, here is what I got:
As you can see mouseMoveEvent stops being called after some time(before releasing) and moving cursor does not call it.
Here is minimal reproducible example:
#ifndef SINEPLOT_H
#define SINEPLOT_H
#include "qcustomplot.h"
#include <QtQuick>
#include <QDebug>
class SinePlot : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit SinePlot(QQuickItem* parent=nullptr)
{
setAcceptedMouseButtons(Qt::AllButtons);
plot_ = new QCustomPlot();
plot_->setInteractions(QCP::iRangeDrag);
plot_->addGraph();
}
virtual ~SinePlot()
{
delete plot_;
}
void paint(QPainter* painter)
{
QPicture picture;
QCPPainter qcpPainter;
qcpPainter.begin(&picture);
plot_->toPainter(&qcpPainter, width(), height());
qcpPainter.end();
picture.play(painter);
};
protected:
virtual void mousePressEvent(QMouseEvent* event) {};
virtual void mouseMoveEvent(QMouseEvent* event)
{
qDebug() << "mouse move";
};
private:
QCustomPlot* plot_;
};
#endif
In my case I got "mouse move" ~10 times.

Related

(Qt)I want to know why the if statement won't be excuted

I want to make a simple timer by Qt. When I want to implement pause and resume functionality,it seemed that the if statement in void Widget::on_Pause_clicked()didn't work .
widget.h:
#include <QWidget>
#include <QTimer>
#include <QTime>
#include <QString>
#include <QLCDNumber>
#include <QMouseEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
private:
Ui::Widget *ui;
QLCDNumber *lcd;
QTimer *ptime;
QTime *timerecord;
QPoint windowPos;
QPoint mousePos;
QPoint dPos;
bool isStart;
public:
Widget(QWidget *parent = nullptr);
~Widget();
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private slots:
void on_Start_clicked();
void updatetime();
void initTime();
void on_Pause_clicked();
void on_Clear_clicked();
public slots:
};
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ptime = new QTimer;
timerecord = new QTime;
ui->Timer->setDigitCount(11);
initTime();
connect(ptime,SIGNAL(timeout()),this,SLOT(updatetime()));
this->setWindowFlags(Qt::FramelessWindowHint);//remove system border
isStart=false;//determine if the timer is running
ui->Start->setEnabled(true);
ui->Pause->setEnabled(false);
ui->Clear->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::initTime()
{
timerecord->setHMS(0, 0, 0);
ui->Timer->display(timerecord->toString("mm:ss:zzz "));
}
void Widget::updatetime()
{
*timerecord = timerecord->addMSecs(1);
ui->Timer->display(timerecord->toString("mm:ss:zzz "));
}
void Widget::on_Start_clicked()//when the start button is clicked
{
ptime->start(1);
isStart=true;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(false);
}
void Widget::on_Pause_clicked()//when the pause button is clicked
{
if(isStart == true)
{
ptime->stop();
ui->Pause->setText("继续");
isStart=false;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(true);
}
if(isStart == false)
{
ptime->start(1);
ui->Pause->setText("暂停");
isStart=true;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(false);
}
}
void Widget::on_Clear_clicked()
{
ptime->stop();
initTime();
ui->Start->setEnabled(true);
ui->Pause->setEnabled(false);
ui->Clear->setEnabled(false);
}
void Widget::mousePressEvent(QMouseEvent *event)//make the window movable
{
this->windowPos = this->pos();
this->mousePos = event->globalPos();
this->dPos = mousePos - windowPos;
}
void Widget::mouseMoveEvent(QMouseEvent *event)//make the window movable
{
this->move(event->globalPos() - this->dPos);
}
In your code:
void Widget::on_Pause_clicked()//when the pause button is clicked
{
if(isStart == true)
{
ptime->stop();
ui->Pause->setText("继续");
isStart=false;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(true);
}
if(isStart == false)
{
ptime->start(1);
ui->Pause->setText("暂停");
isStart=true;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(false);
}
}
if isStart starts out to be true, then it enters the first if condition block. Within it, isStart becomes false.
However, when it exits that block, it hits the if (isStart == false) block and since isStart is false, therefore it goes into that block and changes isStart to true.
What you should do (bear in mind my qT is rusty):
void Widget::on_Pause_clicked()//when the pause button is clicked
{
if(isStart == true)
{
ptime->stop();
ui->Pause->setText("继续");
isStart=false;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(true);
} else {
ptime->start(1);
ui->Pause->setText("暂停");
isStart=true;
ui->Start->setEnabled(false);
ui->Pause->setEnabled(true);
ui->Clear->setEnabled(false);
}
}

Drawing Line at current position using QGraphicsLineItem

I want to draw a line using QGraphicsLineItem. What exactly I want is that on clicking at GraphicsView, after second click Line must be drawn. I am confused with the syntax of QGraphicsLineItem and also how to use it. I am new to Qt. Please help me out to solve this problem.
You can use this code snippet.
*h
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QStack>
#include <QPoint>
#include <QMouseEvent>
class GraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit GraphicsScene(QObject *parent = 0);
signals:
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
public slots:
private:
QStack<QPoint> stack;
};
#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)
{
QPoint pos = mouseEvent->scenePos().toPoint();
if(stack.isEmpty())
stack.append(pos);
else if(stack.count() == 1)
{
stack.append(pos);
addLine(QLine(stack.pop(),stack.pop()),QPen(Qt::green));
}
}
}
Usage:
GraphicsScene *scene = new GraphicsScene(this);
ui->graphicsView->setScene(scene);
ui->graphicsView->show();
Edit: more beautiful solution which works as you need.
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
qDebug() << "in";
if (mouseEvent->button() == Qt::LeftButton)
{
QPoint pos = mouseEvent->scenePos().toPoint();
if(stack.isEmpty())
stack.append(pos);
else
addLine(QLine(pos,stack.pop()),QPen(Qt::green));
}
}
You can derive the graphics view/scene and override the mousePressEvent
Below is example using derived QGraphicsScene and overridden mousePressEvent
Class Definition :
class MyScene : public QGraphicsScene
Data Members :
QList<QPointF> m_clickPositions;
int m_mode;
Code :
void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(false == sceneRect().contains(event->scenePos()))
{
QGraphicsScene::mousePressEvent(event);
}
else if(Qt::LeftButton == event->button() && m_mode == ConstructMode)
{
m_clickPositions.append(event->scenePos());
if(m_clickPositions.size() == 2)
{
QLineF lineF(m_clickPositions[0], m_clickPositions[1]);
QGraphicsLineItem* item = this->addLine(lineF);
m_clickPositions.clear();
m_mode = ScrollMode;
}
}
}
I had used something similar in my project and extracted the code. Hope this helps.
Please comment is this is not working.
Edit ::
ConstructMode and Scroll mode are used in the above program so that I can distinguish whether I want to Draw/Construct or just scroll the scene. You can remove them and the declaration of m_mode if not required by you.
If you want to use the modes you can define some public constants and add a method setMode(). Please see the code below.
MyScene.h or some Constant file if you have one
#define ConstructMode 100
#define ScrollMode 101
And add the following function
void MyScene::setMode(int mode)
{
m_mode = mode;
}
After this if you want to enter the construction mode you will need to call myScene->setMode(ConstructMode) everytime, as after the item is constructed the mode is reset to ScrollMode.

Cannot implement Drag and Drop for TextItem

this is my first try trying to use Drag&Drop feature of Qt. I'm a beginner, I made my first subclassing this week although I have made other 2 Qt programs in the past.
I need a movable by Drag&Drop QGraphicsTextItem to show on a QGraphicsView that is connected to the corresponding QGraphicScene. So I can retrieve the new position of the item.
I have looked at the animated robot example and this link: http://www.qtcentre.org/threads/50028-Drag-and-Drop-QGraphicsTextItem
The code of the link above, looked well for my. So I reimplemented it but when building, the compiler shows all kind of errors I´m not sure how to overcome. I don't know where to start, and don't know what piece of code is incorrect...
examples of errors appearing:
error: no matching function for call to 'GraphicsTextItem::setCursor(Qt::CursorShape)'
setCursor(Qt::OpenHandCursor);
^
error: invalid use of incomplete type 'class QGraphicsSceneDragDropEvent'
if(event->mimeData()->hasText())
^
error: forward declaration of 'class QGraphicsSceneDragDropEvent'
class QGraphicsSceneDragDropEvent;
^
I'll leave the code:
Header:
#ifndef GRAPHICSTEXTITEM_H
#define GRAPHICSTEXTITEM_H
#include <QGraphicsTextItem>
class GraphicsTextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
GraphicsTextItem(QGraphicsItem *parent = 0);
protected:
void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
void dropEvent(QGraphicsSceneDragDropEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
private:
bool dragOver;
};
//! [0]
#endif // GRAPHICSTEXTITEM_H
and the Implementation:
#include <graphicstextitem.h>
#include <QDrag>
//#include <QGraphicsScene>
GraphicsTextItem::GraphicsTextItem(QGraphicsItem *parent)
:QGraphicsTextItem(parent)
{
//setFlag(QGraphicsItem::ItemIsSelectable);
setFlag(QGraphicsItem::ItemIsMovable);
setTextInteractionFlags(Qt::TextEditorInteraction);
setAcceptedMouseButtons(Qt::LeftButton);
setAcceptDrops(true);
setCursor(Qt::OpenHandCursor);
}
void GraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
if(event->mimeData()->hasText())
{
event->setAccepted(true);
update();
dragOver = true;
}
else
event->setAccepted(false);
}
void GraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
Q_UNUSED(event);
dragOver = false;
update();
}
void GraphicsTextItem::dropEvent(QGraphicsSceneDragDropEvent *event)
{
event->setAccepted(true);
//qDebug() << "I dropped it";
dragOver = false;
update();
}
void GraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
setCursor(Qt::ClosedHandCursor);
}
void GraphicsTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (QLineF(event->screenPos(), event->buttonDownScreenPos(Qt::LeftButton)).length()
< QApplication::startDragDistance())
return;
QDrag *drag = new QDrag(event->widget());
QMimeData *mime = new QMimeData;
mime->setText(this->toPlainText());
drag->setMimeData(mime);
drag->exec();
setCursor(Qt::OpenHandCursor);
}
void GraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
setCursor(Qt::OpenHandCursor);
}
The error message is telling you that there is a forward declaration somewhere in your code, although that is not true based on the code you have shown so far.
Either way, for accessingt members of your heap object, you need more than just forward declaration. You are missing this include:
#include <QGraphicsSceneDragDropEvent>

QGraphicsPixmapItem, alternative methods of connecting to slots

I'm aware I need to derive from QObject in order to connect to a slot if I am using QGraphicsPixmapItem, but I am struggling to do this. I have tried alternative ways to achieve what I want, I have tried onMousePress and isSelectable i.e.
run->setFlag(QGraphicsPixmapItem::ItemIsSelectable);
if (run->isSelected())
{
qDebug() << "selected";
}
else if (!run->isSelected())
{
qDebug() << "not selected";
}
although run is selectable, the first argument is never true, it is always "not selected"
This is my code, I am working on the slot method;
mainwindow.cpp
int MainWindow::sim()
{
...
QGraphicsPixmapItem* run = new QGraphicsPixmapItem(QPixmap::fromImage(image6));
run->scale(0.3,0.3);
run->setPos(-200,-200);
run->setFlag(QGraphicsPixmapItem::ItemIsSelectable);
run->setCursor(Qt::PointingHandCursor);
connect(run, SIGNAL(selectionChanged()), this, SLOT(runClicked()));
scene->addItem(run);
//pause
QGraphicsPixmapItem* pause = new QGraphicsPixmapItem(QPixmap::fromImage(image7));
pause->scale(0.3,0.3);
pause->setPos(-160,-197);
pause->setFlag(QGraphicsPixmapItem::ItemIsSelectable);
pause->setCursor(Qt::PointingHandCursor);
connect(pause, SIGNAL(selectionChanged()), this, SLOT(pauseClicked()));
scene->addItem(pause);
...
}
void MainWindow::runClicked()
{
qDebug() << "run Clicked";
}
void MainWindow::pauseClicked()
{
qDebug() << "pause Clicked";
}
mainwindow.h
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
int sim();
...
public slots:
void runClicked();
void pauseClicked();
...
So obviously I get the error when connecting to the slots. Could anyone help please? Thank you.
To find out if your item is selected, do this:
QVariant MyItem::itemChange( GraphicsItemChange change, const QVariant& value )
{
if ( change == QGraphicsItem::ItemSelectedHasChanged ) {
qDebug() << ( isSelected() ? "selected" : "not selected" );
}
return QGraphicsItem::itemChange( change, value );
}
If you want to use signals and slots, you need to subclass both QObject and QGraphicsPixmapItem.
Because QObject doesn't contain clicked() signal, you need to implement that, too, by re-implementing
void mousePressEvent ( QGraphicsSceneMouseEvent *e ) and void mouseReleaseEvent ( QGraphicsSceneMouseEvent *e ).
MyItem:
#pragma once
#include <QGraphicsPixmapItem>
#include <qobject.h>
#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>
class MyItem: public QObject, public QGraphicsPixmapItem
/* moc.exe requires to derive from QObject first! */
{
Q_OBJECT
public:
MyItem(QGraphicsItem *parent = 0): QObject(), QGraphicsPixmapItem(parent)
{
}
MyItem(const QPixmap & pixmap, QGraphicsItem * parent = 0 ): QObject(),
QGraphicsPixmapItem(pixmap, parent)
{
}
signals:
void clicked();
protected:
// re-implement processing of mouse events
void mouseReleaseEvent ( QGraphicsSceneMouseEvent *e )
{
// check if cursor not moved since click beginning
if ((m_mouseClick) && (e->pos() == m_lastPoint))
{
// do something: for example emit Click signal
emit clicked();
}
}
void mousePressEvent ( QGraphicsSceneMouseEvent *e )
{
// store click position
m_lastPoint = e->pos();
// set the flag meaning "click begin"
m_mouseClick = true;
}
private:
bool m_mouseClick;
QPointF m_lastPoint;
};
And simple example of usage:
#include <qgraphicsview.h>
#include <qgraphicsscene.h>
#include "reader.h"
#include <qdebug.h>
class MainAppClass: public QObject
{
Q_OBJECT
public:
MainAppClass()
{
QGraphicsScene *scene = new QGraphicsScene();;
scene->setSceneRect( -100.0, -100.0, 200.0, 200.0 );
MyItem *item = new MyItem(QPixmap("about.png"));
connect(item, SIGNAL(clicked()), this, SLOT(pixmapClicked()));
scene->addItem(item);
QGraphicsView * view = new QGraphicsView( scene );
view->setRenderHints( QPainter::Antialiasing );
view->show();
}
public slots:
void pixmapClicked()
{
qDebug() << "item clicked!" ;
}
};

Horde3D Particle System not rendering in Qt OpenGL

Horde3d come with 2 samples, compiled with GLFW. One of them, Knight, shows a particle emitter. I've ported the samples to Qt, with a thin layer I wrote that leave unchanged the applicative code (i.e. scene setup, rendering and events handling).
Indeed, the functionality is ok, except the particle emitter doesn't show. I can't see anything specific in GLFW initialization, and I tried some setting I found in Qt, without success. Horde3d takes care of OpenGL interface, and expose a higher level, clean C interface. Any clue?
EDIT : Most Rilevant Sources of qtKnight.pro
here (cleaned :) main.cpp
#include "glwidget.h"
#include <QApplication>
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
GLWidget glw;
glw.show();
return app.exec();
}
here glWidget.h
#ifndef GL_WIDGET_H
#define GL_WIDGET_H
#include <QtOpenGL>
#include <QTimer>
#include <QKeyEvent>
#include <Horde3D.h>
#include <Horde3DUtils.h>
#include <sstream>
#include <app.h>
class GLWidget : public QGLWidget, Application {
Q_OBJECT
public:
GLWidget();
~GLWidget();
QSize minimumSizeHint() const { return sizeHint(); }
QSize sizeHint() const { return QSize(640, 480); }
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *e) { keyEvent(e, true); QGLWidget::keyPressEvent(e); }
void keyReleaseEvent(QKeyEvent *e) { keyEvent(e, false); QGLWidget::keyReleaseEvent(e); }
void keyEvent(QKeyEvent *, bool);
public slots:
void appLoop() { updateGL(); }
private:
QPoint lastPos;
QTimer evloop;
};
#endif
and here glWidget.cpp
#include "glwidget.h"
#include <stdexcept>
#include <QtDebug>
#include <QTextStream>
#include <QGLFormat>
GLWidget::GLWidget() :
QGLWidget(QGLFormat(QGL::AlphaChannel | QGL::SampleBuffers)),
Application("/home/carlo/horde3d/SDK_1.0.0_Beta5/Horde3D/Binaries/Content")
{
connect(&evloop, SIGNAL(timeout()), this, SLOT(appLoop()));
evloop.start(0);
}
GLWidget::~GLWidget()
{
h3dutDumpMessages();
h3dRelease();
}
void GLWidget::initializeGL()
{
if (!init())
throw std::runtime_error("Could not initialize renderer");
}
void GLWidget::paintGL()
{
keyStateHandler();
mainLoop(30);
}
void GLWidget::resizeGL(int width, int height)
{
Application::resize(width, height);
}
void GLWidget::mousePressEvent(QMouseEvent *event)
{
lastPos = event->pos();
}
void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
QPoint cPos = event->pos();
float dX = cPos.x() - lastPos.x(); //event->x() - lastPos.x();
float dY = cPos.y() - lastPos.y(); //event->y() - lastPos.y();
Application::mouseMoveEvent(dX, dY);
lastPos = cPos;
}
void GLWidget::mouseReleaseEvent(QMouseEvent * /* event */)
{
}
void GLWidget::keyEvent(QKeyEvent *k, bool on_off)
{
#define setK(X,Y) case Qt::X: setKeyState(Y, on_off); break;
#define setF(X) case Qt::Key_##X: setKeyState(X, on_off); break;
#define R(X, Y) (v >= #X[0] && v <= #Y[0])
int v = k->key();
switch (v) {
case Qt::Key_F1: if (on_off) showFullScreen(); break;
case Qt::Key_F2: if (on_off) showNormal(); break;
setF(F3)
setF(F6)
setF(F7)
setF(F8)
setK(Key_Space, SP)
default:
if (R(A, Z) || R(0, 9))
setKeyState(v, on_off);
}
}
Since you say it is only the particles that aren't shown, it could have to do with alpha blending. I also saw from your code that you don't specify a format when constructing the QGLWidget, in which case the default format is used which explicitly disables the alpha channel.
Though I don't know if this has any effect (shouldn't there always be an A in RGBA?), but maybe this really requests a pixel format where there is no storage for the A channel, in which case things like alpha blending (used for the transparent particles) won't work.
So just try to request it explicitly by using an appropriate format in the QGLWidget constructor:
GLWidget::GLWidget()
: QGLWidget(QGLFormat(QGL::AlphaChannel))
You actually were on the right track with your outcommented QGLFormat argument, but it hasn't anything to do with the HasOverlay option, which you don't really need, as Horde3d does it's own overlay rendering.

Resources