QT from entry to soil - mouse event

introduction
Personally, the event mechanism is the most difficult and subtle part of Qt. There are two main types of events:

  1. Occurs when interacting with a user. For example, press the mouse (mousepress event) and hit the keyboard (keyPressEvent).
  2. The system automatically occurs, such as timer event, etc.

When an event occurs (for example, pressing the mouse as mentioned above), a QEvent object will be generated (here is QMouseEvent, a subclass of QEvent), and this QEvent object will be passed to the event function of the current component. If the current component does not have an event filter installed (this will be mentioned later), it will be issued to the corresponding xxevent function by the event function (mousePressEvent function here).

It should be distinguished that events and signals are not the same.

For example, when the mouse clicks a button, the mouse event (QMouseEvent), and the button itself emits a clicked () signal. Generally speaking, we only need to focus on click signals, not mouse events. However, when we want to do additional operations on the button without signal processing, events are a good choice. The close event (QCloseEvent) is a common event.

**

1, Events

**
All event classes in Qt inherit from QEvent. After the event object is created, Qt passes the event object to the event() function of QObject. The event() function does not handle events directly, but is assigned to a specific event handler according to the type of event object.

The signal is bound to the slot function through connect() to process the response. How is the event handled?
There are five common ways to handle events:

  1. Re implement the event handling functions of the part, such as paintEvent(), mousePressEvent(). This is the most commonly used method, but it can only be used to deal with specific events of specific parts (that is, it needs to create new classes to implement)
  2. Re implement the notify() function. This function is powerful and provides complete control. You can get them between events through the event filter. However, it can only handle one event at a time.
  3. Install the event filter on the QApplication object. Because a program has only one QApplication object, it implements the same function as the notify() function. The advantage is that it can handle multiple events at the same time.
  4. Re implement the event() function. The event() function of the QObject class can get the event before it reaches the default event handler.
  5. Install the event filter on the object. Using the event filter, you can handle the events of different sub components simultaneously in another interface class (implemented in this class)

The most commonly used method in practical programming is method (1), followed by method (5). Method 2 needs to inherit the QApplication class, and method 3 needs a global event filter to slow down the transmission of events.

Mouse events:

Common mouse events: (this article uses method 1 to handle events: Rewrite mouse events)

void mousePressEvent(QMouseEvent *event); // single click
void mouseReleaseEvent(QMouseEvent *event); // release
void mouseDoubleClickEvent(QMouseEvent *event); // double-click
void mouseMoveEvent(QMouseEvent *event); // move
void wheelEvent(QWheelEvent *event); // pulley
When using mouse events, add header file: #include

Override event framework:

one ️⃣ Mouse down event

void Widget::mousePressEvent(QMouseEvent *event)
{
    // If the left mouse button is pressed   
    if(event->button() == Qt::LeftButton){
        ···
    }
    // If you press the right mouse button
    else if(event->button() == Qt::RightButton){
       ···
    }
}

two ️⃣ Mouse movement event

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    // buttons() must be used here
    if(event->buttons() & Qt::LeftButton){  //Bitwise AND
       ···
    }
}

By default, triggering events can only be triggered after clicking. Can be set to auto trigger: setMouseTracking(true);

three ️⃣ Mouse release event

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
   ···
}

four ️⃣ Mouse double click event

void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
    // If the left mouse button is pressed
    if(event->button() == Qt::LeftButton){
      
        ···
    }
}

five ️⃣ Wheel event

void Widget::wheelEvent(QWheelEvent *event)
{
    // When the roller is away from the user
    if(event->delta() > 0){
        ···
    }else{//When the roller rotates in the direction of the user
        ···
    }
}

Example demonstration (in the label control, move the mouse to obtain the real-time position and display it on the interface)

Create the mylabel class and set the base class to QLabel

Here, a method similar to a custom control is used to encapsulate the Mylabel class. The base class QLabel is set to promote the label control in the ui interface (that is, the label control is associated with Mylabel, and the two base classes must be the same when promoting)

In mylabel Mouse events declared in H

#pragma once
#include <qlabel.h>

class mylabel : public QLabel
{
public:
    mylabel(QWidget* parent = 0);
    ~mylabel();
public:
    //Mouse movement event
    void mouseMoveEvent(QMouseEvent* event);
    //Mouse down event
    void mousePressEvent(QMouseEvent* event);
    //Mouse release event
    void mouseReleaseEvent(QMouseEvent* event);
};

