I need some virtual function/signal/event in a QApplication that centrally informs about any opened and closed window in the application (providing a pointer to the window object; including QMainWindow, QDialog, QWidget based windows).
This should work without manually registering all window instances and without manually manipulating each instance (e.g. by installing event filters or connections on each window object).
Also it should not be necessary to sub-class the tracked windows from some interface class or similar.
So, what is the best way in Qt to track all opened and closed windows in an application?
You must overwrite the notify method of QApplication(or QGuiApplication):
#include <QtWidgets>
class Application: public QApplication
{
public:
using QApplication::QApplication;
bool notify(QObject *receiver, QEvent *e) override
{
if(receiver->isWindowType()){
if(e->type() == QEvent::Show){
qDebug()<< receiver << "show";
}
else if (e->type() == QEvent::Close) {
qDebug()<< receiver << "close";
}
}
return QApplication::notify(receiver, e);
}
};
int main(int argc, char *argv[])
{
Application a(argc, argv);
QMainWindow m;
QDialog d;
QWidget w;
m.show();
d.show();
w.show();
return a.exec();
}
Update:
#include <QtWidgets>
class Application: public QApplication
{
public:
using QApplication::QApplication;
bool notify(QObject *receiver, QEvent *e) override
{
if(receiver->isWidgetType()){
QWidget *w = qobject_cast<QWidget *>(receiver);
if(w->isWindow()){
if(e->type() == QEvent::Show){
qDebug()<< w << "show";
}
else if (e->type() == QEvent::Close) {
qDebug()<< w << "close";
}
}
}
return QApplication::notify(receiver, e);
}
};
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);
}
}
Is there a way to connect a signal before executing a default handler? I'm looking for a way to execute my function prior to QLineEdit::textChanged signal to execute notification about maximum length limit.
GTK+ has connect_before(), connect() and connect_after(). Is there something similar in Qt?
You can use the keyPressEvent method to issue the custom signal.
#include <QtWidgets>
class LineEdit: public QLineEdit
{
Q_OBJECT
public:
using QLineEdit::QLineEdit;
signals:
void maxLengthSignal();
protected:
void keyPressEvent(QKeyEvent *event) override{
if(!event->text().isEmpty() && maxLength() == text().length())
emit maxLengthSignal();
QLineEdit::keyPressEvent(event);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LineEdit w;
QObject::connect(&w, &QLineEdit::textEdited, [](const QString & text){
qDebug()<< text;
});
QObject::connect(&w, &LineEdit::maxLengthSignal, [](){
qDebug()<< "maxLength signal";
});
w.setMaxLength(10);
w.show();
return a.exec();
}
#include "main.moc"
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;
}
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();
}
I'm trying to use QLocalServer as an ipc solution. The version of qt is 4.6
This is my main.cpp:
int main(int argc, const char*argv[]) {
QServer test();
while (true) {
}
}
This is my QServer class:
class QServer : public QObject
{
Q_OBJECT
public :
QServer ();
virtual ~QServer();
private :
QLocalServer* m_server;
QLocalSocket* m_connection;
private slots:
void socket_new_connection();
};
QServer::QServer()
{
m_server = new QLocalServer(this);
if (!m_server->listen("DLSERVER")) {
qDebug() << "Testing";
qDebug() << "Not able to start the server";
qDebug() << m_server->errorString();
qDebug() << "Server is " << m_server->isListening();
}
connect(m_server, SIGNAL(newConnection()),
this, SLOT(socket_new_connection()));
}
void
QServer::socket_new_connection()
{
m_connection = m_server->nextPendingConnection();
connect(clientConnection, SIGNAL(readyRead()),
this, SLOT(newData(clientConnection)));
}
This all compiles, however at runtime, when I try to connect newConnection(), I get a QSocketNotifier: Can only be used with threads started with QThread error.
I have tried wrapping this whole thing in a QThread, but I still got the same error.
Can anybody explain what I'm doing wrong or why there's even a thread involved?
The error message is misleading. You need a Qt event loop in order to use QSocketNotifier. The appropriate way to do that in your application is to create a QApplication (or if you don't want any graphical stuff, a QCoreApplication). Your main should look like:
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
QServer test();
app.exec();
return 0;
}
QCoreApplication::exec() starts the event loop (which replaces your while (true) {} loop).