Qt之快捷键、事件处理、自定义按键——完成记事本项目

快捷键

我们电脑中的记事本中还支持快捷键,如

"CTRL+O"打开文件、"CTRL+S"保存文件

在Qt中使用QShortcut这个类创建快捷键

在.cpp文件的构造函数中创建QShortcut对象,绑定打开文件和保存文件的槽函数

放大缩小字体

还是在.cpp的构造函数中编写代码

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->verticalLayout);
    ui->widget_2->setLayout(ui->horizontalLayout_2);
    connect(ui->comboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(oncurrentIndex(int)));
    connect(ui->textEdit,SIGNAL(cursorPositionChanged()),this,SLOT(oncursorPosition()));
    
    QShortcut *shortcutOpen=new QShortcut(QKeySequence(tr("Ctrl+O","File|Open")),this);        //添加快捷键
    QShortcut *shortcutSave=new QShortcut(QKeySequence(tr("Ctrl+S","File|Save")),this);
    connect(shortcutOpen,&QShortcut::activated,[=](){on_Bopen_clicked();});                    //绑定信号与槽(指针)
    connect(shortcutSave,&QShortcut::activated,[=](){on_Bsave_clicked();});
    
    QShortcut *shortcutZoomBig=new QShortcut(QKeySequence(tr("Ctrl+Shift+=","File|Save")),this);   //ctrl、shift、+号同时按下(+与=在同一个位置)
    QShortcut *shortcutZoomSmall=new QShortcut(QKeySequence(tr("Ctrl+Shift+-","File|Save")),this); 
    connect(shortcutZoomBig,&QShortcut::activated,[=](){
        QFont font = ui->textEdit->font();            //获取当前字体信息
        int fontSize = font.pointSize();              //获取当前字体大小
        if(fontSize==-1) return;
        int newfontSize=fontSize+1;                   //改变字体大小
        font.setPointSize(newfontSize);               //设置新字体大小
        ui->textEdit->setFont(font);
    });  
    connect(shortcutZoomSmall,&QShortcut::activated,[=](){
        QFont font = ui->textEdit->font();            //获取当前字体信息
        int fontSize = font.pointSize();              //获取当前字体大小
        if(fontSize==-1) return;
        int newfontSize=fontSize-1;                   //改变字体大小
        font.setPointSize(newfontSize);               //设置新字体大小
        ui->textEdit->setFont(font);
    });   
}

事件处理

事件是 Qt 程序与用户(或操作系统)交互的基本单元:用户按下鼠标、键盘输入、窗口被遮挡或暴露、定时器到期......都会产生一个 QEvent 对象。

过去我们常用"信号-槽"机制来处理用户动作,但信号-槽只能覆盖 Qt 已定义好的"高层语义",遇到"关闭窗口时询问是否保存""拖拽窗口时限制范围"这类底层或组合行为,就必须介入真正的事件处理流程。

在 Qt 中,事件处理分为四个连贯的步骤:

  1. 事件派发(dispatch):QApplication::notify() 把事件发给目标对象;

  2. 事件过滤(filter):沿途的所有 QObject::eventFilter() 都有机会截断或修改事件;

  3. 事件分发(delivery):目标对象内部的 QWidget::event() 根据事件类型再细分;

  4. 事件处理(handle):具体虚函数如 mousePressEvent()closeEvent() 最终被执行。

在Qwidget中的保护成员中,还有如下这些事件处理函数,如closeEvent()可以关闭窗口,我们重写事件处理函数也可以在一定程度上处理事件。

事件重写

我们再来添加一个关闭窗口时的弹窗询问

打开.h文件,声明重写closeEvent()事件处理函数(widget继承于Qwidget)

同时按下"ALT+ENTER",在.cpp文件中添加实现

cpp 复制代码
void Widget::closeEvent(QCloseEvent *event)           //记得添加头文件
{
    int ret=QMessageBox::warning(this,tr("My Application"),tr("close the window.\n""Do you want to close the window?"),
                                 QMessageBox::Yes|QMessageBox::No);      //弹窗
    switch (ret) {
        case QMessageBox::Yes:
            event->accept();        //QCloseEvent继承于QEvent,accept接受事件,ignore忽略 
            break;
       case QMessageBox::No:
            event->ignore();
            break;
    }
            
}

自定义按键

按键个性化设置

新建一个项目(同前),然后自定义一个按钮

右键项目,点击"Add New"

点击"C++ Class",点击"choose"

继承于QWidget,点击"下一步",点击"完成"

需要在.h文件中声明的成员如下

再次右键项目名称,点击"Add New",添加一个Qt的资源文件

点击"Add Files",选择3张图片样式添加(在项目文件下添加),"CTRL+S"保存

在.cpp文件中实现重写逻辑

右键复制图片文件地址

cpp 复制代码
#include "mybutton.h"

#include <QPainter>

MyButton::MyButton(QWidget *parent) : QWidget(parent)
{
    pic.load(":/p1.png");   //加载图片(初始图片)
    setFixedSize(pic.size());  //设置按键大小为图片大小
    update();                  //刷新,触发paintEvent()
}

void MyButton::mousePressEvent(QMouseEvent *event)    
{
    pic.load(":/p3.png");
    update();
}

