[C++] Qt-Events (Part 1) (events, overriding events, event distribution)

event

Events are emitted at different times by the system or Qt itself. For example, when the user presses the mouse, types on the keyboard, or when the window needs to be redrawn, a corresponding event will be emitted. Some events are emitted in response to user operations, such as keyboard events; other events are automatically emitted by the system, such as timer events (this type of event was used in the game shell we wrote before) .

It's easy to confuse Qt's events and signal slots. Events are actually so-called event-driven. Signals are sent by specific objects and then immediately handed over to the slot connected by the connect function for processing. For events, Qt uses an **Event Queue (windowSystemEventQueue)** to maintain all emitted events. When a new event is generated, it will be appended to the end of the event queue. After the previous event is completed, the subsequent events will be taken out. for processing. However, when necessary, Qt events can be processed directly without entering the event queue.

If we use components, we care about signals and slots; if we customize components, we care about events.

Override event

Generally, when we rewrite the events of a certain component, we need to customize the class, inherit the corresponding component class, and rewrite the events of interest.

Create a new subclass:

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-NQ3AxlrK-1688187869334) (C++.assets/image-20230619200032369.png)]

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-mmx0Xx5N-1688187869335) (C++.assets/image-20230619200059528.png)]

Then after the code is successfully created, change the parent class to QLable.

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-IhD35y3s-1688187869335) (C++.assets/image-20230619200323735.png)]

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-eJZlUNye-1688187869336) (C++.assets/image-20230619200434430.png)]

If we want to know what events there are, we need to go to the parent class and fuzzy search for events. Most of the events are virtual functions for us to rewrite and define our own implementation rules.

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-gstro72k-1688187869336) (C++.assets/image-20230619200555877.png)]

We focus on mouse-related events: rewrite the three virtual functions of mousePressEvent, mouseMoveEvent, and mouseReleaseEvent (shown in italics in qt).

You can add the macro Q_DECL_OVERRIDE or the keyword override after the function declaration to verify whether the current virtual function overrides the parent class. If not, an error will be reported.

In the three rewritten virtual functions, we need to track the status of the left mouse button on the Label component.

statement:

public:
    void mousePressEvent(QMouseEvent *ev) Q_DECL_OVERRIDE;
    void mouseMoveEvent(QMouseEvent *ev) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *ev) Q_DECL_OVERRIDE;

definition:

void MyLabel::mousePressEvent(QMouseEvent *ev){
    
    
    if(ev->button() == Qt::LeftButton){
    
      //如果按下的键是鼠标左键
        this->setText(QString("鼠标左键按下:%1,%2").arg(ev->x()).arg(ev->y()));
    }
}

//button:触发当前事件的按钮
//buttons:触发当前事件时,有哪些按键是按下的
void MyLabel::mouseMoveEvent(QMouseEvent *ev){
    
    
    if(ev->buttons() == Qt::LeftButton|Qt::RightButton){
    
      //鼠标左键和右键同时按下且移动

        this->setText(QString("鼠标左键合右键同时按下且移动"));
    }else if(ev->buttons() == Qt::NoButton){
    
      //鼠标移动,没有按下任何的按键

        this->setText(QString("鼠标移动:%1,%2").arg(ev->x()).arg(ev->y()));
    }
}

void MyLabel::mouseReleaseEvent(QMouseEvent *ev){
    
    
    if(ev->button() == Qt::RightButton){
    
      //鼠标右键抬起

        this->setText(QString("鼠标右键抬起:%1,%2").arg(ev->x()).arg(ev->y()));
    }
}

The custom MyLabel class is bound to the Label component on the main window.

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-GYG0EkYg-1688187869336) (C++.assets/image-20230619202211745.png)]

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-CzA0BYqi-1688187869336) (C++.assets/image-20230619202318093.png)]

Then we tested. After testing, we found that basically everything passed. The only one that did not respond was when the mouse was only moved but not pressed. This was because we did not track it when it was not pressed, so we went to the constructor. Add a function.

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-abnFJqJq-1688187869337)(C++.assets/image-20230619202634123.png)]

that's it

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-a6DyhAf8-1688187869337) (C++.assets/image-20230619202709370.png)]

event distribution

After the event object is created, Qt passes the event to the QObject::event() function. The event() function is mainly used for event distribution. Generally, it does not process events directly, but classifies these events according to their different types. , distributed to different event handlers.

If we want to do some additional operations or block certain events before event distribution, we can also override the event() function. Determine the type of event through event->type().

Example: Add the line edit component to the window. We agree that it is a phone number, and only numbers can be entered and up to 11 digits can be entered.

I don’t dare to say that this requirement cannot be done using signal slots, but it will definitely be very troublesome, so we can do it in event distribution.

We first need to customize the class and inherit the corresponding component class

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-IxJKCOHx-1688187869337) (C++.assets/image-20230629072253496.png)]

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-ajzwByEX-1688187869337) (C++.assets/image-20230629072318382.png)]

Now that the class is built, it’s time to find the functions that need to be rewritten.

