Qt-目录和文件

1. 目录和文件

1.1 目录操作

  • QDir 类用来处理目录

  • 常用方法:

    • QDir(QString path) : 实例化

    • absolutePath() : 获取目录绝对路径

    • dirName() : 获取目录相对路径

    • exists(dirPath) : 判断目录是否存在

    • mkdir(QString dirPath) : 创建目录

    • rmdir(QString dirPath) : 删除目录

示例:

cpp 复制代码
// 实例化对象,并将当前目录的相对路径传入
QDir dir("./");

// 打印 绝对路径 和 项目路径
qDebug() << dir.absolutePath() << dir.dirName();

// 在当前目录下创建 abc 目录
if (dir.exists("./abc") == false)
{
  bool ret = dir.mkdir("abc");
  qDebug() << (ret == true ? "创建成功" : "创建失败");
}
else
{
  qDebug() << "目录已存在";
}

// 删除当前目录下的 abc 目录
dir.rmdir("abc");

其他方法:

  • entryInfoList({文件类型}) : 获取指定目录下所有的目录和文件,返回值 QFileInfoList

    • QList<QFileInfo> <===> QFileInfoList

    • entryInfoList({"*.jpg", "*.png"})

  • setFilter() : 过滤获取的文件和目录类型

    • QDir::Dirs : 保留目录

    • QDir::Files :保留文件

    • QDir::NoSymLinks : 不要快捷方式

    • QDir::NoDotAndDotDot : 不要 . 和 ..

1.2 文件信息

QFileInfo 类用来获取文件信息

cpp 复制代码
QFileInfo info("./Makefile.Debug");

qDebug() << "文件绝对路径: " << info.absoluteFilePath();
qDebug() << "文件全名:" << info.fileName();
qDebug() << "文件名:" << info.baseName();
qDebug() << "文件后缀:" << info.suffix();
qDebug() << "文件大小:" << info.size();
qDebug() << "创建时间:" << info.birthTime().toString("yyyy-MM-dd hh:mm:ss");
qDebug() << "是否为目录:" << info.isDir();
qDebug() << "是否为文件:" << info.isFile();

// 获取文件所在目录的路径
QDir filePath = info.dir();
qDebug() << filePath;

案例: 获取路径下所有的文件和目录,并将文件和目录的信息输出在控制台

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"

#include <QDir>
#include <QDebug>
#include <QFileInfoList>
#include <QFileInfo>
#include <QDateTime>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->getDirInfo(".");
   
   // qDebug() << this->getDirSize(".");

}

int Widget::getDirSize(QString path)

{
     int totalSize = 0;
    QDir dir(path);
    dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
    QFileInfoList l = dir.entryInfoList();
    for(QFileInfo item : l)
    {
        if (item.isFile())
        {
            //如果是文件 ,直接累加
            totalSize += item.size();
        }
        else if (item.isDir()) {
           totalSize += this->getDirSize((item.absoluteFilePath()));

        }
    }
    return totalSize;
}

void Widget::getDirInfo(QString path)
{
   QDir dir(path);
   dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
   QFileInfoList list = dir.entryInfoList();
    for (QFileInfo item : list)
    {
        if(item.isDir())
        {
            qDebug() << "dir" << item.fileName() << this->getDirSize(item.absoluteFilePath()) << item.birthTime().toString("yyyy-MM-dd");
        }
        else {
             qDebug() << "file" << item.fileName() << item.size() << item.birthTime().toString("yyyy-MM-dd");
        }
    }
}

1.3 写文件

  • QFile 类用来对文件进行读写

  • 常用方法:

    • open(打开方式) : 打开文件

      • QIODevice::WriteOnly 已只写方式打开,新内容会覆盖原来的内容

      • QIODevice::ReadWrite 已读写方式打开, 打开时光标在文件头部,内容从文件头开始追加

      • QIODevice::Append 已追加方式打开,打开时光标在文件尾部,内容从尾部开始追加

    • write(QByteArray) : 向文件中写入内容 , 返回值得到写入的字符串长度

向文件中写入内容 (覆盖写入)