void MyButton::leaveEvent(QEvent *event)
{
    pic.load(":/p1.png");
    update();    
}

void MyButton::enterEvent(QEvent *event)
{
    pic.load(":/p2.png");
    update();    
}

void MyButton::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);                    //绘画师
    painter.drawPixmap(rect(),pic);            //绘制图像(矩形,位图)
    
}

打开.ui文件,托入一个widget控件,右键,点击"提升为"

输入新按钮的类的名称,点击"添加"

点击运行文件,按钮图标能正常转换

这样自定义后按键的形状就能随自己设计,更好看一些(可以用图片等)

自定义按键的信号与槽

在"button.h"文件中声明点击信号

在widget.cpp中引入button的头文件

connect绑定信号与槽

并在button.cpp文件,在鼠标信号点击处,发送点击信号

点击"打开"按钮后,能正常发射信号

事件重写实现滚轮放大缩小字体

标准的QTextEdit控件并不支持"CTAL+鼠标滚轮",所以我们要自定义一个MyTextEdit出来,再将notebook原来的textEdit提升为我们自定义的textEdit类(原代码.c文件不用修改,都是继承于QtextEdit实现)

右键项目名称,新建一个类文件

标注父控件

在我们的MyTextEdit构造时还需标注父控件,使MyTextEdit与ui中的TextEdit联系起来(ui中所有控件都有QWidget这个父亲)

"ALT+ENTER"添加构造函数的实现(把原来的删掉)

cpp 复制代码
MyTextEdit::MyTextEdit(QWidget *parent):QTextEdit(parent)    //调用QtextEdit的构造函数实现
{
    
}

再在.h文件中声明要实现的功能

cpp 复制代码
#ifndef MYTEXTEDIT_H
#define MYTEXTEDIT_H

#include <QTextEdit>



class MyTextEdit : public QTextEdit
{
public:
    MyTextEdit(QWidget *parent);
    
protected:
    void wheelEvent(QWheelEvent *e) override;              //鼠标滚轮事件
    void keyPressEvent(QKeyEvent *e) override;             //按键按下事件
    void keyReleaseEvent(QKeyEvent *e) override;           //按键松开事件
};

#endif // MYTEXTEDIT_H

提升TextEdit

在ui中右键TextEdit,"提升为"

然后右边可以看到已经提升过来了

代码实现

放大和缩小字体的代码与之前快捷键实现重复了,所以直接把之前那段代码用函数封装调用就好了

widget.h添加声明

widget.cpp添加实现

使用事件函数基本的使用,我们已经能写出大致框架,但我们要实现的应该是"CTRL+滚轮"实现,但滚轮能够上下滑动

我们只要添加一个bool型的变量,使同时操作时再调用函数就可以了

以及除了同时按下,正常操作的反应要继承下来

cpp 复制代码
#include "mytextedit.h"

#include <QCloseEvent>

MyTextEdit::MyTextEdit(QWidget *parent):QTextEdit(parent)    //调用QtextEdit的构造函数实现
{

}

void MyTextEdit::wheelEvent(QWheelEvent *e)
{
    if(ctrlKeyPressed==1){
        if(e->angleDelta().y()>0){                           //上滑缩小
            zoomIn();
        }else if(e->angleDelta().y()<0){
            zoomOut();
        }
        e->accept();                                         //处理完毕
    }else{
        QTextEdit::wheelEvent(e);                             //正常执行QTextEdit的滚轮事件
    }
}

void MyTextEdit::keyPressEvent(QKeyEvent *e)
{
    if(e->key()==Qt::Key_Control){                          //Ctrl按下
        ctrlKeyPressed=1;
    }
    QTextEdit::keyPressEvent(e);                            //按键按下执行
}

void MyTextEdit::keyReleaseEvent(QKeyEvent *e)
{
    if(e->key()==Qt::Key_Control){                          //Ctrl释放
        ctrlKeyPressed=0;
    }
    QTextEdit::keyReleaseEvent(e);
}

事件过滤器

对于Qt事件,我们主要把中重点放在事件处理和事件过滤

事件过滤器适用于:当你不想在修改子代码的情况下改变事件的行为(如上面的情况不添加新的类)。可在事件到达目标对象之前进行拦截和处理

先在.h文件添加声明

安装事件过滤器

在事件过滤器中,我们既要检测滚轮,又要检测"Ctrl"是否被按下。若单使用QEvent事件,检测滚轮会调用一次,检测ctrl按下又会调用一次。则两个事件不能同时被检测,所以我们换种方式检测滚轮。

cpp 复制代码
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if(event->type()==QEvent::Wheel){             //事件是滚轮事件
        if(QGuiApplication::keyboardModifiers()==Qt::ControlModifier){    //ctrl被按下
            QWheelEvent *weelEvent=dynamic_cast<QWheelEvent*>(event);                   //转换类型
            if(weelEvent->angleDelta().y()>0){
                zoomIn();
            }else{
                zoomOut();
            }
            return true;                           //事件已执行
        }
        return false;                              //若ctrl没被按下,事件继续传递给目标对象
    }
}

至此,我们的记事本项目简单完成!

下图为up主老陈的总结

相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner12 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner13 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00615 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术15 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript