In my QWidget there are some subwidgets like a QLineEdit and QLabels. I can easily check if my mouse is over a QLabel and if it was clicked on the right button. Not so on QLineEdit.
I tried to subclass QLineEdit and re-implement the mouseRelease, but it is never called.
The findChild method is to get the corresponding widget out off my UI.
How do I get the mouseRelease and whether it's left or right mouse button in a QLineEdit?
void Q_new_LineEdit::mouseReleaseEvent(QMouseEvent *e){
qDebug() << "found release";
QLineEdit::mouseReleaseEvent(e);
}
m_titleEdit = new Q_new_LineEdit();
m_titleEdit = findChild<QLineEdit *>("titleEdit",Qt::FindChildrenRecursively);
Clicks on labels are recognized, but the click on QLineEdit is not, like below:
void GripMenu::mouseReleaseEvent(QMouseEvent *event){
if (event->button()==Qt::RightButton){
//get click on QLineEdit
if (uiGrip->titleEdit->underMouse()){
//DO STH... But is never called
}
//change color of Label ...
if (uiGrip->col1note->underMouse()){
//DO STH...
}
}
I seem to be able to detect clicks on the line edit and distinguish which type it is in the class posted below which is very similar to what has been posted in the mentioned link
#ifndef MYDIALOG_H
#define MYDIALOG_H
#include <QDialog>
#include <QMouseEvent>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QtCore>
class MyClass: public QDialog
{
Q_OBJECT
public:
MyClass() :
layout(new QHBoxLayout),
lineEdit(new QLineEdit)
{
layout->addWidget(lineEdit);
this->setLayout(layout);
lineEdit->installEventFilter(this);
}
bool eventFilter(QObject* object, QEvent* event)
{
if(object == lineEdit && event->type() == QEvent::MouseButtonPress) {
QMouseEvent *k = static_cast<QMouseEvent *> (event);
if( k->button() == Qt::LeftButton ) {
qDebug() << "Left click";
} else if ( k->button() == Qt::RightButton ) {
qDebug() << "Right click";
}
}
return false;
}
private:
QHBoxLayout *layout;
QLineEdit *lineEdit;
};
#endif
main.cpp for completeness
#include "QApplication"
#include "myclass.h"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MyClass dialog;
dialog.show();
return app.exec();
}
Related
When an object of QLabel sub class is actived, how can one find if the mouse pointer is on the label and get its position if it is?
QWidegt::event() can check the event type of QEvent::WindowActivate, but it provides no information about mouse pointer position.
UPDATE
According to comment by #Mathias Schmid , I create the following code. It verifies itself that both focusInEvent and focusOutEvent can happen. However, I still cannot get the mouse pointer position. Maybe I am missing the part of "bind enable/disable of mouse tracking to focus in and out events", or something else.
#include "mainwindow.h"
#include <QApplication>
#include <QtWidgets>
#include <QtCore>
class MyLabel : public QLabel
{
public:
MyLabel(QWidget*parent = nullptr) : QLabel(parent)
{
setMouseTracking(true);
setFocusPolicy(Qt::FocusPolicy::StrongFocus);
}
protected:
virtual void focusInEvent(QFocusEvent *ev) override
{
(void)ev;
this->setText(__PRETTY_FUNCTION__);
}
virtual void focusOutEvent(QFocusEvent *ev) override
{
(void)ev;
this->setText(__PRETTY_FUNCTION__);
}
virtual void mouseMoveEvent(QMouseEvent *ev) override
{
this->setText(QString::number(ev->pos().x()) +", " +QString::number(ev->pos().y()));
QLabel::mouseMoveEvent(ev);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyLabel w;
w.setFixedSize(400, 300);
w.show();
return a.exec();
}
Update 2: solution
Thanks to #Mathias Schmid, the final solution is to use static function QCursor::pos() in focusInEvent().
#include "mainwindow.h"
#include <QApplication>
#include <QtWidgets>
#include <QtCore>
#include <QCursor>
class MyLabel : public QLabel
{
public:
MyLabel(QWidget*parent = nullptr) : QLabel(parent)
{
setMouseTracking(true);
setFocusPolicy(Qt::FocusPolicy::StrongFocus);
}
protected:
virtual void focusInEvent(QFocusEvent *ev) override
{
(void)ev;
QPoint pos = QCursor::pos();
QString msg = QString(__PRETTY_FUNCTION__) + ": \n" + QString::number(pos.x()) + ", " + QString::number(pos.y());
QPoint posLocal = this->mapFromGlobal(pos);
if(this->rect().contains(posLocal))
msg += "\nLocal pos: " + QString::number(posLocal.x()) + ", " + QString::number(posLocal.y());
this->setText(msg);
QLabel::focusInEvent(ev);
}
virtual void focusOutEvent(QFocusEvent *ev) override
{
(void)ev;
this->setText(QString(__PRETTY_FUNCTION__));
QLabel::focusOutEvent(ev);
}
virtual void mouseMoveEvent(QMouseEvent *ev) override
{
this->setText(QString::number(ev->pos().x()) +", " +QString::number(ev->pos().y()));
QLabel::mouseMoveEvent(ev);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyLabel w;
w.setFixedSize(450, 300);
w.show();
return a.exec();
}
To check if mouse cursor is on custom widget derived from QLabel at time when it gets focus just override focusInEvent() and handle mouse cursor position check there.
MyLabel.h
class MyLabel: public QLabel
{
Q_OBJECT
public:
MyLabel(QWidget *parent = nullptr);
~MyLabel();
protected:
virtual void focusInEvent(QFocusEvent *event) override;
};
MyLabel.cpp
MyLabel::MyLabel(QWidget *parent)
: QLabel(parent)
{
setFocusPolicy(Qt::StrongFocus);
}
MyLabel::~MyLabel()
{
}
void MyLabel::focusInEvent(QFocusEvent *event)
{
if (event) {
const QPoint cursorPos = QCursor::pos();
if (rect().contains(mapFromGlobal(cursorPos))) {
// TODO: Add desired action
}
QLabel::focusInEvent(event);
}
}
I would like to get mouse position inside my QListWidget. The tracking is fine when mouse hovers over all other QWidgets - QMainWindow, QPushButton, CentralWidget, etc., except QListWidget.
c++ file: test_1.cpp
#include "test_1.h"
#include "ui_test_1.h"
test_1::test_1(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::test_1)
{
ui->setupUi(this);
this->setMouseTracking(true);
ui->centralWidget->setMouseTracking(true);
ui->listWidget->setMouseTracking(true);
ui->pushButton->setMouseTracking(true);
ui->listWidget->addItem("aaa");
ui->listWidget->addItem("bbb");
ui->listWidget->addItem("ccc");
ui->listWidget->addItem("ddd");
ui->listWidget->addItem("eee");
}
void test_1::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << event->pos();
}
test_1::~test_1()
{
delete ui;
}
Header file: test_1.h
#ifndef TEST_1_H
#define TEST_1_H
#include <QMainWindow>
#include <QDebug>
#include <QMouseEvent>
namespace Ui {
class test_1;
}
class test_1 : public QMainWindow
{
Q_OBJECT
public:
explicit test_1(QWidget *parent = 0);
~test_1();
private:
Ui::test_1 *ui;
void mouseMoveEvent(QMouseEvent*);
};
#endif // TEST_1_H
Main: main.cpp
#include "test_1.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
test_1 w;
w.show();
return a.exec();
}
Output:
QPoint(359,141)
QPoint(358,141)
QPoint(357,140)
QPoint(356,140)
QPoint(355,140)
QPoint(354,139)
QPoint(353,139)
QPoint(352,139)
QPoint(351,139)
void test_2::mouseMoveEvent(QMouseEvent *event)
{
QPoint p = event->pos();
QRect widgetRect = ui->listWidget->rect();
if(widgetRect.contains(p))
{
qDebug() << "Inside";
ui->listWidget->grabMouse();
}
else
{
qDebug() << "Outside";
ui->listWidget->releaseMouse();
}
}
The right way of solving this is inheriting QListWidget and implementing void mouseMoveEvent(QMouseEvent *event)
But you have also another option, like installing an event filter on your QListWidget.
Add this in your contructor:
ui->listWidget->viewport()->installEventFilter(this);
And implement the event filter:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
{
qDebug() << Q_FUNC_INFO << "QEvent::MouseButtonPress";
}
if(event->type() == QEvent::MouseMove)
{
qDebug() << Q_FUNC_INFO << " pos: " << this->mapFromGlobal(QCursor::pos());
}
return false;
}
The software shown 3 widget:
Main window
Content widget, that cover most of the main window
custom widget, that cover part of both, the main window and the content widget.
The custom widget has a part (defined as a QRect) that need to be Event-opaque, while the surrounding zone has to be Event-transparent.
I tried with:
setAttribute(Qt::WA_TransparentForMouseEvents);
But all sub-widgets of custom become transparent also.
I also tried with setMask, but then the custom widget is unable to draw on the surrounding area.
How to achieve this partial event-transparency?
Example (it does not explain the full problem, just add a base on which to test solutions):
main.cpp
#include "transparentwidget.hpp"
#include "normalwidget.hpp"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Main Window
NormalWidget window;
window.resize(500,500);
window.setObjectName("window");
window.setStyleSheet("background-color: rgba(0,0,128,128); ");
// Content window
NormalWidget content(&window);
content.setObjectName("content");
content.resize(400, 400);
content.move(0,0);
content.setStyleSheet("background-color: rgba(128,0,0,128);");
TransparentWidget custom(&window);
custom.setObjectName("custom");
custom.resize(500, 200);
custom.setStyleSheet("background-color:rgba(0,128,0,128);");
window.show();
return a.exec();
}
transparentwidget.hpp
#ifndef TRANSPARENTWIDGET_H
#define TRANSPARENTWIDGET_H
#include <QWidget>
#include <QStyleOption>
#include <QPainter>
#include <QDebug>
#include <QEvent>
// This widget shall be transparent in some parts
class TransparentWidget : public QWidget
{
Q_OBJECT
public:
explicit TransparentWidget(QWidget *parent = 0): QWidget(parent)
{
// Start of solution with WA_TransparentForMouseEvents (not working)
setAttribute(Qt::WA_TransparentForMouseEvents);
// end solution with WA_TransparentForMouseEvents
}
~TransparentWidget(){}
protected:
QRect opaqueRect = QRect(0,0,400,100);
void paintEvent(QPaintEvent *)
{
// Solution with setMask, not working
QRegion reg(opaqueRect);
setMask(reg);
// end of setMask solution
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
bool event(QEvent *event)
{
// Starting of solution with event propagation (not working)
if (event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* e = static_cast<QMouseEvent*>(event);
if (e && !opaqueRect.contains(e->pos()) return false;
}
// end solution with event propagation.
if (event->type() == QEvent::MouseButtonPress) qDebug() << "Press: " << objectName();
else if(event->type() == QEvent::MouseButtonRelease) qDebug() << "Release: " << objectName();
return QWidget::event(event);
}
};
#endif
normalwidget.hpp
#ifndef NORMALWIDGET_H
#define NORMALWIDGET_H
#include <QWidget>
#include <QStyleOption>
#include <QPainter>
#include <QDebug>
#include <QEvent>
// Widgets that are not event-transparent
class NormalWidget : public QWidget
{
Q_OBJECT
public:
explicit NormalWidget(QWidget *parent = 0): QWidget(parent){}
~NormalWidget(){}
protected:
void paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
bool event(QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress) qDebug() << "Press: " << objectName();
else if(event->type() == QEvent::MouseButtonRelease) qDebug() << "Release: " << objectName();
}
};
#endif // NORMALWIDGET_H
Like the docs say:
When enabled, this attribute disables the delivery of mouse events to
the widget and its children.
The solution is to ignore all the mouse events inside TransparentWidget::event(). If you do a mouse event over a child of TransparentWidget, the event will be consumed by the child, otherwise it will be delivered to the parent of TransparentWidget:
bool TransparentWidget::event(QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease ||
event->type() == QEvent::MouseButtonRelease)
return false;
else
return QWidget::event(event);
}
How does one disable tooltips on a Qt4 QToolBar?
Using QAction::setToolTip("") does nothing and I can't find any settings related to disabling tooltips on either a QAction or QToolbar!
Example:
Toolbar.h
#ifndef TOOLBAR_H
#define TOOLBAR_H
#include <QtGui>
class Toolbar : public QToolBar
{
Q_OBJECT
public:
Toolbar()
{
QAction *action = this->addAction("Action");
action->setToolTip("");
}
bool event(QEvent *event)
{
if(event->type() == QEvent::ToolTip)
{
qDebug() << "QEvent::ToolTip";
}
return QToolBar::event(event);
}
};
#include "moc_Toolbar.cpp"
#endif // TOOLBAR_H
main.cpp
#include <QtGui>
#include "Toolbar.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
Toolbar *toolbar = new Toolbar;
window.addToolBar(toolbar);
window.setCentralWidget(new QWidget());
window.show();
return app.exec();
}
An event filter has to be used in this scenario.
Toolbar.h
#ifndef TOOLBAR_H
#define TOOLBAR_H
#include <QtGui>
class Toolbar : public QToolBar
{
Q_OBJECT
public:
Toolbar()
{
QAction *action = this->addAction("Action");
}
bool eventFilter(QObject *object, QEvent *event)
{
if(event->type() == QEvent::ToolTip)
{
return true;
}
return false;
}
};
#include "moc_Toolbar.cpp"
#endif // TOOLBAR_H
main.cpp
#include <QtGui>
#include "Toolbar.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
Toolbar *toolbar = new Toolbar;
qApp->installEventFilter(toolbar);
window.addToolBar(toolbar);
window.setCentralWidget(new QWidget());
window.show();
return app.exec();
}
I'm not quite sure how to localize this to just the Toolbar but I don't like tooltips anyway so this is a quick way to disable all of them.
How can I delete a value from a cell in a QTableView?
I created a QTableView but if I press the cancel button of the keyboard on the selected cell nothing happens.
If I want to delete that value I have to double-click the cell and press cancel but I want to delete the value without the double-click, just selecting the cell and press Canc.
Is keyEvent->key() useful?
#Chernobyl
MAINWINDOW.H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QKeyEvent>
#include <QTableView>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) ;
~MainWindow();
QTableView *griglia;
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
Ui::MainWindow *ui;
};
#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);
qApp->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == griglia && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Cancel)
{
QModelIndex in =griglia->currentIndex();
griglia->model()->setData(in," ");
}
}
return QObject::eventFilter(obj, event);
}
MainWindow::~MainWindow()
{
delete ui;
}
MAIN.CPP
#include "mainwindow.h"
#include "itemdelegate.h"
#include "mymodel.h"
#include <QApplication>
#include <QtGui>
#include <QtCore>
#include <QtWidgets>
#include <QFile>
#include <QString>
#include <QTextStream>
#include <QIdentityProxyModel>
#include <QRegExpValidator>
#define GRIGLIA_RX "^[F0-9]|1[0-9]|2[0-4]$"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFile styleFile( "style.qss" );
styleFile.open( QFile::ReadOnly );
QString style( styleFile.readAll() );
a.setStyleSheet( style );
QWidget *mainWindow = new QWidget;
QStandardItemModel *model = new QStandardItemModel(48,33);
QTableView *griglia = new QTableView;
griglia->setModel(model);
QPushButton *calcola = new QPushButton;
calcola->setText("CALCOLA");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(griglia);
layout->addWidget(calcola);
mainWindow->setLayout(layout);
ItemDelegate *itDelegate = new ItemDelegate;
griglia->setItemDelegate(itDelegate);
mainWindow->showMaximized();
return a.exec();
}
I added QDebug line but if I press Canc no message appears
Use next event filter as in my example or reimplement keyPressEvent:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->tableView && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Shift)
{
qDebug() << "works";
QModelIndex in = ui->tableView->currentIndex();
ui->tableView->model()->setData(in,"");
//ui->tableView->model()->setData(ui->tableView->currentIndex(),""); //or just this
}
}
return QObject::eventFilter(obj, event);
}
To use eventFilter you should also:
protected:
bool eventFilter(QObject *obj, QEvent *event);//in header
and
qApp->installEventFilter(this);//in constructor
You can use Qt::Key_Shift or Qt::Key_Cancel or something else.
EDIT
MAINWINDOW.H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QKeyEvent>
#include <QTableView>
#include "itemdelegate.h"
#include "mymodel.h"
#include <QApplication>
#include <QtGui>
#include <QtCore>
#include <QtWidgets>
#include <QFile>
#include <QString>
#include <QTextStream>
#include <QIdentityProxyModel>
#include <QRegExpValidator>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) ;
~MainWindow();
QTableView *griglia;
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
Ui::MainWindow *ui;
};
#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);
QWidget *mainWindow = new QWidget;
QStandardItemModel *model = new QStandardItemModel(48,33);
griglia = new QTableView;
griglia->setModel(model);
QPushButton *calcola = new QPushButton;
calcola->setText("CALCOLA");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(griglia);
layout->addWidget(calcola);
mainWindow->setLayout(layout);
ItemDelegate *itDelegate = new ItemDelegate;
griglia->setItemDelegate(itDelegate);
this->setCentralWidget(mainWindow);
qApp->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == griglia && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Cancel)
{
QModelIndex in =griglia->currentIndex();
griglia->model()->setData(in," ");
}
}
return QObject::eventFilter(obj, event);
}
MainWindow::~MainWindow()
{
delete ui;
}
MAIN.CPP
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFile styleFile( "style.qss" );
styleFile.open( QFile::ReadOnly );
QString style( styleFile.readAll() );
a.setStyleSheet( style );
MainWindow my;
my.showMaximized();
return a.exec();
}
Now you should see "works" and cell should be cleared, another code optimization do by yourself.
Addition for multiple selection:
if(obj == ui->tableView && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Shift)
{
qDebug() << "Up";
//ui->tableView->model()->setData(ui->tableView->currentIndex(),"");
QList<QModelIndex> index = ui->tableView->selectionModel()->selectedIndexes();
for(int i = 0; i < index.size(); i++)
ui->tableView->model()->setData(index.at(i),"");
}
}