cpp 复制代码
QFile file("e:/a.txt");
if (file.open(QIODevice::WriteOnly))
{
  QByteArray str = "Hello World!! 你好啊!!";
  qint64 len = file.write(str);
  qDebug() << "写入内容的长度" << len;
}
else
{
  qDebug() << "写文件失败";
}

向文件头部追加内容 (头部写入)

cpp 复制代码
if (file.open(QIODevice::ReadWrite))
{
  QByteArray str = "头部~~~";
  qint64 len = file.write(str);
  qDebug() << "写入内容的长度" << len;
}
else
{
  qDebug() << "追加到文件头部失败";
}

向文件尾部追加内容 (追加写入)

cpp 复制代码
if (file.open(QIODevice::Append))
{
  QString str = "~~~~尾部追加";
 	qint64 len = file.write(str.toUtf8().data());
  qDebug() << "写入内容的长度" << len;
}
else
{
  qDebug() << "追加到文件尾部失败";
}

1.4 读文件

QIODevice::ReadOnly : 已只读方式打开

  • readAll() : 一次性去读文件的所有内容

  • readLine() : 一次读取一行内容

示例1: 一次性读取文件中所有的内容:

  • readAll() : 一次性读取文件中所有的内容
cpp 复制代码
QFile file("e:/a.txt");

if (file.open(QIODevice::ReadOnly))
{
  // 一次性读取文件所有内容
  QByteArray b = file.readAll();
  qDebug() << QString(b);
}
else
{
  qDebug() << "读文件失败";
}

示例2: 按行读取文件中的内容

核心方法:

  • atEnd() : 判断是否已将到文件结尾

  • readLine(*char, length) : 一次性读取 length 指定长度的内容,并保存到 char 中

cpp 复制代码
QFile file("e:/aaa.txt");
file.open(QIODevice::ReadOnly);

while (!file.atEnd()) {
  char buf[1024];
  qint64 len = file.readLine(buf, sizeof(buf));
  qDebug() << len << buf;
}

2. 综合案例

2.1 利用ui来创建界面

  1. 菜单栏

  2. 工具栏

只能显示在上方,不能移动不能悬浮

可以修改图标大小

3.中心部件

状态栏: 只能使用代码来创建

cpp 复制代码
// 窗口基本设置
ui->setupUi(this);
this->setFixedSize(750, 500);
this->setWindowTitle("记事本");

// 设置状态栏
QLabel *statusLb = new QLabel;
QString str = QString("文本长度: %1").arg(10);
statusLb->setText(str);
ui->statusBar->addWidget(statusLb);

2.2 文件菜单

2.2.1 退出

在 "退出" 按钮上设置信号 (triggered),触发 close 槽函数即可。

cpp 复制代码
// 快捷键设置
ui->actionExit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
// 链接信号和槽,实现关闭功能
connect(ui->actionExit, &QAction::triggered, this, &MainWindow::close);

2.2.2 另存为

实现思路:

  1. 判断多行文本框中是否有内容

没有则不进行操作

  1. 如果有,则弹出文件保存框

  2. 点击文件保存框的 "保存" 按钮时,获取文件路径,获取多行文本框中的内容,将内容写入文件

cpp 复制代码
 // 另存为
ui->actionSaveAs->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_S));
connect(ui->actionSaveAs, &QAction::triggered, [=](){
  // 1) 获取文本框中的内容
  QString tmp = ui->textEdit->toPlainText();

  // 2) 判断内容是否为空
  if (!tmp.isEmpty())
  {
    // 3) 当不为空时打开文件保存框
    filePath = QFileDialog::getSaveFileName(this, "保存文件", "./", "*.txt");

    // 4) 当文件路径不为空时进行文件写入操作
    if (!filePath.isEmpty())
    {
      // 实例化 QFile 并以只写方式打开文件
      QFile file(filePath);
      bool res = file.open(QIODevice::WriteOnly);
      // 当打开正确时,进行文件写入操作
      if (res == true)
      {
        file.write(tmp.toUtf8());
      }
      else
      {
        QMessageBox::critical(this, "严重错误", "保存的文件路径出错");
      }
    }
  }

});

2.2.3 保存

实现思路:

  1. 判断多行文本框中是否有内容; 如果没有则不做任何操作

  2. 如果有,判断是否有文件路径;