In mylabel Overriding events in CPP

#include "mylabel.h"
#include"QMouseEvent"


mylabel::mylabel(QWidget* parent) :QLabel(parent)
{
    
}
mylabel::~mylabel()
{

}
//Mouse movement display coordinates
void mylabel::mouseMoveEvent(QMouseEvent* event)
{
    if (event->buttons() & Qt::LeftButton)  //Bit pressing and (only left click to move)
    { 
        QString str = QString("Move:(X:%1,Y:%2)").arg(event->x()).arg(event->y());
         this->setText(str);
         
    }
    
}
//Press the mouse to display "ok, mouse is press"
void mylabel::mousePressEvent(QMouseEvent* event)
{
    setText("Ok, mouse is press");

}
//Mouse release clear display
void mylabel::mouseReleaseEvent(QMouseEvent* event)
{
    setText(" ");
}

Declare the class object of mylabel in the main function (QTest.cpp) (that is, the label control that declares a mylabel class)

#include "qtest.h"

QTest::QTest(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    //Declare the control of the mylabel class
    mylabel* label1 = new mylabel(this);
    label1->setGeometry(QRect(130, 100, 271, 161));
    //Set border
    label1->setFrameShape(QFrame::Panel);
}

In addition, when setMouseTracking(true) is called; When (i.e. setting the mouse status to auto trigger), you need to remove the if statement of the mouse movement event (because you don't need to click to trigger)

Modify maylabel CPP event:

#include "mylabel.h"
#include"QMouseEvent"


mylabel::mylabel(QWidget* parent) :QLabel(parent)
{
    //Set mouse status (auto trigger)
    setMouseTracking(true);
}
mylabel::~mylabel()
{

}
//Mouse movement display coordinates
void mylabel::mouseMoveEvent(QMouseEvent* event)
{
   QString str = QString("Move:(X:%1,Y:%2)").arg(event->x()).arg(event->y());
   this->setText(str);
}
//Press the mouse to display "ok, mouse is press"
void mylabel::mousePressEvent(QMouseEvent* event)
{
    setText("Ok, mouse is press");

}
//Mouse release clear display
void mylabel::mouseReleaseEvent(QMouseEvent* event)
{
    setText(" ");
}

Effect display:

😒 The code used here is to create the label control, so can you edit it with the ui interface and then improve the label control?

The answer is yes, but it should be noted that global inclusion cannot be selected here
Insert picture description here

Otherwise:

I think the main reasons are:

In this example, a new mylabel class is created, instead of a common QT control (3) - Custom Control encapsulation. In this blog post, a new designer interface class (including UI. H. CPP) is directly added. When global inclusion is selected, the main class is included.

In fact, there is also a solution: you need to put the address of the custom control under the project directory here in the header file of the promotion interface (address of this article: C:/Users/WFD/Desktop/QTest/QTest/mylabel.h)

**

2, Event distribution: event function

**
The above-mentioned xxevent function is called event handler. The function of event is to distribute events. If you want to perform some operations before event distribution, such as listening (blocking) mouse press events.

If you want to do something before event distribution, you can override the event() function. For example, if we want to block the mouse click event, we will override the event() function in the new Mylabel class (the parent class of this class is QLabel)

In mylabel Declare event event in H

#include"qlabel.h"
class Mylabel : public QLabel
{
public:
    explicit Mylabel(QWidget* parent = 0);

    //Mouse down event
    void mousePressEvent(QMouseEvent* event); 
    //Mouse release event
    void mouseReleaseEvent(QMouseEvent* event);
    //Declare event event
    bool event(QEvent* e);
};

In mylabel Override the event event in CPP.

#include "Mylabel.h"
#include"QMouseEvent"

Mylabel::Mylabel(QWidget* parent) :QLabel(parent)
{

}

//Override mouse down events
void Mylabel::mousePressEvent(QMouseEvent* event)
{
    this->setText(QString("mouse is press x:%1,y:%2").arg(event->x()).arg(event->y()));
}
//Override mouse release event
void Mylabel::mouseReleaseEvent(QMouseEvent* event)
{
    this->setText("mouse is release ");
}
//Override event event
bool Mylabel::event(QEvent* e)
{
    //If the mouse is pressed, the event distribution will be intercepted
    if (e->type()==QEvent::MouseButtonPress)
    {
        //Static conversion (converting QEvent objects to QMouseEvent objects)
        QMouseEvent* event = static_cast<QMouseEvent*>(e);
        this->setText(QString("event mouse is press x:%1,y:%2").arg(event->x()).arg(event->y()));
        return true;//Return to ture, indicating that the user handles the event and does not distribute it down (that is, intercept the above press event)
    }
    return QLabel::event(e);
}

Click the mouse to see that the event is triggered (that is, the event blocking mousePressEvent). Special attention should be paid to the event function distributed to the parent class when blocking distribution is not required. That is, (return qlabel:: event (E);)

As you can see, event () is a place to focus on different types of events. If you don't want to rewrite a lot of event handlers, you can rewrite the event() function to judge different events through QEvent::type(). Since rewriting the event () function requires careful attention to the call of the function with the same name of the parent class, and problems may occur if you are not careful, it is generally recommended to rewrite only the event processor (of course, you must remember whether you should call the processor with the same name of the parent class).
**

3, Event filter (Even Filter)

**
In some application scenarios, it is necessary to intercept the event of a component so that the event does not propagate to other components. At this time, an event filter can be installed for this component or its parent component, which intercepts before event distribution.

There are two steps to filter events:

one ️⃣ Install a filter on the QObject component (call the installEvenFilter function)

void QObject::installEventFilter ( QObject * filterObj );

The parameter filterobj refers to who installs the filter for the component (usually the parent class)

This function accepts a parameter of type QObject *. Remember what we just said, the eventFilter() function is a member function of QObject, so any QObject can be used as an event filter (the problem is that if you do not rewrite the eventFilter() function, the event filter has no effect, because nothing will be filtered by default). Existing filters can be removed through the QObject::removeEventFilter() function.
We can install multiple event handlers on an object by calling the installEventFilter() function multiple times. If there are multiple event filters for an object, the last installed will be executed first, that is, in the order of last in first out.

two ️⃣ Override of event filter (evenFilter function)

virtual bool QObject::eventFilter ( QObject * watched, QEvent * event );

You can see that the function has two parameters, one is the component of the specific event, and the other is the event (the generated QEvent object). When the event is a type of interest, we can process it in place and make it no longer forward to other components. The return value of the function is also of bool type. Its function is similar to that of the even function. If it returns true, it will not be forwarded, and if it returns false, it will continue to be processed.

Example: block the mouse press event in the above code through the event filter

#include "qtest.h"
#include"qmouseevent"

QTest::QTest(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    //Step 1: add a filter to the label
    ui.label->installEventFilter(this);


}
//Step 2: rewrite the filter event
bool QTest::eventFilter(QObject* obj, QEvent* e)
{
    if (obj == ui.label)
    {
        //If the mouse is pressed, the event distribution will be intercepted
        if (e->type() == QEvent::MouseButtonPress)
        {
            QMouseEvent* event = static_cast<QMouseEvent*>(e);
            ui.label->setText(QString("eventfilter mouse is press x:%1,y:%2").arg(event->x()).arg(event->y()));
            return true;//Return to ture, indicating that the user handles the event and does not distribute it down (that is, intercept the above press event)
        }
    }
    return QWidget::eventFilter(obj, e);
}

//Override mouse down events
void QTest::mousePressEvent(QMouseEvent* event)
{
    ui.label->setText(QString("mouse is press x:%1,y:%2").arg(event->x()).arg(event->y()));
}

//Override event distribution
bool QTest::event(QEvent* e)
{
    //If the mouse is pressed, the event distribution will be intercepted
    if (e->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent* event = static_cast<QMouseEvent*>(e);
        ui.label->setText(QString("event mouse is press x:%1,y:%2").arg(event->x()).arg(event->y()));
        return true;//Return to ture, indicating that the user handles the event and does not distribute it down (that is, intercept the above press event)
    }
    return QWidget::event(e);
}

Operation results:

You can see that the mouse press is monitored in the filter event (that is, the subsequent event distribution and mouse press are blocked)

Keywords: C++ OpenCV Qt UI

Added by mtwildcard on Sun, 16 Jan 2022 00:32:32 +0200