We go to the parent class to find the relevant events we need through fuzzy search for events.

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-8lmsTs5L-1688187869337) (C++.assets/image-20230629072513696.png)]

Paste this event into the subclass, and then we also need to find the keyboard release event, but we found that there is no event in the parent class, so we go to the grandpa class to find it.

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-ue1QzbcL-1688187869338) (C++.assets/image-20230629072911850.png)]

We found the keyboard release function, and also found an event distribution function, and put these two functions into subclasses to rewrite

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-FPXjH8Kw-1688187869338) (C++.assets/image-20230629073104332.png)]

Then define these three functions in the source file

Event distribution occurs before the event handler and is used to centrally receive and distribute various types of events.

Implement interception of illegal characters in the event distribution function

//事件分发,集中接收并分发各种类型的事件
bool MyLineEdit::event(QEvent *event){
    
    
    if(event->type() == QEvent::KeyPress){
    
      //判断事件类型,如果是键盘按下的事件
        QKeyEvent * pkey=(QKeyEvent *)event;  //已经做判断了,所以可以强转为具体的事件了
        if(Qt::Key_0 <= pkey->key() && pkey->key() <= Qt::Key_9 || pkey->key() == Qt::Key_Backspace){
    
      //0~9分发,

            return QLineEdit::event(event);  //调用父类的分发
        }else{
    
      //不分发

            qDebug()<<"event 拦截"<<pkey->key();
            //return true;  //代表的是:当前事件已经被处理,不需要分发了
            return false;  //代表:当前事件处理不了,一般会转到父窗口处理
        }
    }
    return QLineEdit::event(event);  //其他类型的事件,仍要继续分发
}

Then promote line edit to MyLineEdit

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-3NycJuNK-1688187869338) (C++.assets/image-20230629075111671.png)]

Then in the keyboard press event, the received number is converted into a string and displayed

At this time, we can only enter numbers when entering the phone number. If we enter letters, they will be blocked (in English mode)

Store phone number in class member attribute

Let’s add another restriction so that the input string can only be less than 11 characters.

But there is another problem. If the phone number we enter is wrong, no matter what we click, it will be intercepted, so we need to release a deletion hole in the interception condition of the event distribution function.

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-2WARmABn-1688187869338) (C++.assets/image-20230629075637783.png)]

Then make a judgment in the keyboard press function. If the backspace key is pressed, delete one digit at the end.

It’s not over yet, our needs have increased. In order to improve privacy, we want to display the middle four digits in the form of *.

Therefore, we need to add three sets of judgments to the judgment. If the size is less than 3, it will be output normally. If it is greater than 3 and less than 7, it will display *. Finally, if it is greater than seven digits, the first three digits will be intercepted normally, and then four * will be spliced. In the splicing The last four digits will be displayed last.

Of course, when the tail deletion was implemented before, the number with * should also be displayed in the final display.

Complete implementation of keyboard press event:

void MyLineEdit::keyPressEvent(QKeyEvent * pkey){
    
    
    if(pkey->key() == Qt::Key_Backspace){
    
      //结尾删除一位
        m_tel= m_tel.left(m_tel.size()-1);  //保留前面,去除最后一位
        //this->setText(m_tel);

        this->setText(this->text().left(this->text().size()-1));
    }
    else if(m_tel.size()<11){
    
    
        m_tel += QString::number(pkey->key()-Qt::Key_0);
        this->setText(m_tel);  //将接收到的数字转换为字符串,并显示
        if(m_tel.size()<=3){
    
    
            this->setText(m_tel);
        }else if(3<m_tel.size() && m_tel.size() <=7){
    
    
            QString tel = m_tel.left(3);
            for(int i=3;i<m_tel.size();i++){
    
    
                tel+="*";
            }
            this->setText(tel);
        }else{
    
    
            QString tel = m_tel.left(3)+"****"+ m_tel.right(m_tel.size()-7);
            this->setText(tel);
        }
    }
}

There is one last thing left. Our phone number at this time is encrypted with *, so we want to use the keyboard release event to display the complete phone number during the keyboard release. We agree that when the Enter key is lifted, A pop-up box pops up to display the complete phone number

void MyLineEdit::keyReleaseEvent(QKeyEvent *event){
    
    
    //Qt::Key_Return 字母区的回车  Qt::Key_Enter 数字小键盘的回车
    if(event->key() == Qt::Key_Return){
    
      //如果是回车抬起
        QMessageBox::information(this,"电话号码",m_tel);
    }
}

Finally, we still remember that when inputting letters, the default was Chinese. If it was a Chinese input method, the letters would not be intercepted, so we want to disable the Chinese input method.

Call a function that disables the Chinese input method at the beginning of the constructor

MyLineEdit::MyLineEdit(QWidget *parent) : QLineEdit(parent)
{
    
    
    this->setAttribute(Qt::WA_InputMethodEnabled,false);  //禁用中文输入法
}

final window display

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-aB285ZDP-1688187869338) (C++.assets/image-20230629081834237.png)]

Guess you like

Origin blog.csdn.net/jia_03/article/details/131489396