Qt项目——记事本

发布于:2025-04-10 ⋅ 阅读:(35) ⋅ 点赞:(0)

前言

这个项目就是搞一个类似于电脑自带的记事本小项目,需要了解信号与槽的原理,了解QFile,QTextStream、QFileDialog、QComboBox等空件。

在这里插入图片描述

工程文档

链接:https://pan.baidu.com/s/1PYZr2PnPyL3294IL_ZyjfQ
提取码:th5h

一、功能介绍

1.支持文本创建,打开,保存,关闭的功能
2.UI样式美化
3.添加打开快捷键,添加保存快捷
4.底部显示行列号及文本字符编码
5.Ctrl加鼠标滚轮支持字体放大缩小

二、界面预览

在这里插入图片描述

三、UI设计师工具

创建好widget工程文件后就可以到这个界面去拖动左边的这些控件到中间这些UI界面,左上角三个小图标分别为打开,保存和删除文件里面文字的pushbutton的按钮,还有弹簧用于将这三个按钮压缩到黑色背景的最左端,中间白色区域就是TextEdit(文本编辑),右下角显示几行几列用的是Label和可以切换编码方式的comboBox,这个板块的布局和上面同理,从上到下这个三个大的板块采用的是垂直布局,其中上下模块里的控件都是水平布局。右下角可以调整模块的间距和长度和宽度。
在这里插入图片描述

四、给三个按钮设置贴图

在这里插入图片描述

1.先创建一个新的Qt Resource File。
在这里插入图片描述

2.将所需要的贴图放入这整个项目的文件夹里,点击新创建的资源文件再点击添加文件,就可以把所有贴图添加进去。

在这里插入图片描述

3.右键三个按钮点击改变样式
在这里插入图片描述
第一行表示按钮正常的图片
第二行表示按钮鼠标悬浮的图片
第三行点击图片
同理可以调整其中文字的颜色和背景颜色

五、信号与槽

在 Qt 中,信号和槽机制是一种非常强大的事件通信机制。这是一个重要的概念,特别是对于初学者来说,理解它对于编写 Qt 程序至关重要。

概要

  1. 信号 (Signals):是由对象在特定事件发生时发出的消息。例如, QPushButton 有一个
    clicked() 信号,当用户点击按钮时发出。
  2. 槽 (Slots):是用来响应信号的方法。一个槽可以是任何函数,当其关联的信号被发出时,该槽函数
    将被调用。
  3. 连接信号和槽:使用 QObject::connect() 方法将信号连接到槽。当信号发出时,关联的槽函数
    会自动执行。

自定义信号与槽

  1. 定义信号:在Qt中,信号是由 signals 关键字声明的类成员函数。它们不需要实现,只需声明。例
    如:
class MyClass : public QObject {
Q_OBJECT
public:
MyClass();
signals:
void mySignal(int value);
};

在上面的例子中, MyClass 有一个名为 mySignal 的信号,它带有一个整型参数。

2.定义槽:槽可以是任何普通的成员函数,但通常在类定义中用 slots 关键字标识。槽可以有返回类型,
也可以接受参数,但它们的参数类型需要与发出信号的参数类型匹配。例如:

class MyClass : public QObject {
Q_OBJECT
public slots:
void mySlot(int value);
};

在这个例子中,我们定义了一个名为 mySlot 的槽,它接收一个整型参数。

3.连接信号与槽:使用 QObject::connect 函数将信号与槽连接起来。当信号被发射时,连接到这个信号的槽将被调用。

MyClass *myObject = new MyClass();
connect(myObject, SIGNAL(mySignal(int)), myObject, SLOT(mySlot(int)));

这行代码连接了 myObject 的 mySignal 信号到同一个对象的 mySlot 槽。

4.发射信号:使用 emit 关键字发射信号。当信号被发射时,所有连接到这个信号的槽都会被调用。

emit mySignal(123);

这将触发所有连接到 mySignal 的槽。
自定义信号和槽是Qt编程中非常强大的特性,它们使得组件之间的通信变得灵活而松耦合。通过信和槽,可以方便地实现各种复杂的事件驱动逻//辑。

六、实现文件打开功能

为QPushButton对应Open的控件设置槽函数
槽函数代码开发:
1.打开文件
2.读取文件
3.把文件数据显示在TextEdit控件上

