QWidget how to detect mouse stop moving - qt

I can do something when mouse is moving by overwriting QWidget's mouseMoveEvent function.
But I want to do something at the moment when mouse stop moving. How can I implement this?

I would recommend using a single-shot QTimer that you restart each time mouseMoveEvent is called. Set the timeout to some threshold of your choosing. For example:
class Widget : public QWidget
{
public:
Widget(QWidget *parent = nullptr)
: QWidget(parent)
{
setMouseTracking(true);
mTimer.setInterval(500);
mTimer.setSingleShot(true);
connect(&mTimer, &QTimer::timeout, [] {
qDebug("Mouse stopped moving!!!");
});
}
void mouseMoveEvent(QMouseEvent *event) override
{
mTimer.start();
}
private:
QTimer mTimer;
};

Related

How to connect to mousePressEvent slot Qt

In Class Buttons, I have a btnRightClicked signal and a mousePressEvent slot:
void Buttons::mousePressEvent(QMouseEvent *e)
{
if(e->button() == Qt::RightButton) {
emit btnRightClicked();
}
}
And in mainwindow.cpp, I connect the btnRightClicked signal to onRightClicked slot like this:
connect(&mButtons, SIGNAL(btnRightClicked()), this, SLOT(onRightClicked()));
The onRightClicked slot is like this:
void MainWindow::onRightClicked()
{
qDebug() << "right clicked";
}
But I ran this program, nothing happened. I guess the reason is because I did not connect to the mousePressEvent slot. I am kind of new to Qt, I do not know if I am right or not.
I set up some buttons on the central widget, I want them to have the right clicked event when right click each of them. So how can I make this work?Thanks
Edit:
in button.h:
class Buttons : public QObject
{
Q_OBJECT
public:
Buttons();
QVector<QPushButton*> buttons;
void setButtons(int totalBtns) {
for(int i = 0; i < totalBtns; i++) {
buttons[i]->setObjectName(QString::number(i));
buttons[i]->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
}
}
public slots:
void mousePressEvent(QMouseEvent *e) {
if(e->button() == Qt::RightButton) {
emit btnRightClicked();
}
}
signals:
void btnRightClicked();
};
To get the mouse right click on your widget, you need to implement your own button widget.
class MyButton : public QPushButton
{
Q_OBJECT
public:
MyButton(QWidget *parent = Q_NULLPTR);
private slots:
void mousePressEvent(QMouseEvent *e);
signals:
void btnRightClicked();
};
cpp
MyButton:MyButton(QWidget * parent) :
QPushButton(parent)
{
}
void MyButton::mousePressEvent(QMouseEvent *e)
{
if(e->button()==Qt::RightButton)
emit btnRightClicked();
//this forwards the event to the QPushButton
QPushButton::mousePressEvent(e);
}
In your buttons class change the button vector to
QVector<MyButton*> buttons;
Then register the right click event of your MyButton to your signal in Buttons class then forwared the signal to your mainWindow
connect(&mButtons, &Buttons::btnRightClicked,
this, &MainWindow::onRightClicked);

Qt add points one by one with QThread or QTimer?

I want to make a program in Qt to add points one by one, not all at once. To do that, I need to use QThread, or I can just use QTimer?
it can be done using QTimer and if it is time dependent (like every 1 second) then its the way to go. just create the timer, connect its timeout signal to your slot and it should work like a charm
You need create some class, inherited from QObject:
class QTimer;
class QList;
class Test_Timer : public QObject
{
Q_OBJECT
public:
explicit Test_Timer(QObject *parent = 0);
~Test_Timer();
private:
QList<QPoint> *lst;
QTimer *timer;
public slots:
void addPoint();
};
Ok, now we have timer variable for QTimer events, lst for store QPoint and addPoint() slot for handling your timer event.
At constructor we initialize members of class, connect timer's slot with current class slot and start timer with period 500ms:
Test_Timer::Test_Timer(QObject *parent) : QObject(parent)
{
lst = new QList<QPoint>;
timer = new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(addPoint()));
timer->start(500);
}
Slot for adding points may look something like this:
void Test_Timer::addPoint()
{
static int number = 0;
if (lst->size() < 10) {
lst->append(QPoint(0, number++));
qDebug() << lst->size();
} else {
timer->stop();
deleteLater();
}
}
After all don't remember free resources:
Test_Timer::~Test_Timer()
{
lst->clear();
delete lst;
if (timer->isActive())
timer->stop();
delete timer;
}
I think this example will be helpful for you.

Qt rightclick QPushButton

