Qt uses the event filter eventFilter to move (including pop-up windows) window movement (principle + implementation)

Preface

Since in actual development, the window's own title bar cannot satisfy our aesthetics, we hope to draw the window title bar by ourselves, but if the title bar is removed, the form cannot be moved, so you need to implement the form movement by yourself. At this time, you need to rewrite Mouse events.

The commonly used method is to rewrite the event handling function of the control: such as rewriting keyPressEvent(), mousePressEvent() and paintEvent(). This is the most commonly used event handling method. We have seen many examples of this.

Another way is to override QObject::event() and process the event before it reaches the event handler.

However, rewriting event processing functions such as mousePressEvent can only change the event action for the current window, and adding a pop-up window at this time cannot satisfy the movement.

Here is the third method: install an event filter for the QApplication object , qApp (the only QApplication object ) installs an event filter, each event of all objects in the program must be sent before being sent to any other event filter eventFilter() function.

1. Event mechanism in Qt

There are two main types of events:

  1. Occurs when interacting with the user. For example, press the mouse (mousePressEvent), hit the keyboard (keyPressEvent), etc.
  2. The system occurs automatically, such as timer events (timerEvent)

It has the following characteristics:
3. Each event corresponds to an event handler, such as mouse movement corresponds to mouseMoveEvent()
4. When an event occurs (for example, the mouse is pressed as mentioned above), a QEvent object is generated, this QEvent object Will be passed to the event function of the current component
5. In the main function of the Qt program, a QApplication object needs to be created, and then the exec function is called. This will make the program enter an endless loop, and continue to monitor the application's events, when an event occurs, a QEvent object is generated. This is called the event loop

When the Qt system processes events, there is a mechanism called event propagation mechanism . What we mainly do is to use the event propagation mechanism to filter global events .

Second, realize

1. The form can set custom properties to move
void CMainFrm::SetFrmAttribute()
{
    
    
    this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);	//屏蔽标题栏
    this->setProperty("canMove", true);	//设置自定义属性可移动
}
2. Get App with custom class

head File:

#ifndef CAPPINIT_H
#define CAPPINIT_H

#include <QObject>
#include <QApplication>
#include <QWidget>

class CAppInit : public QObject
{
    
    
    Q_OBJECT
public:
    static CAppInit* GetInstance();	//单例模式,需要用到锁
    ~CAppInit();

public:
    void startFilter();		//将该事件过滤器加入到QApplication中

protected:
    bool eventFilter(QObject *watched, QEvent *event) override;	//重写事件过滤器

private:
    explicit CAppInit(QObject *parent = nullptr);

private:
    static CAppInit*    m_pInstance;
    static QPoint       m_qMousePoint;		//记录当前位置
    static bool         m_bIsMousePressed;	//记录鼠标松放
};

#endif // CAPPINIT_H

cpp file

#include "CAppInit.h"
#include <QMutex>
#include <QMutexLocker>
#include <QMouseEvent>

CAppInit* CAppInit::m_pInstance = NULL;
QPoint CAppInit::m_qMousePoint;
bool CAppInit::m_bIsMousePressed = false;

CAppInit* CAppInit::GetInstance()
{
    
    
    if(m_pInstance == NULL)
    {
    
    
        QMutex mutex;
        QMutexLocker locker(&mutex);
        m_pInstance = new CAppInit;
    }
}

CAppInit::CAppInit(QObject *parent) : QObject(parent)
{
    
    

}

CAppInit::~CAppInit()
{
    
    
    m_pInstance = NULL;
}

void CAppInit::startFilter()
{
    
    
    qApp->installEventFilter(this);	//qApp为QApplication宏,qt中只有一个qApp
}

bool CAppInit::eventFilter(QObject *watched, QEvent *event)
{
    
    
    QWidget* pWidget = qobject_cast<QWidget*>(watched); //转换事件对象
    if(!pWidget->property("canMove").toBool())          //自定义属性,判断是否需要移动,如不需要则将事件送出
        return QObject::eventFilter(watched, event);

    QMouseEvent* pEvent = static_cast<QMouseEvent *>(event);    //将事件转换成鼠标事件,进行鼠标事件过滤
    switch (pEvent->type())
    {
    
    
    case QEvent::MouseButtonPress:
        if(pEvent->button() == Qt::LeftButton)
        {
    
    
            m_bIsMousePressed = true;
            m_qMousePoint = pEvent->globalPos() - pWidget->pos();   //如果左键按下则记录当前鼠标在widget中位置
        }
        return true;
    case QEvent::MouseButtonRelease:
        m_bIsMousePressed = false;
        return true;
    case QEvent::MouseMove:
        if(m_bIsMousePressed && (pEvent->buttons() == Qt::LeftButton))
        {
    
    
            pWidget->move(pEvent->globalPos() - m_qMousePoint);
            return true;
        }
    default:
        break;
    }

    return QObject::eventFilter(watched, event);
}

When using it, call CAppInit->GetInstance()->startFilter() directly in main.

Guess you like

Origin blog.csdn.net/qq_42956179/article/details/109614406