代码实现

void Widget::on_btnOpen_clicked()
{
    QString filename =  QFileDialog::getOpenFileName(this,tr("Open File"),
    "D:/qt_project/bigProject/", tr("Text (*.txt)"));


    ui->textEdit->clear();//清空所有文字

    file.setFileName(filename);
    if(!file.open(QIODevice::ReadWrite | QIODevice::Text)){
        qDebug() << "file open error";
    }

    this->setWindowTitle(filename + "- 曙哥记事本");

    QTextStream in(&file);
    //in.setEncoding(QStringConverter::Utf8);
    QString encodingStr = ui->comboBox->currentText();
    if (encodingStr == "UTF-8") {
        in.setEncoding(QStringConverter::Utf8);
    } else if (encodingStr == "UTF-16") {
        in.setEncoding(QStringConverter::Utf16);
    } else {
        in.setEncoding(QStringConverter::System); // 默认系统编码
    }

    // QStringConverter::Encoding encoding = ui->comboBox->currentData().value<QStringConverter::Encoding>();
    // in.setEncoding(encoding);

    // QString context = in.read(file.size());
    while(!in.atEnd()){
        QString context = in.readLine();
        //ui->textEdit->setText(context);
        ui->textEdit->append(context);//    把每一行追加到记事本里
    }

}

在文本中有文字的情况下打开其他文件需将文本中的文字清空再将光标放回初始位置。

代码实现

void Widget::onCurrentIndexChanged(int )
{
    ui->textEdit->clear();
    if(file.isOpen()){
        QTextStream in(&file);
        QString encodingStr = ui->comboBox->currentText();
        if (encodingStr == "UTF-8") {
            in.setEncoding(QStringConverter::Utf8);
        } else if (encodingStr == "UTF-16") {
            in.setEncoding(QStringConverter::Utf16);
        } else {
            in.setEncoding(QStringConverter::System); // 默认系统编码
        }
        file.seek(0);//光标回到最出位置
        while(!in.atEnd()){
            QString context = in.readLine();
            ui->textEdit->append(context);
        }
    }
}

七、实现文件保存

判断当下是否有已经打开的文件,如果有打开的文件
读取TextEdit的内容
写入新文件

代码内容

void Widget::on_btnSave_clicked()
{
    if(!file.isOpen()){
        QString filename =  QFileDialog::getSaveFileName(this,tr("Save File"),
        "D:/qt_project/bigProject/untitled.txt", tr("Text (*.doc *.txt)"));

        this->setWindowTitle(filename + "- 曙哥记事本");

        file.setFileName(filename);
        if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){ //文件打开模式为只读和文本模式
            qDebug() << "file open error";
        }
    }


    QTextStream out(&file);
    QString encodingStr = ui->comboBox->currentText();
    if (encodingStr == "UTF-8") {
        out.setEncoding(QStringConverter::Utf8);
    } else if (encodingStr == "UTF-16") {
        out.setEncoding(QStringConverter::Utf16);
    } else {
        out.setEncoding(QStringConverter::System); // 默认系统编码
    }
    QString context = ui->textEdit->toPlainText();
    out << context;
}

八、实现文件关闭

QMessageBox 是 Qt 框架中用于显示消息框的一个类,它常用于向用户显示信息、询问问题或者报告错误。以下是 QMessageBox 的一些主要用途:

  1. 显示信息:向用户显示一些信息性的消息。
  2. 询问用户决策:询问用户一个问题,并根据其回答做出相应的操作。
  3. 报告错误:向用户报告程序运行中的错误。

代码实现

void Widget::on_btnClose_clicked()
{

    QMessageBox msgBox;

    int ret = QMessageBox::warning(this, tr("曙哥记事本"),
                                   tr("文档已修改.\n"
                                      "要保存更改吗?"),
                                   QMessageBox::Save | QMessageBox::Discard
                                       | QMessageBox::Cancel,
                                   QMessageBox::Save);

    switch (ret) {
    case QMessageBox::Save:
        // Save was clicked
        on_btnSave_clicked();
        break;
    case QMessageBox::Discard:
        // Don't Save was clicked
        ui->textEdit->clear();
        if(file.isOpen()){
            file.close();
            this->setWindowTitle("曙哥记事本");
        }

        qDebug() << "Discard";
        break;
    case QMessageBox::Cancel:
        // Cancel was clicked
        qDebug() << "Cancel";
        break;
    default:
        // should never be reached
        break;
    }

}