① 如果没有,则弹出文件保存框,获取文件路径,进行写入操作

② 如果有,覆盖写入

注意事项:

在头文件中加入了 filePath 属性,获取的文件保存路径都要放在 filePath 属性中(包括另存为时使用filePath)

cpp 复制代码
ui->actionSave->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
connect(ui->actionSave, &QAction::triggered, [=](){
  QString tmp = ui->textEdit->toPlainText();
  if (!tmp.isEmpty())
  {
    // 判断保存文件的文件路径是否为空
    if (filePath.isEmpty())
    {
      // 为空时,说明内容还没有保存,需要弹出保存框
      // 不为空时,说明内容曾经保存过,不需要弹出保存框,直接写文件即可
      filePath = QFileDialog::getSaveFileName(this, "保存文件", "./", "*.txt");
    }

    QFile file(filePath);
    file.open(QIODevice::WriteOnly);
    file.write(tmp.toUtf8());
  }
});

2.2.4 打开

核心功能:

  1. 点击 "打开" 按钮时,弹出文件打开框,选中文件,得到文件路径

  2. 根据文件路径,读取文件中的内容,再显示到 textEdit 上

扩展功能:

  1. 判断 textEdit 中是否有内容,如果没有则直接执行打开

  2. 如果有,则弹出询问框。 如果点击 取消,则执行开大

  3. 如果选择 保存, 执行保存的流程

cpp 复制代码
ui->actionOpen->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
connect(ui->actionOpen, &QAction::triggered, [=](){
  // 获取文本框中的内容
  QString tmp = ui->textEdit->toPlainText();

  if (!tmp.isEmpty())
  {
    // 不为空时,要提示是否保存
    int res = QMessageBox::question(this, "询问", "内容尚未保存,您需要进行保存吗?", QMessageBox::Save | QMessageBox::Cancel);
    if (QMessageBox::Save == res)
    {
      if (!tmp.isEmpty())
      {
        // 判断保存文件的文件路径是否为空
        if (filePath.isEmpty())
        {
          // 为空时,说明内容还没有保存,需要弹出保存框
          // 不为空时,说明内容曾经保存过,不需要弹出保存框,直接写文件即可
          filePath = QFileDialog::getSaveFileName(this, "保存文件", "C:/Users/Administrator/Documents", "*.txt");
        }

        QFile file(filePath);
        file.open(QIODevice::WriteOnly);
        file.write(tmp.toUtf8());
      }
    }
  }

  // 打开文件选择框,获取文件路径
  filePath = QFileDialog::getOpenFileName(this, "打开文件", "./", "*.txt");

  if (!filePath.isEmpty())
  {
    // 如果文件路径不为空,则读取文件的内容,显示到 textEdit 中
    QFile file(filePath);
    file.open(QIODevice::ReadOnly);
    QByteArray b = file.readAll();
    ui->textEdit->setText(b);
  }
});

2.2.5 新建

实现思路:

  1. 判断文本区域是否有内容

  2. 如果没有,则将 filePath 置空,同时将文本区域也置空

  3. 如果有,则弹出询问框,询问是否需要保存。

① 选择取消时,则将 filePath 置空,同时将 文本区域也置空

② 选择保存时,弹出文件保存框。得到文件路径并将其保存在 filePath 中,再获取文本区域的内容,进行写文件操作。