I'm using Qt Creator to create a gui for a mineseeper game.
How can I know a QpushButton clicked with rightclick? for flag in the game.
In other word, which signal used for rightclick?
Create your own button with filter at mousePressEvent slot.
qrightclickbutton.h
#ifndef QRIGHTCLICKBUTTON_H
#define QRIGHTCLICKBUTTON_H
#include <QPushButton>
#include <QMouseEvent>
class QRightClickButton : public QPushButton
{
Q_OBJECT
public:
explicit QRightClickButton(QWidget *parent = 0);
private slots:
void mousePressEvent(QMouseEvent *e);
signals:
void rightClicked();
public slots:
};
#endif // QRIGHTCLICKBUTTON_H
qrightclickbutton.cpp
#include "qrightclickbutton.h"
QRightClickButton::QRightClickButton(QWidget *parent) :
QPushButton(parent)
{
}
void QRightClickButton::mousePressEvent(QMouseEvent *e)
{
if(e->button()==Qt::RightButton)
emit rightClicked();
}
Now connect like this
QRightClickButton *button = new QRightClickButton(this);
ui->gridLayout->addWidget(button);
connect(button, SIGNAL(rightClicked()), this, SLOT(onRightClicked()));
Create a slot in MainWindow.cpp.
void MainWindow::onRightClicked()
{
qDebug() << "User right clicked me";
}
It works for me!
I think QPushButton is internally implemented to listen to left mouse clicks only. But you can easily extend QPushButton and re-implement let's say the mouse release event and do your thing if the right mouse button was pressed, e.g. emit a custom rightClicked() signal for example:
signals:
void rightClicked();
protected:
void mouseReleaseEvent(QMouseEvent *e) {
if (e->button() == Qt::RightButton) emit rightClicked();
else if (e->button() == Qt::LeftButton) emit clicked();
}
... or you can create an overload of the clicked signal that forwards the mouseEvent pointer so you can do the same check outside of the button.
signals:
void clicked(QMouseEvent *);
protected:
void mouseReleaseEvent(QMouseEvent *e) {
emit clicked(e);
}
Then you do the check in the slot you connect the button's clicked(QMouseEvent *) signal to and proceed accordingly.
I just wrote this little helper adapter to make any existing button right-clickable with no need to subclass it:
class CRightClickEnabler : public QObject
{
public:
CRightClickEnabler(QAbstractButton * button): QObject(button), _button(button) {
button->installEventFilter(this);
};
protected:
inline bool eventFilter(QObject *watched, QEvent *event) override {
if (event->type() == QEvent::MouseButtonPress)
{
auto mouseEvent = (QMouseEvent*)event;
if (mouseEvent->button() == Qt::RightButton)
_button->click();
}
return false;
}
private:
QAbstractButton* _button;
};
Usage:
connect(ui->pushButton, &QPushButton::clicked, [](){qDebug() << "Button clicked";});
new CRightClickEnabler(ui->pushButton);
From now on, the clicked signal will be triggered by the right click as well as left click. There's no need to delete this object - it uses ui->pushButton as parent and will be auto-deleted by Qt when the parent is destroyed.
Obviously, you can write 2 lines of code (literally) to declare a new signal here and emit that signal upon right click instead of clicked, if desired.
I'd like to suggest this option as well, without need for event filter/other stuffs...
self.button.released.connect(self.doStuff)
self.button.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.button.customContextMenuRequested.connect(partial(self.doStuff, False))
def doStuff(self,state=True,p=QPoint()):
print("True for left, False for right!",state)

QDialog with label that I'm trying to paint

from my main window I am launching a dialog which has a label, in which I am trying to paint.
So, the dialog's header file (.h) has two classes, one for the dialog itself and one for my label. So, my label's class is this:
class MyImage : public QLabel
{
Q_OBJECT
public:
explicit MyImage(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *e);
};
and in the .cpp, along with the constructor of my QDialog I have the constructor of my MyImage class and the paintEvent function:
MyImage::MyImage(QWidget *parent)
: QLabel(parent)
{
/*...*/
}
void MyImage::paintEvent(QPaintEvent *e)
{
QLabel::paintEvent(e);
QPainter painter(image_label);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setBrush(QBrush(QColor(255,255,255,120)));
painter.drawRect(selectionRect);
}
The image_label is a MyImage object. On the constructor of my QDialog I do the following so as to add it to my QDialog's layout:
mainLayout->addWidget(image_label);
But it is null. I get an error message on output (cannot add null widget) and when I try to add a pixmap to the image_label the program crashes.
Thanks in advance for any answers!
void MyImage::paintEvent(QPaintEvent *e)
{
// QPainter painter(image_label); <- Only paint onto yourself.
QPainter painter(this);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setBrush(QBrush(QColor(255,255,255,120)));
painter.drawRect(selectionRect);
}
Do not call the base class as any output will be overwritten by the new QPainter. It is crashing because image_label is null.

How do I connect slot to user defined variable in Qt?

Sorry if I'm missing something obvious, but I can't seem to find an answer to my question. Any help would be appreciated.
I am trying to use a QSlider to manipulate data in a class I created.
In the main window constructor I have the following:
connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)));
With a slot defined in the same class:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
AFrame *frame;
Ui::MainWindow *ui;
public slots:
void setValue(int val)
{
frame->setMphValue(val);
}
};
My frame class is a promoted widget to allow for drawing over the image I have set and is defined as follows:
class AFrame : public QLabel
{
Q_OBJECT
public:
AFrame( QWidget *parent );
void setMphValue(int val) { m_mph = val; }
protected:
void paintEvent( QPaintEvent *event );
private:
int m_mph;
};
The problem is that when I try assigning the m_mph value in the paintEvent function of the AFrame class, the integer value is lost.
Is there something obvious that I'm missing? Is there a better way to approach this problem?
And my paintEvent code:
void AFrame::paintEvent(QPaintEvent *event)
{
QLabel::paintEvent(event);
QPainter painter(this);
QPen pen("#FF0099");
pen.setWidth(8);
painter.setPen(pen);
//rpm
painter.drawLine(250,275,165,165);
//oil
painter.drawLine(450,100,400,75);
//fuel
painter.drawLine(650,95,600,65);
//mph
QRect rec(0,0,125,3);
int velocity = m_mph;
int rpmStartVal = -225;
float mph = velocity * 1.68;
painter.translate(870,275);
painter.rotate(rpmStartVal + mph);
painter.drawRect(rec);
}
The integer value is not being lost. The widget has no magical insight into the fact that it should repaint when the mph value is updated. Your setMphValue should look like below. That's all there's to it.
void setMphValue(int val) {
m_mph = val;
update();
}
To add to Kuba's reply:
You should also check whether val is the same value as previous, in order to avoid avoid repainting when it's not actually necessary - and side-effect infinite loops should anything called by update() later touch setMphValue().
In full:
void setMphValue(int val) {
if (val == m_mph) return;
m_mph = val;
update();
}

Resources