九、显示高亮和行列位置

实现策略:
获取当前行的光标位置,使用的信号和获取行列值是一样的
通过ExtraSelection来配置相关属性
在当前行设置该属性
实现该功能,需要用到一个API

QList<QTextEdit::ExtraSelection> extraSelections;
void setExtraSelections(const QList<QTextEdit::ExtraSelection> &extraSelections)

代码实现

void Widget::onCursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();
    //qDebug() << cursor.blockNumber() + 1 << "," << cursor.columnNumber() + 1;
    QString blockNum = QString::number(cursor.blockNumber() + 1);
    QString columNum = QString::number(cursor.columnNumber() + 1);
    const QString labelMes = "行:" + blockNum + ",列:" + columNum + "  ";
    ui->label->setText(labelMes);

    //设置当前行高亮
    QList<QTextEdit::ExtraSelection> extraSelection;
    QTextEdit::ExtraSelection ext;

    //1.知道当前行
    ext.cursor = cursor;
    QBrush qBrush(Qt::lightGray);
    //2.颜色
    ext.format.setBackground(qBrush);
    //整行显示
    ext.format.setProperty(QTextFormat::FullWidthSelection, true);
    //3.设置
    extraSelection.append(ext);
    ui->textEdit->setExtraSelections(extraSelection);

}

十、实现快捷功能

在 Qt 中实现快捷键功能通常涉及到 QShortcut 类的使用。下面是一个简单的代码示例,展示了如何在
Qt 应用程序中为特定功能设置快捷键:

// 创建一个快捷键 (Ctrl + N) 并关联到窗口
QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+N"), &window);
// 当快捷键被按下时,显示一个消息框
QObject::connect(shortcut, &QShortcut::activated, [&]() {
QMessageBox::information(&window, "Shortcut Activated", "Ctrl+N was
pressed");
});

在这个示例中,当用户按下 Ctrl + N 时,程序将弹出一个消息框。这是通过创建一个 QShortcut 对象,
并将其快捷键序列设置为 “Ctrl+N” 来实现的。然后,将 activated 信号连接到一个 Lambda 函数,
该函数在快捷键被激活时执行。这种方法非常适用于为特定操作提供快速访问路径

代码实现

 QShortcut *shortcutOpen = new QShortcut(QKeySequence(tr("Ctrl+O", "File|Open")), this);
    QShortcut *shortcutSave = new QShortcut(QKeySequence(tr("Ctrl+S", "File|Save")), this);

    QShortcut *shortcutZoomIn = new QShortcut(QKeySequence(tr("Ctrl+Shift+=", "File|Save")), this);
    QShortcut *shortcutZoomOut = new QShortcut(QKeySequence(tr("Ctrl+Shift+-", "File|Save")), this);

    connect(shortcutOpen, &QShortcut::activated, [=]{
        on_btnOpen_clicked();
    });

    connect(shortcutSave, &QShortcut::activated, [=]{
        on_btnSave_clicked();
    });

    connect(shortcutZoomIn, &QShortcut::activated, [=]{
        zoomIn();
    });

    connect(shortcutZoomOut, &QShortcut::activated, [=]{
        zoomOut();
    });

void Widget::zoomIn()
{
    QFont font = ui->textEdit->font();

    //获得当前字体的大小
    int fontsize = font.pointSize();
    if(fontsize == -1) return;
    int newFontSize = fontsize + 1;
    font.setPointSize(newFontSize);
    ui->textEdit->setFont(font);
}

void Widget::zoomOut()
{
    //获得当前字体的信息
    QFont font = ui->textEdit->font();

    //获得当前字体的大小
    int fontsize = font.pointSize();
    if(fontsize == -1) return;
    int newFontSize = fontsize - 1;
    font.setPointSize(newFontSize);
    ui->textEdit->setFont(font);
}
    

总结

一定要清楚每个控件的使用方式,控件太多我们不需要死记硬背,不懂的就查官方帮助文档,UI部分要提升熟练度,要回使用信号和槽的机制。

在这里插入图片描述

希望大家可以一键三连,后续我们一起学习,谢谢大家!!!

在这里插入图片描述