效果:
按下ctrl+f跳出搜索框,然后支持搜索next或者previous。支持搜索下一步和上一步。
嵌入框的实现
#ifndef POPFINDBOX_H
#define POPFINDBOX_H#include <QWidget>class QLineEdit;
class QPushButton;
class PopFindBox : public QWidget
{Q_OBJECT
public:PopFindBox(QWidget* parent=nullptr);~PopFindBox();signals:void searchText(const QString& text);void searchNext(const QString& text);void searchPrev(const QString& text);protected:bool eventFilter(QObject *obj, QEvent *e);private:QLineEdit* key;QPushButton* prev;QPushButton* next;
};#endif // POPFINDBOX_H#include "popfindbox.h"#include <QEvent>
#include <QKeyEvent>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>
PopFindBox::PopFindBox(QWidget *parent):QWidget(parent)
{ key = new QLineEdit;key->setObjectName("keyword");prev = new QPushButton(tr("pre"), this);prev->setObjectName("prebtn");next = new QPushButton(tr("next"), this);next->setObjectName("nextbtn");QHBoxLayout* layout = new QHBoxLayout;layout->setContentsMargins(2,0,2,0);layout->addWidget(key);layout->addWidget(prev);layout->addWidget(next);layout->setStretch(0, 1);setLayout(layout);resize(260, 30);connect(prev, &QPushButton::clicked, this, [&]{emit searchPrev(key->text());});connect(next, &QPushButton::clicked, this, [&]{emit searchNext(key->text());});key->installEventFilter(this);//setWindowFlags(Qt::Widget|Qt::FramelessWindowHint); //for dialogsetWindowFlags(Qt::CustomizeWindowHint|Qt::FramelessWindowHint);
}PopFindBox::~PopFindBox()
{}bool PopFindBox::eventFilter(QObject *obj, QEvent *e)
{if(key == obj){if(e->type() == QEvent::KeyPress){QKeyEvent *ee = static_cast<QKeyEvent*>(e);if(ee && (ee->key() == Qt::Key_Enter || ee->key() == Qt::Key_Return)){searchText(key->text());return true;}}}return QWidget::eventFilter(obj, e);
}
qtextedit文本实现:
#ifndef LOGTEXTEDIT_H
#define LOGTEXTEDIT_H#include <QTextEdit>class PopFindBox;
class LogTextEdit : public QTextEdit
{Q_OBJECT
public:LogTextEdit(QWidget* parnet=nullptr);void searchPrevious(const QString& text);void searchNext(const QString& text);protected:void keyPressEvent(QKeyEvent *e);private:void searchText(const QString& text, QTextDocument::FindFlags flags);private:bool mFind{false};PopFindBox* findBox; QTextCursor* mLastFound{nullptr};
};#endif // LOGTEXTEDIT_H
#include "logtextedit.h"
#include "popfindbox.h"#include <QColor>
#include <QMessageBox>
#include <QKeyEvent>
#include <QTextBlock>
#include <QTextCharFormat>LogTextEdit::LogTextEdit(QWidget *parnet):QTextEdit(parnet)
{ findBox = new PopFindBox(this);findBox->hide();connect(findBox, &PopFindBox::searchText, this, &LogTextEdit::searchNext);connect(findBox, &PopFindBox::searchNext, this, &LogTextEdit::searchNext);connect(findBox, &PopFindBox::searchPrev, this, &LogTextEdit::searchPrevious);connect(this, &LogTextEdit::cursorPositionChanged, [&]{if(mLastFound) *mLastFound = textCursor();});
}void LogTextEdit::searchPrevious(const QString& text)
{return searchText(text, QTextDocument::FindBackward);
}void LogTextEdit::searchNext(const QString& text)
{return searchText(text, QTextDocument::FindFlags());
}void LogTextEdit::keyPressEvent(QKeyEvent *e)
{if(e->key() == Qt::Key_F&& e->modifiers() == Qt::CTRL){ findBox->show();findBox->move(width()-findBox->width()-3, 1);}else if(e->key() == Qt::Key_Escape){findBox->hide();if(mFind){document()->undo();//delete mLastFound;//mLastFound = nullptr;}mFind = false;}
}void LogTextEdit::searchText(const QString &text, QTextDocument::FindFlags flags)
{if(text.isEmpty())return;bool clear = true;QSignalBlocker block(this);auto doc = this->document();if(!mLastFound)mLastFound = new QTextCursor(doc);QTextCursor highlightCursor(doc);QTextCursor cursor(doc);cursor.beginEditBlock();QTextCharFormat plainFormat(mLastFound->charFormat());QTextCharFormat colorFormat = plainFormat;colorFormat.setForeground(QColor("#ff8911"));while (!highlightCursor.isNull() && !highlightCursor.atEnd()){highlightCursor = doc->find(text, *mLastFound, flags);if (!highlightCursor.isNull()){this->setTextCursor(highlightCursor);//更新可见光标if(mFind && clear)doc->undo();*mLastFound = highlightCursor;mLastFound->movePosition(QTextCursor::WordRight,QTextCursor::KeepAnchor);mLastFound->mergeCharFormat(colorFormat);//highlightCursor.select(QTextCursor::LineUnderCursor); //select row instead of keywordmFind = true;clear = false;break;}}cursor.endEditBlock();if (clear)QMessageBox::information(this, tr("Word Not Found"),tr("Sorry, the word cannot be found."));
}#if 0
//点击搜索按钮查找相应字段、并高亮显示查到的第一个数据所在行
void searchText()
{QString text = ui->lineEdit->text().trimmed();if(nullptr == text){myHelper::ShowMessageBoxError(QString("搜索内容不能为空!"));return;}loginDoc = ui->txtMain->document(); //返回plainTextEdit加载的文本对象loginDocNum = loginDoc->blockCount() ;//返回文档中的文本块的数量,回车符是一个blocktravPlainTextDoc(index,loginDocNum,loginDoc,text);//index是我所使用到的控件stacketWidget的currentIndex,不用管。这个函数里面就是遍历数据以及高亮显示。
}//遍历并高亮显示查询到的第一个数据所在行
void travPlainTextDoc(int index,int docNum,QTextDocument *doc,QString text)
{
//2021-7-23 若之前设置了标记,需要将之前的标记颜色改为背景色recoverExtraSelection(index);for (int i = 0; i < docNum; i++){QTextBlock textLine = doc->findBlockByNumber(i) ; // 文本中的一段QString str = textLine.text();if(str.contains(text)){QList<QTextEdit::ExtraSelection> extraSelections;//提供一种方式显示选择的文本if(index == 0){loginCurrentDocNum = i;extraSelections = ui->txtMain->extraSelections();//获取之前高亮的设置ui->txtMain->setTextCursor(QTextCursor(textLine));//更新可见光标}QTextEdit::ExtraSelection selection;QColor lineColor = QColor("#F79332");selection.format.setBackground(lineColor);selection.format.setProperty(QTextFormat::FullWidthSelection, true);if(index == 0){selection.cursor = ui->txtMain->textCursor();}selection.cursor.clearSelection();//通过设置锚到光标位置清除当前的选择extraSelections.append(selection);if(index == 0){ui->txtMain->setExtraSelections(extraSelections);//设置高亮}
//查找到第一个就返回return;}}
}
//清除上一次的高亮行设置
void recoverExtraSelection(int index)
{QList<QTextEdit::ExtraSelection> selections;if(index == 0){selections = ui->txtMain->extraSelections();}
//这一步是高亮之前的颜色,没有这一步即使选择下一行高亮了,上一行高亮的也不会消失。不想恢复的当我没说。for(int i = 0;i < selections.count();i++){QColor lineColor = QColor("#646464");selections.at(i).format.setBackground(lineColor);selections.at(i).format.setProperty(QTextFormat::FullWidthSelection, true);}if(selections.count() > 0){if(index == 0){ui->txtMain->setExtraSelections(selections);//恢复背景色ui->txtMain->extraSelections().clear();}}
}//上一个,我没有写成循环的遍历的
void on_btn_searchLast_clicked()
{int index = ui->stackedWidget->currentIndex();QString text = ui->lineEdit->text().trimmed();if(nullptr == text){myHelper::ShowMessageBoxError(QString("当前搜索内容为空!"));return;}int currentDocNum = 0;int docNum = 0;QTextDocument *doc = nullptr;if(index == 0){currentDocNum = loginCurrentDocNum;docNum = loginDocNum;doc = loginDoc;}if(currentDocNum == 0){return;}recoverExtraSelection(index);for(int i = currentDocNum - 1;i < docNum;i--){QTextBlock textLine = doc->findBlockByNumber(i) ; // 文本中的一段QString str = textLine.text();if(str.contains(text)){QList<QTextEdit::ExtraSelection> extraSelections;//提供一种方式显示选择的文本if(index == 0){loginCurrentDocNum = i;extraSelections = ui->txtMain->extraSelections();//获取之前高亮的设置ui->txtMain->setTextCursor(QTextCursor(textLine));//更新可见光标}QTextEdit::ExtraSelection selection;QColor lineColor = QColor("#F79332");selection.format.setBackground(lineColor);selection.format.setProperty(QTextFormat::FullWidthSelection, true);if(index == 0){selection.cursor = ui->txtMain->textCursor();}selection.cursor.clearSelection();//通过设置锚到光标位置清除当前的选择extraSelections.append(selection);if(index == 0){ui->txtMain->setExtraSelections(extraSelections);//设置高亮}return;}}
}//下一个
void on_btn_searchNext_clicked()
{int index = ui->stackedWidget->currentIndex();QString text = ui->lineEdit->text().trimmed();if(nullptr == text){myHelper::ShowMessageBoxError(QString("当前搜索内容为空!"));return;}int currentDocNum = 0;int docNum = 0;QTextDocument *doc = nullptr;if(index == 0){currentDocNum = loginCurrentDocNum;docNum = loginDocNum;doc = loginDoc;}if(currentDocNum >= docNum - 1){myHelper::ShowMessageBoxError(QString(""));return;}recoverExtraSelection(index);for(int i = currentDocNum + 1;i < docNum;i++){QTextBlock textLine = doc->findBlockByNumber(i) ; // 文本中的一段QString str = textLine.text();if(str.contains(text)){QList<QTextEdit::ExtraSelection> extraSelections;//提供一种方式显示选择的文本if(index == 0){loginCurrentDocNum = i;extraSelections = ui->txtMain->extraSelections();//获取之前高亮的设置ui->txtMain->setTextCursor(QTextCursor(textLine));//更新可见光标}QTextEdit::ExtraSelection selection;QColor lineColor = QColor("#F79332");selection.format.setBackground(lineColor);selection.format.setProperty(QTextFormat::FullWidthSelection, true);if(index == 0){selection.cursor = ui->txtMain->textCursor();}selection.cursor.clearSelection();//通过设置锚到光标位置清除当前的选择extraSelections.append(selection);if(index == 0){ui->txtMain->setExtraSelections(extraSelections);//设置高亮}return;}}
}#endif