cpp 复制代码
connect(ui->actionNew, &QAction::triggered, [=](){
  // 获取当前文本区域的内容
  QString tmp = ui->textEdit->toPlainText();
	// 判断文本区域的内容是否为空
  if (!tmp.isEmpty())
  {
    // 不为空的时候弹出询问框进行询问提示, 利用 QMessageBox 的构造函数实现中文按钮的设置
    // 参数1: 设置弹出框的类型 和 图标设置
    // 参数2: 弹出框标题栏的文本
    // 参数3: 弹出框正文区域的文本
    // 参数4: 设置使用哪些按钮
    QMessageBox myBox(
      QMessageBox::Question, 
      "是否保存", 
      "您需要保存当前内容吗?", 
      QMessageBox::Save | QMessageBox::Cancel
    );
    // 利用两种方式修改按钮中的文字
    myBox.setButtonText(QMessageBox::Save, "保存");
    myBox.button(QMessageBox::Cancel)->setText("取消");

    // 调用 exec 方法弹出询问框
    // 返回值: int类型,但是本质是选中的按钮的枚举值
    int result = myBox.exec();
    // 判断是否点击的是保存按钮
    if (result == QMessageBox::Save)
    {
      // 判断保存文件的文件路径是否为空
      if (filePath.isEmpty())
      {
        // 为空时,说明内容还没有保存,需要弹出保存框
        // 不为空时,说明内容曾经保存过,不需要弹出保存框,直接写文件即可
        filePath = QFileDialog::getSaveFileName(this, "保存文件", "./", "*.txt");
      }

      QFile file(filePath);
      // 打开文件的方式  WriteOnly | ReadWrite | Append  |  ReadOnly
      file.open(QIODevice::WriteOnly);
      file.write(tmp.toUtf8());
    }
  }

  // 清空操作
  filePath = "";
  ui->textEdit->setText("");
});

2.3 编辑菜单

利用 QTextEdit 的槽函数即可

cpp 复制代码
// 复制
connect(ui->actionCopy, &QAction::triggered, ui->textEdit, &QTextEdit::copy);
// 粘贴
connect(ui->actionPaste, &QAction::triggered, ui->textEdit, &QTextEdit::paste);
// 剪切
connect(ui->actionCut, &QAction::triggered, ui->textEdit, &QTextEdit::cut);
// 撤销
connect(ui->actionUndo, &QAction::triggered, ui->textEdit, &QTextEdit::undo);

2.4 格式菜单

2.4.1 自动换行

实现思路:

  1. 设置一个标记来标志当前是否为 换行状态 (true 换行 | false 不换行)

  2. 显示图标、自动换行

  3. 在 "自动换行" 菜单上注册信号,判断状态,如果为true则显示图标,自动换行;反之,不显示图标,不换行

核心方法:

  • QTextEdit::setLineWrapMode(QTextEdit::WidgetWidth | QTextEdit::NoWrap)

    • QTextEdit::WidgetWidth 自动换行

    • QTextEdit::NoWrap 不自动换行

实现:

1.在头文件中定义状态

cpp 复制代码
class MainWindow : public QMainWindow
{
    ...
private:
    Ui::MainWindow *ui;

    QString filePath;
    // 自动换行的标记,true 是自动换行 | false 是不自动换行
    bool warpFlag = true;
};

2.在源文件中实现

cpp 复制代码
// 程序首次运行时进行初始化状态
ui->actionWrap_2->setIcon(QIcon(":/icon/r.png"));
// QTextOption::NoWrap (不自动换行) | QTextOption::WordWrap  (自动换行)
ui->textEdit->setLineWrapMode(QTextEdit::WidgetWidth);

// 点击 "自动换行" 时触发信号
connect(ui->actionWrap_2, &QAction::triggered, [&](){
  // 对状态取反
  warpFlag = !warpFlag;
  // 判断自动换行的状态
  if (warpFlag == false)
  {
    // 如果为false时不换行,则设置图标为空,自动换行的状态为 NoWrap
    ui->actionWrap_2->setIcon(QIcon(""));
    ui->textEdit->setLineWrapMode(QTextEdit::NoWrap);
  }
  else
  {
    // 如果为true时自动换行,设置图标,自动换行状态为 WordWrap
    ui->actionWrap_2->setIcon(QIcon(":/icon/r.png"));
    ui->textEdit->setLineWrapMode(QTextEdit::WidgetWidth);
  }
});

2.4.2 字体

实现思路:

  1. 点击 "字体" 时,弹出字体选择框(QFontDialog)

  2. 当用户点击 "确定" 按钮时,获取选中的字体数据

  3. 将字体数据设置到 textEdit 中

cpp 复制代码
connect(ui->actionFont, &QAction::triggered, [=](){
  bool flag = true;
  // 打开字体选择框,返回值能够保存用户选择的字体数据
  QFont font = QFontDialog::getFont(&flag);
  // 将字体数据设置到 textEdit 中
  ui->textEdit->setFont(font);
});

2.5 状态栏

