qt实现文件比较
功能点
1.鼠标拖动到文本区进行读取显示
2.高亮第二个文本区的文本
核心逻辑:
每次读取文件后将文本内容存到一个QStringList中 按换行分割。
确定两个列表中较长的那个的长度。这确保在比较两个文件时,即使一个文件比另一个长,也能进行完整的行比较。
检查三种情况来判定两个文件在某行是否不同:i < lines1.size() && i >= lines2.size()
如果 lines1 有这一行,但 lines2 已经没有更多行了。
i >= lines1.size() && i < lines2.size()
如果 lines2 有这一行,但 lines1 已经没有更多行了。i < lines1.size() && i < lines2.size() && lines1[i].trimmed() != lines2[i].trimmed()
如果两个列表都有这一行,但内容(去除前后空白后)不同。结果展示:
#ifndef MYEDIT_H #define MYEDIT_H #include <QApplication> #include <QWidget> #include <QVBoxLayout> #include <QPlainTextEdit> #include <QDragEnterEvent> #include <QDropEvent> #include <QMimeData> #include <QFile> #include <QTextStream> #include <QDebug> #include<QPainter> class MyEdit : public QPlainTextEdit { Q_OBJECT public: MyEdit(QWidget *parent = nullptr); protected: void dragEnterEvent(QDragEnterEvent *event) override; void dropEvent(QDropEvent *event) override; private: int lineNumberAreaWidth(); public: QStringList fileLines; private: void loadFile(const QString &fileName); }; #endif // MYEDIT_H
#include "MyEdit.h" MyEdit::MyEdit(QWidget *parent): QPlainTextEdit(parent) { setAcceptDrops(true); } void MyEdit::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls()) { event->acceptProposedAction(); } } void MyEdit::dropEvent(QDropEvent *event) { const QMimeData *mimeData = event->mimeData(); if (mimeData->hasUrls()) { QList<QUrl> urlList = mimeData->urls(); if (urlList.size() == 1) { // 只处理单个文件 QString fileName = urlList.at(0).toLocalFile(); if (!fileName.isEmpty()) { loadFile(fileName); event->acceptProposedAction(); } } } } void MyEdit::loadFile(const QString &fileName) { QFile file(fileName); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); in.setCodec("UTF-8"); QString content = in.readAll(); setPlainText(content); file.close(); // 清空旧的内容,并存储新的每一行 fileLines.clear(); fileLines = content.split('\n', QString::KeepEmptyParts); } else { qDebug() << "Failed to open file:" << fileName; } }
#ifndef FILECOMPARER_H #define FILECOMPARER_H #include <QPushButton> #include <QWidget> #include <QTextCursor> #include <QTextDocument> #include <QTextBlock> #include<QHBoxLayout> #include<QSpacerItem> #include"MyEdit.h" class FileComparer : public QWidget { Q_OBJECT public: FileComparer(QWidget *parent = nullptr); ~FileComparer(); private: void initUI(); void compareAndHighlight(); void highlightLine(const QStringList &lines1, const QStringList &lines2); private: MyEdit *m_beforeFile; MyEdit *m_afterFile; QPushButton *compareButton; }; #endif // FILECOMPARER_H
#include "filecomparer.h" FileComparer::FileComparer(QWidget *parent) : QWidget(parent) { initUI(); } FileComparer::~FileComparer() { } void FileComparer::initUI() { this->resize(800,650); QVBoxLayout *layout = new QVBoxLayout(this); m_beforeFile = new MyEdit(this); m_afterFile = new MyEdit(this); compareButton = new QPushButton("比较文件", this); QHBoxLayout *hb1=new QHBoxLayout; hb1->addWidget(m_beforeFile); hb1->addWidget(m_afterFile); QHBoxLayout *hb2=new QHBoxLayout; hb2->addWidget(compareButton); hb2->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding)); layout->addLayout(hb1); layout->addLayout(hb2); setLayout(layout); this->m_afterFile->setStyleSheet("border:2px solid red"); this->m_beforeFile->setStyleSheet("border:2px solid blue"); connect(compareButton, &QPushButton::clicked, this, &FileComparer::compareAndHighlight); } void FileComparer::compareAndHighlight() { highlightLine(m_beforeFile->fileLines,m_afterFile->fileLines); } void FileComparer::highlightLine(const QStringList &lines1, const QStringList &lines2) { int maxLines = qMax(lines1.size(), lines2.size()); QTextCharFormat format; format.setBackground(Qt::yellow); for (int i = 0; i < maxLines; ++i) { if ((i < lines1.size() && i >= lines2.size()) || (i >= lines1.size() && i < lines2.size()) || (i < lines1.size() && i < lines2.size() && lines1[i].trimmed() != lines2[i].trimmed())) { QTextCursor cursor(m_afterFile->document()->findBlockByLineNumber(i)); cursor.select(QTextCursor::LineUnderCursor); cursor.mergeCharFormat(format); } } }