1. 目录和文件
1.1 目录操作
-
QDir 类用来处理目录
-
常用方法:
-
QDir(QString path) : 实例化
-
absolutePath() : 获取目录绝对路径
-
dirName() : 获取目录相对路径
-
exists(dirPath) : 判断目录是否存在
-
mkdir(QString dirPath) : 创建目录
-
rmdir(QString dirPath) : 删除目录
-
示例:
// 实例化对象,并将当前目录的相对路径传入
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 类用来获取文件信息
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;
案例: 获取路径下所有的文件和目录,并将文件和目录的信息输出在控制台
#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) : 向文件中写入内容 , 返回值得到写入的字符串长度
-
向文件中写入内容 (覆盖写入)
QFile file("e:/a.txt");
if (file.open(QIODevice::WriteOnly))
{QByteArray str = "Hello World!! 你好啊!!";qint64 len = file.write(str);qDebug() << "写入内容的长度" << len;
}
else
{qDebug() << "写文件失败";
}
向文件头部追加内容 (头部写入)
if (file.open(QIODevice::ReadWrite))
{QByteArray str = "头部~~~";qint64 len = file.write(str);qDebug() << "写入内容的长度" << len;
}
else
{qDebug() << "追加到文件头部失败";
}
向文件尾部追加内容 (追加写入)
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() : 一次性读取文件中所有的内容
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 中
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来创建界面
-
菜单栏
-
工具栏
只能显示在上方,不能移动不能悬浮
可以修改图标大小
3.中心部件
状态栏: 只能使用代码来创建
// 窗口基本设置
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 槽函数即可。
// 快捷键设置
ui->actionExit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
// 链接信号和槽,实现关闭功能
connect(ui->actionExit, &QAction::triggered, this, &MainWindow::close);
2.2.2 另存为
实现思路:
-
判断多行文本框中是否有内容
没有则不进行操作
-
如果有,则弹出文件保存框
-
点击文件保存框的 "保存" 按钮时,获取文件路径,获取多行文本框中的内容,将内容写入文件
// 另存为
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 保存
实现思路:
-
判断多行文本框中是否有内容; 如果没有则不做任何操作
-
如果有,判断是否有文件路径;
① 如果没有,则弹出文件保存框,获取文件路径,进行写入操作
② 如果有,覆盖写入
注意事项:
在头文件中加入了 filePath 属性,获取的文件保存路径都要放在 filePath 属性中(包括另存为时使用filePath)
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 打开
核心功能:
-
点击 "打开" 按钮时,弹出文件打开框,选中文件,得到文件路径
-
根据文件路径,读取文件中的内容,再显示到 textEdit 上
扩展功能:
-
判断 textEdit 中是否有内容,如果没有则直接执行打开
-
如果有,则弹出询问框。 如果点击 取消,则执行开大
-
如果选择 保存, 执行保存的流程
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 新建
实现思路:
-
判断文本区域是否有内容
-
如果没有,则将 filePath 置空,同时将文本区域也置空
-
如果有,则弹出询问框,询问是否需要保存。
① 选择取消时,则将 filePath 置空,同时将 文本区域也置空
② 选择保存时,弹出文件保存框。得到文件路径并将其保存在 filePath 中,再获取文本区域的内容,进行写文件操作。
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 | ReadOnlyfile.open(QIODevice::WriteOnly);file.write(tmp.toUtf8());}}// 清空操作filePath = "";ui->textEdit->setText("");
});
2.3 编辑菜单
利用 QTextEdit 的槽函数即可
// 复制
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 自动换行
实现思路:
-
设置一个标记来标志当前是否为 换行状态 (true 换行 | false 不换行)
-
显示图标、自动换行
-
在 "自动换行" 菜单上注册信号,判断状态,如果为true则显示图标,自动换行;反之,不显示图标,不换行
核心方法:
-
QTextEdit::setLineWrapMode(QTextEdit::WidgetWidth | QTextEdit::NoWrap)
-
QTextEdit::WidgetWidth 自动换行
-
QTextEdit::NoWrap 不自动换行
-
实现:
1.在头文件中定义状态
class MainWindow : public QMainWindow
{...
private:Ui::MainWindow *ui;QString filePath;// 自动换行的标记,true 是自动换行 | false 是不自动换行bool warpFlag = true;
};
2.在源文件中实现
// 程序首次运行时进行初始化状态
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时不换行,则设置图标为空,自动换行的状态为 NoWrapui->actionWrap_2->setIcon(QIcon(""));ui->textEdit->setLineWrapMode(QTextEdit::NoWrap);}else{// 如果为true时自动换行,设置图标,自动换行状态为 WordWrapui->actionWrap_2->setIcon(QIcon(":/icon/r.png"));ui->textEdit->setLineWrapMode(QTextEdit::WidgetWidth);}
});
2.4.2 字体
实现思路:
-
点击 "字体" 时,弹出字体选择框(QFontDialog)
-
当用户点击 "确定" 按钮时,获取选中的字体数据
-
将字体数据设置到 textEdit 中
connect(ui->actionFont, &QAction::triggered, [=](){bool flag = true;// 打开字体选择框,返回值能够保存用户选择的字体数据QFont font = QFontDialog::getFont(&flag);// 将字体数据设置到 textEdit 中ui->textEdit->setFont(font);
});
2.5 状态栏
目标: 显示文本长度
实现步骤:
-
使用 QTextEdit 的 textChanged 信号,该信号是一旦文本框中的内容发送变化就会触发
-
获取 QTextEdit 中内容,使用 size 方法来获取内容的长度,最后再将长度显示到 状态栏的QLabel中
// 在头文件中声明了状态栏中的QLabel
class MainWindow : public QMainWindow
{....private slots:// textChanged 匹配的槽函数void on_textEdit_textChanged();private:Ui::MainWindow *ui;QString filePath;bool warpFlag = true;// 状态栏中使用 QLabelQLabel *statusLb;
};
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 状态栏
逻辑同 自动换行
// 是否显示状态栏
connect(ui->actionStatus, &QAction::triggered, [=](){isStatusLbShow = !isStatusLbShow;if (isStatusLbShow == true){statusLb->show();}else{statusLb->hide();}
});
2.6.2 放大&缩小
实现步骤:
-
在头文件中对字体数据进行单独声明 (family、pointSize、italic、bold)
优势: 1. 可以在程序首次运行时对 textEdit 中的字体进行设置 2. 方便单独对字体进行放大和缩小的操作
-
在源文件中,初始化 textEdit 中的字体数据
-
点击 "放大" 和 "缩小" 时,单独设置 pointSize 的值
class MainWindow : public QMainWindow
{......private:....// 设置字体数据QString family = "微软雅黑";int pointSize = 16;bool italic = true;bool bold = true;
};
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{.....// 设置字体ui->textEdit->setFont(QFont(family, pointSize, italic, bold));....
}
// 放大
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 修补: 在 "格式" 菜单中调整字体之后,需要将最新的字体数据保存在属性中,否则放大和缩小会出错
// 字体
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 帮助菜单
打开浏览器
connect(ui->actionHelpDoc, &QAction::triggered, [](){QDesktopServices::openUrl(QUrl("https://www.baidu.com"));
});