目标: 显示文本长度

实现步骤:

  1. 使用 QTextEdit 的 textChanged 信号,该信号是一旦文本框中的内容发送变化就会触发

  2. 获取 QTextEdit 中内容,使用 size 方法来获取内容的长度,最后再将长度显示到 状态栏的QLabel中

cpp 复制代码
// 在头文件中声明了状态栏中的QLabel
class MainWindow : public QMainWindow
{
    ....

private slots:
  // textChanged 匹配的槽函数
  void on_textEdit_textChanged();

private:
  Ui::MainWindow *ui;

  QString filePath;
  bool warpFlag = true;
  
	// 状态栏中使用 QLabel
  QLabel *statusLb;
};
cpp 复制代码
void MainWindow::on_textEdit_textChanged()
{
  // 获取文本长度
  int len = ui->textEdit->toPlainText().size();
  QString str = QString("文本长度: %1").arg(len);
  statusLb->setText(str);
}

2.6 查看菜单

2.6.1 状态栏

逻辑同 自动换行

cpp 复制代码
// 是否显示状态栏
connect(ui->actionStatus, &QAction::triggered, [=](){
  isStatusLbShow = !isStatusLbShow;

  if (isStatusLbShow == true)
  {
    statusLb->show();
  }
  else
  {
    statusLb->hide();
  }
});

2.6.2 放大&缩小

实现步骤:

  1. 在头文件中对字体数据进行单独声明 (family、pointSize、italic、bold)

优势: 1. 可以在程序首次运行时对 textEdit 中的字体进行设置 2. 方便单独对字体进行放大和缩小的操作

  1. 在源文件中,初始化 textEdit 中的字体数据

  2. 点击 "放大" 和 "缩小" 时,单独设置 pointSize 的值

cpp 复制代码
class MainWindow : public QMainWindow
{
	......

private:
   ....

    // 设置字体数据
    QString family = "微软雅黑";
    int pointSize = 16;
    bool italic = true;
    bool bold = true;
};
cpp 复制代码
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    .....
    
    // 设置字体
    ui->textEdit->setFont(QFont(family, pointSize, italic, bold));
      
    ....
}
cpp 复制代码
// 放大
connect(ui->actionZoomUp, &QAction::triggered, [=](){
  pointSize += 2;
  ui->textEdit->setFont(QFont(family, pointSize, italic, bold));
});

// 缩小
connect(ui->actionZoomDown, &QAction::triggered, [=](){
  pointSize -= 2;
  ui->textEdit->setFont(QFont(family, pointSize, italic, bold));
});

bug 修补: 在 "格式" 菜单中调整字体之后,需要将最新的字体数据保存在属性中,否则放大和缩小会出错

cpp 复制代码
// 字体
connect(ui->actionFont_2, &QAction::triggered, [=](){
  bool flag = true;
  QFont font = QFontDialog::getFont(&flag);
  ui->textEdit->setFont(font);

  // 将最新的字体数据保存
  family = font.family();
  pointSize = font.pointSize();
  italic = font.italic();
  bold = font.bold();

});

2.7 帮助菜单

打开浏览器

cpp 复制代码
connect(ui->actionHelpDoc, &QAction::triggered, [](){
	QDesktopServices::openUrl(QUrl("https://www.baidu.com"));
});
相关推荐
engchina11 分钟前
如何在 Python 中忽略烦人的警告?
开发语言·人工智能·python
向宇it12 分钟前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
诚丞成37 分钟前
计算世界之安生:C++继承的文水和智慧(上)
开发语言·c++
Smile灬凉城6661 小时前
反序列化为啥可以利用加号绕过php正则匹配
开发语言·php
lsx2024061 小时前
SQL MID()
开发语言
Dream_Snowar1 小时前
速通Python 第四节——函数
开发语言·python·算法
西猫雷婶1 小时前
python学opencv|读取图像(十四)BGR图像和HSV图像通道拆分
开发语言·python·opencv
鸿蒙自习室1 小时前
鸿蒙UI开发——组件滤镜效果
开发语言·前端·javascript
言、雲1 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
东风吹柳2 小时前
观察者模式(sigslot in C++)
c++·观察者模式·信号槽·sigslot