Markdownedit
1 markdownhighlighter.h
QList<QTextCharFormat> titleFormats;//字体格式容器
QRegularExpression titleRegex;//正则表达式类
- 利用QList容器类以数组的形式存放编辑字体的类QTextCharFormat
- 创建正则表达式类用于高亮文本的获取
struct HighlightingRule
{
QRegularExpression pattern;
QTextCharFormat format;//设定格式
};
QVector<HighlightingRule> highlightingRules;//高亮显示规则容器
创建结构体类型HighlighterRule,其中成员有:
- 正则表达式类型的pattern用于储存高亮文本
- format用于传输高亮类型的指令
利用动态数组模板QVector创建结构体highlightingRules
public:
MarkdownHighlighter(QTextDocument *parent);
给MarkdownHighter类提供它的父亲QTextDocument,这也是QSyntaxHighlighter的接口
protected:
void highlightBlock(const QString &text);
保护成员函数highlightBlock用于代码块函数的实现
2.markdownhighlighter.cpp
2.1 标题高亮
for (int i = 0; i < 9; ++i) {
QTextCharFormat f;
f.setFontWeight(QFont::Bold);//设置黑体
f.setForeground(Qt::blue);//设置颜色
f.setFontPointSize(20 - i * 2);//设置字体大小
titleFormats.append(f);//将f追加到高亮容器中
}
设置标题字体为黑体
字体颜色为红色
字体大小随着输入#的多少而减小
将TextCharFormat的字体编辑类型f加到titleFormats容器内
2.2 字体高亮
QTextCharFormat boldFormat;
boldFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression(QStringLiteral("\\*\\*.*\\*\\*"));//用正则表达式设置黑体加粗的字符串模式
rule.format = boldFormat;
highlightingRules.append(rule);// 将正则表达式和指定的格式分配给HighlightingRule对象,并将该对象附加到规则列表中。
利用QFont类将字体类型设置为黑体
利用正则表达式储存****内的需要高亮的文本内容
设置指令为字体高亮指令
追加到容器后
- 我们指定一个字符串模式,它实际上是一个捕获所有Qt类名的正则表达式。
- 然后,我们将正则表达式和指定的格式分配给HighlightingRule对象,并将该对象附加到规则列表中。
2.3 设置斜体
QTextCharFormat italicFormat;
italicFormat.setFontItalic(true);//true为斜体,false为非斜体
rule.pattern = QRegularExpression(QStringLiteral("\\-.*\\-"));//设置斜体
rule.format = italicFormat;
highlightingRules.append(rule);
利用setFontItalic设置斜体,如果italic为true,将文本格式的字体设置为斜体;否则字体将是非斜体。
利用正则表达式储存–内的需要高亮的文本内容
设置指令为斜体指令
追加到容器后
2.4 设置超链接
QTextCharFormat linkFormat;
linkFormat.setForeground(Qt::blue);
linkFormat.setFontUnderline(true);
rule.pattern = QRegularExpression(QStringLiteral("https?\\:\\/\\/\\S+"));//设置htpps://超链接
rule.format = linkFormat;
highlightingRules.append(rule);
利用setForeground将字体设置为蓝色
利用正则表达式储存https://后的内容
设置指令为超链接指令
追加到容器后
2.5 设置代码块
codeFormat.setForeground(Qt::red);
codeFormat.setBackground(QColor(230, 230, 230));
设置代码块的字体颜色和背景颜色
2.6 HighlighterBlock函数
void MarkdownHighlighter::highlightBlock(const QString &text)
{
//首先,应用存储在highlightingRules向量中的语法高亮显示规则。检索每个规则(即每个HighlightingRule对象)
if (text == "```") {
setCurrentBlockState(previousBlockState() == STATE_CODE ? 0
: STATE_CODE);
setFormat(0, text.count(), codeFormat);//参数为0不执行任何操作,bool参数,文本字数,代码框类型
return;
}
if (previousBlockState() == STATE_CODE) {
setCurrentBlockState(STATE_CODE);
setFormat(0, text.count(), codeFormat);
return;
}
for (const HighlightingRule &rule : qAsConst(highlightingRules))//将高亮规则容器转化为const HighlightingRule类型的左值
{
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);//使用QRegularExpression::globalMatch()函数在给定的文本块中搜索模式。
while (matchIterator.hasNext()) {
// 当发现模式出现时,获取该模式
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format); //为了执行实际的格式化,QSyntaxHighlighter类提供了setFormat()函数。这个函数对作为参数传递给highlightBlock()函数的文本块进行操作。指定的格式将从给定的起始位置应用于给定长度的文本。在显示时,以给定格式设置的格式化属性将与直接存储在文档中的格式化信息合并。文档本身不会被这个函数设置的格式修改。 重复此过程,直到在当前文本块中找到该模式的最后一次出现为止。
}
}
auto m = titleRegex.match(text);//匹配文本
if (m.hasMatch())//正则表达式是否匹配
{
setFormat(0, text.count(), titleFormats.at(m.captured().length() - 2)/*获取文本中的位置*/);//at 对titleFormats进行只读访问
return;
}
}
输入三飘号以更改参数将文本块设置为newstate类型。
首先,应用存储在highlightingRules向量中的语法高亮显示规则。检索每个规则(即每个HighlightingRule对象)
对文本进行正则表达式匹配 并返回匹配到的第一个匹配结果的迭代器。
利用QRegularExpressionMatch类提供了根据字符串匹配QRegularExpression正则表达式的结果,如果该结果存在(即正则表达式后的next有文本)则传入参数给setFormat,利用match.capturedStart()获取文本开头位置,利用match.capturedLength()获取文本结尾位置,利用高亮规则进行高亮。
最后设置一个对打开的md文件高亮文本的识别。
3 Mainwindow.cpp
mainwindow的头文件里基本是一些函数的接口,以下会提到,不再赘述。
connect(textEdit->verticalScrollBar(),
&QScrollBar::valueChanged,
this,
&MainWindow::textBrowser_scroll);
connect(this->pushButton,SIGNAL(clicked(bool)),this,SLOT(blodclick()));
connect(this->pushButton_2,SIGNAL(clicked(bool)),this,SLOT(italicclick()));
connect(this->pushButton_3,SIGNAL(clicked(bool)),this,SLOT(linkclick()));
- 连接textBrowser滚动块,使其与TextEdit文本移动同步。
- 连接按钮信号和其槽函数实现功能。
MainWindow::~MainWindow()
{
if (!_filePath.isEmpty()) {
QSettings s;
s.setValue("FilePath", _filePath);
s.sync();
}
}
析构函数,文件路径写入后在析构时赋值,并利用sync将缓冲区数据写入文件系统。
3.1 滚动块实现函数
void MainWindow::textBrowser_scroll(int value)
{
textBrowser->verticalScrollBar()->setValue(
(int)(((float)value / (float)textEdit->verticalScrollBar()->maximum())
* (float)textBrowser->verticalScrollBar()->maximum()));
}
3.2 预览和字数行数统计
void MainWindow::on_textEdit_textChanged()
{
textBrowser->setText(textEdit->toPlainText());
QTextCursor tc = textEdit->textCursor(); //当前光标
int rowNum = tc.blockNumber() + 1;//获取光标所在行的行号
qDebug()<<"行数:"<<rowNum;
this->label->setText(QString::number(rowNum));
int lettercount=textEdit->document()->characterCount();
qDebug()<<"字数:"<<lettercount;
this->label_2->setText(QString::number(lettercount));
}
这里不太熟,qDebug了一下。
3.3 新建按钮实现
void MainWindow::on_actionNew_triggered()
{
_filePath.clear();
textEdit->clear();
textBrowser->clear();
}
路径新建
文本新建
Html文本新建
3.4 打开按钮实现
void MainWindow::on_actionOpen_triggered()
{
auto filePath
= QFileDialog::getOpenFileName(this,
"Open markdown",
QString(),
"Markdown files (*.md);;All files (*)");//打开文件
if (!filePath.isEmpty()) {
QFile f(filePath);//读取文件路径
if (!f.open(QIODevice::ReadOnly | QIODevice::Text))//只读,行结束符转化为/n
return;
textEdit->setText(f.readAll());//读取所有数据,隐式转化为QString
f.close();//关闭文件对象
_filePath = filePath;
}
}
获取路径后打开,对外界进行只读操作
3.5 保存按钮实现
void MainWindow::on_actionSave_triggered()
{
if (_filePath.isEmpty())
on_actionSave_as_triggered();
QFile f(_filePath);
if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
return;
f.write(textEdit->toPlainText().toUtf8());//以纯文本方式的字符串形式表示
f.close();
}
以纯文本形式保存,使用UTF-8字符集[utf 8]
3.6 另存为实现
void MainWindow::on_actionSave_as_triggered()
{
auto filePath
= QFileDialog::getSaveFileName(this,
"Open markdown",
QString(),
"Markdown files (*.md);;All files (*)");
if (!filePath.isEmpty()) {
QFile f(filePath);
if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
return;
f.write(textEdit->toPlainText().toUtf8());
f.close();
_filePath = filePath;
}
}
操作基本同上,增加输入文件名功能
3.7 关闭按钮实现
void MainWindow::closeEvent(QCloseEvent *event)
{
auto filePath
= QFileDialog::getSaveFileName(this,
"Open markdown",
"markdown",
"Markdown files (*.md);;All files (*)");
if (!filePath.isEmpty()) {\
QFile f(filePath);
if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
return;
f.write(textEdit->toPlainText().toUtf8());
f.close();
_filePath = filePath;
int ret=QMessageBox::question(this,"退出","文件已自动保存,是否退出?","是","否");
if(ret==1)
{
event->ignore();
}
}
else
{
int ret=QMessageBox::question(this,"退出","文件未保存,是否退出?","是","否");
if(ret==1)
{
event->ignore();
}
}
}
在关闭前添加另存为功能,将自动保存可视化,为添加文件名则会提醒未保存
3.8 其他按钮实现
void MainWindow::blodclick()
{
QString str="****";
this->textEdit->append(str);
}
void MainWindow::italicclick()
{
QString str="--";
this->textEdit->append(str);
}
void MainWindow::linkclick()
{
QString str="https://";
this->textEdit->append(str);
}
三个按钮实现,将QString类字符添加至文本后,不再赘述。