I have borderless form with button like in this question
Problem is that I can't click button. It works only if I perform double-click not changing position over the button. How to check that user i performing click (not drag)?
Here come code:
bool LoginForm::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QMouseEvent::MouseButtonPress)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (obj == ui.loginButton)
{
QPoint absPos = ui.loginButton->mapToParent(QPoint(0, 0));
m_dragPosition = (mouseEvent->pos() + absPos);
return true;
}
}
return false;
}
void LoginForm::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_dragPosition = event->globalPos() - frameGeometry().topLeft();
event->accept();
}
}
void LoginForm::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
{
QPoint coord = event->globalPos() - m_dragPosition;
move(coord);
event->accept();
}
}
How to check that user is performing click (not drag)?
It should be easier. Don't steal the event from your button. Such approach is borrowed from Qt example: Music Player. See musicplayer.cpp for details.
void LoginForm::mousePressEvent(QMouseEvent *event)
{
m_dragPosition = event->globalPos() - pos();
event->accept();
}
void LoginForm::mouseMoveEvent(QMouseEvent *event)
{
move(event->globalPos() - m_dragPosition);
event->accept();
}
void LoginForm::mouseReleaseEvent(QMouseEvent *event)
{
m_dragPosition = QPoint();
event->accept();
}
The simpliest way is disable drag clicking on buttonbool
LoginForm::LoginForm(QWidget *parent)
: QWidget(parent)
{
...
m_isDragButton = false;
}
LoginForm::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QMouseEvent::MouseButtonPress)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
if (obj == ui.loginButton)
m_isDragButton = true;
}
return false;
}
void LoginForm::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_dragPosition = event->globalPos() - frameGeometry().topLeft();
event->accept();
}
}
void LoginForm::mouseMoveEvent(QMouseEvent *event)
{
if (!m_isDragButton)
if (event->buttons() & Qt::LeftButton)
{
QPoint coord = event->globalPos() - m_dragPosition;
move(coord);
event->accept();
}
}
void LoginForm::mouseReleaseEvent(QMouseEvent *event)
{
m_isDragButton = false;
m_dragPosition = QPoint();
event->accept();
}
Related
I have QGroupBox with sliderclasses (child class from QLabel)
Picture:
I want to add MouseEvent: when I drag one sliderclasses - another classes will move.
Movement will be as mouse trajectory.
Like this:
Picture:
sliderclass.hpp:
#ifndef SLIDERCLASS_HPP
#define SLIDERCLASS_HPP
#include <QObject>
#include <QLabel>
#include <QMouseEvent>
class sliderclass : public QLabel
{
Q_OBJECT
public:
explicit sliderclass(QWidget *parent = 0);
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
private:
QPoint m_dragPosition;
bool firstCIsNotNull = true;
};
#endif // SLIDERCLASS_HPP
sliderclass.cpp:
#include "sliderclass.hpp"
sliderclass::sliderclass(QWidget *parent) :
QLabel(parent)
{
}
void sliderclass::mouseMoveEvent(QMouseEvent *ev)
{
if ((ev->buttons() & Qt::LeftButton) && firstCIsNotNull){
auto tmp = this->parent()->children();
for(auto obj : tmp) {
auto cbox = static_cast<QLabel*>(obj);
cbox->move(cbox->mapToParent(ev->pos() - m_dragPosition - cbox->geometry().topLeft()));
}
}
}
void sliderclass::mousePressEvent(QMouseEvent *ev)
{
if (ev->button() == Qt::LeftButton) {
m_dragPosition = ev->pos();
firstCIsNotNull = true;
}
}
void sliderclass::mouseReleaseEvent(QMouseEvent *ev)
{
if (ev->button() == Qt::LeftButton) {
firstCIsNotNull = false;
}
}
BUT! This code doesn't work for all QLabels.
All QLabels moves not by trajectory - they all move to final pos of the first QLabel and
all QLabels are layered on top of each other.
mouseEvent->pos().x() always return 0. mouseEvent->pos().y() updating on mouse move
bool Module3::eventFilter(QObject *obj, QEvent *event) {
QMouseEvent *mouseEvent = static_cast(event);
if(obj ==scene && event->type() == QEvent::GraphicsSceneMouseMove){
QToolTip::showText(mouseEvent->pos(),QString::number(mouseEvent->pos().x()) +
", " + QString::number( mouseEvent->pos().y()));
}
return false;
}
You have undefined behaviour. If event->type() is QEvent::GraphicsSceneMouseMove then the real type of event is QGraphicsSceneMouseEvent* not QMouseEvent*.
Try...
if (obj == scene && event->type() == QEvent::GraphicsSceneMouseMove) {
if (auto *mouseEvent = dynamic_cast<QGraphicsSceneMouseEvent *>(event)) {
QToolTip::showText(mouseEvent->scenePos().toPoint(),QString::number(mouseEvent->pos().x()) +
", " + QString::number( mouseEvent->pos().y()));
}
}
return false;
I'm beginner in Qt and I want to drag and move Window using my own custom titleBar(QLabel).
The Qt code:
void MainWindow::mousePressEvent(QMouseEvent *event)
{
mpos = event->pos();
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
{
QPoint diff = event->pos() - mpos;
QPoint newpos = this->pos() + diff;
this->move(newpos);
}
}
This code allow me to move window by mouse pressed on any QWidget but I want to move window by mouse pressed on QLabel.
I know that its kinda late, but I solved this issue. The code is very similar to the implementation that Farhad suggested, but to solve the "jumping" window, you need to update the current position of the mouse also in the event filter:
if (object == ui->frame_title && event->type() == QEvent::MouseButtonPress)
{
QMouseEvent* mouseEvent = (QMouseEvent*)event;
if (pressed == false){
current = mouseEvent->pos();
}
pressed = true;
return true;
}
Adding this, you get the current mouse location when the user first press the left-click.
Here is the full implementation:
void MainWindow::mousePressEvent(QMouseEvent *event)
{
current = event->pos();
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if(pressed)
this->move(mapToParent(event->pos() - current));
}
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->frame_title && event->type() == QEvent::MouseButtonPress)
{
QMouseEvent* mouseEvent = (QMouseEvent*)event;
if (pressed == false){
current = mouseEvent->pos();
}
pressed = true;
return true;
}
if (object == ui->frame_title && event->type() == QEvent::MouseButtonRelease)
{
pressed = false;
return true;
}
else
return false;
}
Then in your constructor, just add (frame_title is my titlebar):
ui->frame_title->installEventFilter(this);
I suggest you to use eventFilter to get event MousePress and MouseRelease:
void MainApp::mousePressEvent(QMouseEvent *event)
{
current = event->pos();
}
void MainApp::mouseMoveEvent(QMouseEvent *event)
{
if(pressed)
this->move(mapToParent(event->pos() - current));
}
bool MainApp::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->label && event->type() == QEvent::MouseButtonPress)
{
pressed = true;
return true;
}
if (object == ui->label && event->type() == QEvent::MouseButtonRelease)
{
pressed = false;
return true;
}
else
return false;
}
This is a sample project for your question on github download here.
You can re-implement QLabel class and impalement mousePressEvent
Example :
header file
#ifndef MYLABLE_H
#define MYLABLE_H
#include <QEvent>
#include <QObject>
#include <QLabel>
class MyLable : public QLabel
{
Q_OBJECT
public:
explicit MyLable(QWidget *parent = 0);
QPoint mpos;
signals:
public slots:
// QWidget interface
protected:
void mousePressEvent(QMouseEvent *);
};
#endif // MYLABLE_H
.cpp
#include "mylable.h"
#include <QMouseEvent>
MyLable::MyLable(QWidget *parent) : QLabel(parent)
{
}
void MyLable::mousePressEvent(QMouseEvent * event)
{
if (event->buttons() & Qt::LeftButton)
{
QPoint diff = event->pos() - mpos;
QPoint newpos = this->pos() + diff;
this-> parentWidget()->move(newpos);
}
}
I'm building a simple level editor for my game using Qt. To navigate the 3d scene i need to use the keyboard and the mouse at the same time.
This is what i have so far and it works but when i move using WASD i cant look around. How to capture and respond to keyboard and mouse events at the same time ?
void MainWindow::mousePressEvent(QMouseEvent* event)
{
if(event->buttons() == Qt::LeftButton && actionCamera)
{
ui->renderWindow->trackMouse = true;
}
}
void MainWindow::mouseReleaseEvent(QMouseEvent* event)
{
ui->renderWindow->trackMouse = false;
}
void MainWindow::keyPressEvent(QKeyEvent* event)
{
if(event->key() == Qt::Key_W)
{
ui->renderWindow->moveForward = true;
}
if(event->key() == Qt::Key_S)
{
ui->renderWindow->moveBackwards = true;
}
if(event->key() == Qt::Key_A)
{
ui->renderWindow->moveLeft = true;
}
if(event->key() == Qt::Key_D)
{
ui->renderWindow->moveRight = true;
}
}
void MainWindow::keyReleaseEvent(QKeyEvent* event)
{
if(event->key() == Qt::Key_W)
{
ui->renderWindow->moveForward = false;
}
if(event->key() == Qt::Key_S)
{
ui->renderWindow->moveBackwards = false;
}
if(event->key() == Qt::Key_A)
{
ui->renderWindow->moveLeft = false;
}
if(event->key() == Qt::Key_D)
{
ui->renderWindow->moveRight = false;
}
}
I want a widget to animate its opacity when it is shown/hidden. I used the below code, but it does not work.
If I animate the property "maximumHeight", it gets animated in show(), but not in hide(). Could someone tell me where I am going wrong?
Header file
byeform.h
#include <QWidget>
#include <QPropertyAnimation>
namespace Ui {
class ByeForm;
}
class ByeForm : public QWidget
{
Q_OBJECT
public:
explicit ByeForm(QWidget *parent = 0);
~ByeForm();
private:
Ui::ByeForm *ui;
QPropertyAnimation *mpTransition;
protected:
bool eventFilter(QObject *obj, QEvent *event);
};
Source file
byeform.cpp
#include "byeform.h"
#include "ui_byeform.h"
#include <QDebug>
ByeForm::ByeForm(QWidget *parent) :
QWidget(parent),
ui(new Ui::ByeForm)
{
ui->setupUi(this);
this->installEventFilter(this);
mpTransition = new QPropertyAnimation(this, "windowOpacity");
mpTransition->setDuration(1000);
mpTransition->setStartValue(0.00);
mpTransition->setEndValue(1.00);
}
ByeForm::~ByeForm()
{
delete ui;
}
bool ByeForm::eventFilter(QObject *obj, QEvent *event)
{
if (this == obj && QEvent::Show == event->type())
{
qDebug() << Q_FUNC_INFO << "in show";
mpTransition->setDirection(QAbstractAnimation::Forward);
mpTransition->start();
}
else if (this == obj && (QEvent::Hide == event->type() ||
QEvent::Close == event->type()))
{
mpTransition->setDirection(QAbstractAnimation::Backward);
mpTransition->start();
}
return false;
}
Does this fix it?
bool ByeForm::eventFilter(QObject *obj, QEvent *event)
{
if (this == obj && QEvent::Show == event->type())
{
qDebug() << Q_FUNC_INFO << "in show";
mpTransition->setDirection(QAbstractAnimation::Forward);
mpTransition->start();
return true; // you might want to remove this line
}
else if (this == obj && (QEvent::Hide == event->type() ||
QEvent::Close == event->type()))
{
mpTransition->setDirection(QAbstractAnimation::Backward);
mpTransition->start();
return true; // you might want to remove this line
}
return QWidget::eventFilter(obj, event);
}
Ofcourse, it doesn't work because it's already hidden when you start the animation. You need to prolong the visibility until your animation has finished.
Like this, maybe:
void ByeForm::setVisible(bool visible)
{
if(isVisible() && !visible) // transition to hide
{
// m_bHideCalled = true;
mpTransition->setDirection(QAbstractAnimation::Backward);
mpTransition->start();
QTimer::singleShot(1000, this, SLOT(hide());
}
if(!isVisible() && visible) // transition to show
{
mpTransition->setDirection(QAbstractAnimation::Forward);
mpTransition->start();
show();
}
// if(m_bHideCalled)
// {
// m_bHideCalled = false;
// hide();
// }
}
Note that you MIGHT need the m_bHideCalled. Set it to false in the constructor. The name could be better though.
It works, but I think that it not good way to do this (I think that you should be do animate before close event will coming)
bool ByeForm::eventFilter(QObject *obj, QEvent *event)
{
if (this == obj && QEvent::Show == event->type())
{
qDebug() << Q_FUNC_INFO << "in show";
mpTransition->setDirection(QAbstractAnimation::Forward);
mpTransition->start();
}
else if (this == obj && (QEvent::Hide == event->type() ||
QEvent::Close == event->type()))
{
mpTransition->setDirection(QAbstractAnimation::Backward);
mpTransition->start();
while (mpTransition->state() == QAbstractAnimation::Running)
{
QApplication::processEvents();
}
}
return false;
}
Other method
Also you can override closeEvent method like this:
void MainWindow::closeEvent(QCloseEvent* e)
{
mpTransition->setDirection(QAbstractAnimation::Backward);
mpTransition->start();
e->ignore();
}
but in this case you should do something after animate will finished (for example connect on signal finished and call some method for closing window/application/etc).
Also you should be check, would manually call close event or by user operations.