keypress.h
#ifndef KEYPRESS_H
#define KEYPRESS_H
#include <QObject>
#include <QKeyEvent>
class keypress : public QObject {
Q_OBJECT public:
explicit keypress(QObject *parent = nullptr);
void keyPressEvent(QKeyEvent *e);
};
#endif // KEYPRESS_H
keypress.cpp
#include "keypress.h"
#include <QDebug>
keypress::keypress(QObject *parent)
: QObject{parent}
{
}
void keypress::keyPressEvent(QKeyEvent *e)
{
qDebug() <<"Key clicked : "<<e->key();
}
I am new to QKeyEvent and I am not able to call the keyPressEvent function. Should i call the keyPressEvent function inside the constructor?
I also have to display a connect with keyPressEvent function and a timer of 50 milli seconds even if it doesn't receive any keypress.
Thanks in Advance!
If you want to implement keyPressEvent in the widget/dialog/control, you can override keyPressEvent.
Here is another link:
QWidget keyPressEvent override
if you want to implement key press yourself and installed on other widgets, you can refer to the code below,
From QObject::installEventFilter,
class KeyPressEater : public QObject
{
Q_OBJECT
...
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};
bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
qDebug("Ate key press %d", keyEvent->key());
return true;
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
}
And here's how to install it on two widgets:
KeyPressEater *keyPressEater = new KeyPressEater(this);
QPushButton *pushButton = new QPushButton(this);
QListView *listView = new QListView(this);
pushButton->installEventFilter(keyPressEater);
listView->installEventFilter(keyPressEater);
Hope it helps you.
Related
I am new in qt and c++. I have a qgraphicsview to plot signal. I would zoom specific area with mouse clicking and rectangle drawing. So I need mouse pressed position and dragged position. For this I do such this:
in header file:
#include <QtWidgets/QMainWindow>
#include <QGraphicsScene>
#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>
#include "ui_QtGuiApplication.h"
class QtGuiApplication : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication(QWidget *parent = Q_NULLPTR);
protected:
void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event);
bool eventFilter(QObject *obj, QEvent *ev);
private:
Ui::QtGuiApplicationClass ui;
QPoint Zoom_point1_;
QPoint Zoom_point2_;
QGraphicsScene* scene = new QGraphicsScene();
};
in source file:
QtGuiApplication::QtGuiApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.graphicsView->installEventFilter(this);
ui.graphicsView->setMouseTracking(true);
}
bool QtGuiApplication::eventFilter(QObject * obj, QEvent * ev)
{
if (obj == ui.graphicsView)
if (ev->type() == QEvent::MouseMove)
{
QMouseEvent *mEvent = (QMouseEvent*)ev;
Zoom_point2_ = mEvent->pos();
}
return false;
}
void QtGuiApplication::mouseMoveEvent(QMouseEvent * ev)
{
Zoom_point2_ = ev->globalPos();
//do some thing …
}
void QtGuiApplication::mousePressEvent(QMouseEvent * ev)
{
Zoom_point1_ = ev->globalPos();
}
When I press and move mouse in graphicsview, I can recognize the clicked position but mouseMoveEvent(QMouseEvent * ev) never be calle. and also obj == ui.graphicsView statement in eventFilter never be occurred.What's wrong with me? How can I fix it?
By Installing event filter on the viewport of the QgraphicsView object such as
ui.graphicsView->viewport()->installEventFilter(this);
and adding below condition on eventfilter
if (ui.graphicsView->viewport())
if (ev->type() == QEvent::MouseMove)
{
QMouseEvent *mEvent = (QMouseEvent*)ev;
Zoom_point2_ = mEvent->pos();
}
problem solved.
I don't know how to emit a signal when the user changes of row with the keyboard by pressing up or down arrow key in QTableWidget. And after, I will have to use this signal to make some changes to my video.
How can I implement that?
Subclass the class QTableWidget by adding two signals :
class myTableWidget: public QTableWidget
{
public:
myTableWidget() {}
~myTableWidget() {}
private:
void keyPressEvent(QKeyEvent* event)
{
if(event->key() == Qt::Key_Up)
emit keyUpPressed();
else if(event->key() == Qt::Key_Down)
emit keyDownPressed();
else
QWidget::keyPressEvent(event);
}
signals :
keyUpPressed();
keyDownPressed();
};
In your class where you use the video, add two slots (and let's say your class is named yourClass) :
public slots :
void onKeyUpPressed();
void onKeyDownPressed();
Now you can use the signals and slots connection in your main class like this :
myTableWidget* table = new myTableWidget();
connect(table, SIGNAL(keyUpPressed()), this, SLOT(onKeyUpPressed()));
connect(table, SIGNAL(keyDownPressed()), this, SLOT(onKeyDownPressed()));
Then, in your slots, you can process your video.
void yourClass::onKeyUpPressed()
{
// do something here
}
void yourClass::onKeyDownPressed()
{
// do something else here
}
An alternative is to install an event filter.
EDIT : from your comment, your class inherits QStyledItemDelegate so you can just override the function eventFilter like this :
bool myTableWidget::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Up)
emit keyUpPressed();
else if(event->key() == Qt::Key_Down)
emit keyDownPressed();
}
// standard event processing
return QStyledItemDelegate::eventFilter(obj, event);
}
Then, it is the same for the slots in yourClass.
You probably want to connect to to signal currentCellChanged this will deal with both mouse clicks and keyboard movement and give you the indices of the newly selected cell.
To catch a signal from key event you can inherit from QTableWidget and override method keyPressEvent(QKeyEvent *event), for example:
.H file:
class CustomTableWidget : public QTableWidget
{
Q_OBJECT
protected:
void keyPressEvent(QKeyEvent *event);
public:
explicit CustomTableWidget(QWidget *parent = 0);
~CustomTableWidget();
signals:
void upEvent(const QModelIndex &index);
void downEvent(const QModelIndex &index);
.CPP file:
void CustomTableWidget::keyPressEvent(QKeyEvent *event)
{
switch(event->key()) {
case Qt::Key_Up: emit upEvent(currentIndex());
break;
case Qt::Key_Down: emit downEvent(currentIndex());
break;
default: QTableWidget::keyPressEvent(event);
}
}
I've a QGridLayout where each cell contains my custom widget QFrameExtended defined as follow:
In .h:
#ifndef QFRAMEEXTENDED_H
#define QFRAMEEXTENDED_H
#include <QObject>
#include <QFrame>
class QFrameExtended : public QFrame
{
Q_OBJECT
private:
public:
int id;
explicit QFrameExtended(QWidget *parent = 0);
signals:
void mousePressEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
void pressed(QFrameExtended *);
void released(QFrameExtended *);
public slots:
void on_mouse_press();
void on_mouse_release();
};
#endif // QFRAMEEXTENDED_H
In .cpp:
#include "qframe_extended.h"
QFrameExtended::QFrameExtended(QWidget *parent) : QFrame(parent)
{
this->id = /* Imagine here there is a function to generate an id */ ;
connect( this, SIGNAL( mousePressEvent(QMouseEvent*) ), this, SLOT( on_mouse_press() ) );
connect( this, SIGNAL( mouseReleaseEvent(QMouseEvent*) ), this, SLOT( on_mouse_release() ) );
}
void QFrameExtended::on_mouse_press() {
emit pressed(this);
}
void QFrameExtended::on_mouse_release() {
emit released(this);
}
My form creates the QGridLayout with the QFrameExtended widgets and for each of them defines an event handler:
/* ... */
/* This snippet of code is inside a loop that is creating frame objects */
connect(frame, &QFrameExtended::pressed, this, &MyForm::on_mouse_press);
connect(frame, &QFrameExtended::released, this, &MyForm::on_mouse_release);
/* ... */
and finally these are the event handlers:
void MyForm::on_mouse_press(QFrameExtended *frame) {
qDebug() << "Pressed here: " << frame->id << endl;
}
void MyForm::on_mouse_release(QFrameExtended *frame) {
qDebug() << "Released here: " << frame->id << endl;
}
When I click on a cell (i.e. a QFrameExtended widget) without release the button, I would see printed on the console the id of the cell. After I moved the mouse over another cell, when I release the button I would see printed the second id.
An example is an output like this:
Pressed here: 1
Released here: 3
but the reality is that when I press the mouse button over a QFrameExtended, he starting to grab all mouse events until I release the button. This is the expected behaviour:
Qt automatically grabs the mouse when a mouse button is pressed inside a widget; the widget will continue to receive mouse events until the last mouse button is released.
From: http://doc.qt.io/qt-4.8/qmouseevent.html
How can I change this behaviour? I'll really appreciate if you can give me also an example
Ok, I resolved following the tip of peppe. I tried to extend the QGridLayout but layouts don't support mouse events, because don't inherit from QWidget. So, I extended the QWidget that contains the layout.
In .h:
#ifndef QWIDGETEXTENDED_H
#define QWIDGETEXTENDED_H
#include <QWidget>
#include <QString>
#include <QMouseEvent>
#include "qframe_extended.h"
class QWidgetExtended : public QWidget
{
Q_OBJECT
public:
explicit QWidgetExtended(QWidget *parent = 0);
protected:
virtual void mousePressEvent(QMouseEvent *);
virtual void mouseReleaseEvent(QMouseEvent *);
signals:
void pressed(QFrameExtended *);
void released(QFrameExtended *);
};
#endif
In .cpp:
#include "qwidget_extended.h"
#include "qframe_extended.h"
QWidgetExtended::QWidgetExtended(QWidget *parent) : QWidget(parent)
{
}
void QWidgetExtended::mousePressEvent(QMouseEvent *event) {
QFrameExtended frame;
QWidget *widget = this->childAt(event->pos());
if (widget != NULL) {
QString widgetClassName(widget->metaObject()->className());
//I don't use explicitly the string because if one day someone changes the name of the class, the compiler will output an error
QString className(frame.metaObject()->className());
if (widgetClassName == className) {
emit pressed(dynamic_cast<QFrameExtended*> (widget));
}
}
}
void QWidgetExtended::mouseReleaseEvent(QMouseEvent *event) {
QFrameExtended frame;
QWidget *widget = this->childAt(event->pos());
if (widget != NULL) {
QString widgetClassName(widget->metaObject()->className());
//I don't use explicitly the string because if one day someone changes the name of the class, the compiler will output an error
QString className(frame.metaObject()->className());
if (widgetClassName == className) {
emit released(dynamic_cast<QFrameExtended*> (widget));
}
}
}
I'm trying to use a keyPressEvent, but it is only working when the window has focus and not any of the QWidgets.
Here is my code:
In customdialog.h:
class CustomDialog : public QDialog, public Ui::CustomDialog
{
Q_OBJECT
private:
Ui::CustomDialog *ui;
QString lastKey;
public:
CustomDialog(QWidget * parent = 0);
protected:
void keyPressEvent(QKeyEvent *e);
};
In customdialog.cpp:
void CustomDialog::keyPressEvent(QKeyEvent *e)
{
lastKey = e->text();
qDebug() << lastKey;
}
How can I make all widgets within this class use the same keyPressEvent?
You can solve your problem by installing event filters to every child of CustomDialog:
void CustomDialog::childEvent(QChildEvent *event)
{
if (event->added()) {
event->child()->installEventFilter(this);
}
}
bool CustomDialog::eventFilter(QObject *, QEvent *event)
{
if (event->type() == QEvent::KeyPress)
keyPressEvent(static_cast<QKeyEvent*>(event));
return false;
}
But since every ignored keyPress event is sent to the parent widget, you can get keyPressEvent called multiple times for the same event.
I ended up deciding not to use keyPressEvent in this case for my purposes. I just needed to get the last key pressed in a QTextBrowser. Here is what I ended up doing:
connect(ui->textBrowser, SIGNAL(textChanged()), this, SLOT(handleTextBrowser()));
void CustomDialog::handleTextBrowser()
{
QTextCursor cursor(ui->textBrowser->textCursor());
QString key = ui->textBrowser->toPlainText().mid(cursor.position() - 1, 1);
qDebug() << key;
}
I have a little problem, I need to set my event filter to QComboBox popup.
I need to catch events when left and right keys are pressed.
How can I do this?
Thank you!
You need to set the eventFilter on QComboBox's view() (http://qt-project.org/doc/qt-4.8/qcombobox.html#view).
You may need to add following code somewhere in your code.
void MyComboBox::keyPressEvent (QKeyEvent *event)
{
if (event->button() == Qt::Key_Left)
{
// handle left key press
}
if (event->button() == Qt::Key_Right)
{
// handle right key press
}
}
Hope this helps!
The question is quite old, but I provide my answer since it can help someone else.
After popup all events will be sent to the list view used for the QComboBox popup. You can get the things done using key handler class watching on events for list view.
KeyPressHandler.h:
class KeyPressHandler : public QObject
{
Q_OBJECT
public:
explicit KeyPressHandler(QObject *parent = nullptr);
virtual ~KeyPressHandler() override;
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};
KeyPressHandler.cpp:
#include <QCoreApplication>
KeyPressHandler::KeyPressHandler(QObject *parent) : QObject(parent)
{
}
KeyPressHandler::~KeyPressHandler()
{
}
bool KeyPressHandler::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
switch(keyEvent->key())
{
case Qt::Key_Left:
// Send press event for the Key_Up which understood by list view
QCoreApplication::postEvent(obj, new QKeyEvent(QEvent::KeyPress,
Qt::Key_Up,
Qt::NoModifier));
return true;
case Qt::Key_Right:
QCoreApplication::postEvent(obj, new QKeyEvent(QEvent::KeyPress,
Qt::Key_Down,
Qt::NoModifier));
return true;
default:
break;
}
}
// standard event processing
return QObject::eventFilter(obj, event);
}
In ComboBox you will need to install event filter when popup is shown.
It can be done in different ways, for example by overriding QComboBox::showPopup() function.
MyComboBox.h:
#include <memory>
#include <QComboBox>
class MyComboBox : public QComboBox
{
Q_OBJECT
public:
explicit MyComboBox(QWidget *parent = 0);
protected:
void showPopup() override;
void hidePopup() override;
private:
std::unique_ptr<KeyPressHandler> m_key_press_handler;
};
MyComboBox.cpp:
...
void MyComboBox::showPopup()
{
if(!m_key_press_handler)
{
m_key_press_handler.reset(new KeyPressHandler());
QAbstractItemView *v = view();
v->installEventFilter(m_key_press_handler.get());
}
QComboBox::showPopup();
}
void MyComboBox::hidePopup()
{
m_key_press_handler.reset(nullptr);
QComboBox::hidePopup();
}