Qt 统计源码文件中的代码行和注释行

3 篇文章 0 订阅

环境:VS2017,Qt5.12.5

目的:VS本身可以统计代码行数,但个人感觉不太准,于是参考网上资料自己写了一个

注意事项:界面通过代码编写,非Designer设计

效果图:

源码:

CodeStatisticsTool.h

#pragma once

#include <QtWidgets/QWidget>
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTableWidget>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QProgressBar>

QT_BEGIN_NAMESPACE
class QAction;
class QDialogButtonBox;
class QGroupBox;
class QLabel;
class QLineEdit;
class QMenu;
class QMenuBar;
class QPushButton;
class QProgressBar;
class QTextEdit;
QT_END_NAMESPACE

class CodeStatisticsTool : public QWidget
{
    Q_OBJECT

public:
    CodeStatisticsTool(QWidget* parent = Q_NULLPTR);
    ~CodeStatisticsTool();

private:
    void initParseFileInfoTable();
    bool checkFile(const QString& fileName);
    void collectSuitFilePathList(const QString& dirPath, const bool& recursion, QStringList& allFilePathList);
    void parseAllFileCode(const QStringList& filePathList);
    void parseFileCode(const QString& filePath, int& lineCode, int& lineNotes, int& lineBlank);

private slots:
    void onSelectDirButtonClicked();
    void onClearDirButtonClicked();

    //UI
private:
    void createMenu();
    void createSettingGroupBox();

    QMenuBar* m_menuBar;
    QMenu* m_fileMenu;
    QAction* m_exitAction;

    QGroupBox* m_settingGroupBox;
    QLabel* m_filterLabel;
    QLineEdit* m_filterContents;
    QLabel* m_dirLabel;
    QLineEdit* m_dirContents;
    QPushButton* m_selectDirButton;
    QProgressBar* m_progressBar;
    QPushButton* m_clearDirButton;
    QTextEdit* m_summary;
    QTableWidget* m_parseFileInfoTable;

private:
    QStringList m_filePathList;
};

CodeStatisticsTool.cpp

#pragma execution_character_set("utf-8")

#include "CodeStatisticsTool.h"
#include <QtWidgets>

CodeStatisticsTool::CodeStatisticsTool(QWidget* parent)
    : QWidget(parent)
{
    createMenu();
    createSettingGroupBox();

    m_summary = new QTextEdit();
    m_summary->setFixedHeight(200);
    m_summary->setText("");
    initParseFileInfoTable();

    QVBoxLayout* mainLayout = new QVBoxLayout(this);
    mainLayout->setMenuBar(m_menuBar);
    mainLayout->addWidget(m_settingGroupBox);
    mainLayout->addWidget(m_summary);
    mainLayout->addWidget(m_parseFileInfoTable);
    setLayout(mainLayout);

    connect(m_selectDirButton, &QPushButton::clicked, this, &CodeStatisticsTool::onSelectDirButtonClicked);
    connect(m_clearDirButton, &QPushButton::clicked, this, &CodeStatisticsTool::onClearDirButtonClicked);

    setWindowTitle("解析代码行");
    setWindowState(Qt::WindowMaximized);
}

CodeStatisticsTool::~CodeStatisticsTool()
{
    //QMessageBox::about(NULL, "提示", "对话框结束");
}

void CodeStatisticsTool::initParseFileInfoTable()
{
    const int windowWidth = 1200;

    m_parseFileInfoTable = new QTableWidget(this);

    QStringList headTextList;
    headTextList << "文件名称" << "文件类型" << "文件大小(B)" << "总行数" << "代码行数" << "注释行数" << "空白行数" << "路径";
    QList<int> columnWidthList;
    columnWidthList << 0.2 * windowWidth << 0.1 * windowWidth << 0.1 * windowWidth
        << 0.1 * windowWidth << 0.1 * windowWidth << 0.1 * windowWidth << 0.1 * windowWidth
        << 0.2 * windowWidth;

    int columnCount = headTextList.count();
    m_parseFileInfoTable->setColumnCount(columnCount);
    m_parseFileInfoTable->setHorizontalHeaderLabels(headTextList);
    m_parseFileInfoTable->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_parseFileInfoTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
    m_parseFileInfoTable->setSelectionMode(QAbstractItemView::SingleSelection);
    m_parseFileInfoTable->verticalHeader()->setVisible(false);
    m_parseFileInfoTable->horizontalHeader()->setStretchLastSection(true);
    m_parseFileInfoTable->horizontalHeader()->setHighlightSections(false);
    m_parseFileInfoTable->verticalHeader()->setDefaultSectionSize(20);
    m_parseFileInfoTable->verticalHeader()->setHighlightSections(false);

    for (int i = 0; i < columnCount; ++i) 
    {
        m_parseFileInfoTable->setColumnWidth(i, columnWidthList.at(i));
    }
}

bool CodeStatisticsTool::checkFile(const QString& fileName)
{
    if (fileName.startsWith("moc_") || fileName.startsWith("ui_") || fileName.startsWith("qrc_"))
    {
        return false;
    }

    QFileInfo file(fileName);
    QString suffix = "*." + file.suffix();
    QString filterContents = m_filterContents->text().trimmed();
    QStringList filterList = filterContents.split(" ");
    return filterList.contains(suffix);
}

void CodeStatisticsTool::collectSuitFilePathList(const QString& dirPath, const bool& recursion, QStringList& allFilePathList)
{
    QDir dir(dirPath);
    QFileInfoList fileInfos = dir.entryInfoList();
    foreach(QFileInfo fileInfo, fileInfos)
    {
        QString fileName = fileInfo.fileName();
        if (fileInfo.isFile() && checkFile(fileName))
        {
            allFilePathList.push_back(fileInfo.filePath());
        }
        else
        {
            if ("." == fileName || ".." == fileName)
            {
                continue;
            }

            collectSuitFilePathList(fileInfo.absoluteFilePath(), recursion, allFilePathList);
        }
    }
}

void CodeStatisticsTool::parseAllFileCode(const QStringList& filePathList)
{
    m_parseFileInfoTable->setRowCount(0);

    int lineCode;
    int lineBlank;
    int lineNotes;
    int count = filePathList.count();
    m_parseFileInfoTable->setRowCount(count);

    int totalLines = 0;
    int totalBytes = 0;
    int totalCodes = 0;
    int totalNotes = 0;
    int totalBlanks = 0;

    for (int i = 0; i < count; ++i)
    {
        QFileInfo fileInfo(filePathList.at(i));
        parseFileCode(fileInfo.filePath(), lineCode, lineNotes, lineBlank);

        int lineAll = lineCode + lineBlank + lineNotes;

        QTableWidgetItem* itemName = new QTableWidgetItem();
        itemName->setText(fileInfo.fileName());

        QTableWidgetItem* itemSuffix = new QTableWidgetItem();
        itemSuffix->setText(fileInfo.suffix());

        QTableWidgetItem* itemSize = new QTableWidgetItem();
        itemSize->setText(QString::number(fileInfo.size()));

        QTableWidgetItem* itemLine = new QTableWidgetItem();
        itemLine->setText(QString::number(lineAll));

        QTableWidgetItem* itemCode = new QTableWidgetItem;
        itemCode->setText(QString::number(lineCode));

        QTableWidgetItem* itemNote = new QTableWidgetItem;
        itemNote->setText(QString::number(lineNotes));

        QTableWidgetItem* itemBlank = new QTableWidgetItem;
        itemBlank->setText(QString::number(lineBlank));

        QTableWidgetItem* itemPath = new QTableWidgetItem;
        itemPath->setText(fileInfo.filePath());

        itemSuffix->setTextAlignment(Qt::AlignCenter);
        itemSize->setTextAlignment(Qt::AlignCenter);
        itemLine->setTextAlignment(Qt::AlignCenter);
        itemCode->setTextAlignment(Qt::AlignCenter);
        itemNote->setTextAlignment(Qt::AlignCenter);
        itemBlank->setTextAlignment(Qt::AlignCenter);

        m_parseFileInfoTable->setItem(i, 0, itemName);
        m_parseFileInfoTable->setItem(i, 1, itemSuffix);
        m_parseFileInfoTable->setItem(i, 2, itemSize);
        m_parseFileInfoTable->setItem(i, 3, itemLine);
        m_parseFileInfoTable->setItem(i, 4, itemCode);
        m_parseFileInfoTable->setItem(i, 5, itemNote);
        m_parseFileInfoTable->setItem(i, 6, itemBlank);
        m_parseFileInfoTable->setItem(i, 7, itemPath);

        totalBytes += fileInfo.size();
        totalLines += lineAll;
        totalCodes += lineCode;
        totalNotes += lineNotes;
        totalBlanks += lineBlank;

        if (i % 100 == 0)
        {
            qApp->processEvents();
        }
    }

    QString summary;
    summary += ("文件数量:" + QString::number(count) + "\n");
    summary += ("文件大小(B):" + QString::number(totalBytes) + "\n");
    summary += ("文件总行数:" + QString::number(totalLines) + "\n");
    summary += ("文件总代码行数:" + QString::number(totalCodes) + "\n");
    summary += ("文件总注释行数:" + QString::number(totalNotes) + "\n");
    summary += ("文件总空白行数:" + QString::number(totalBlanks) + "\n");
    m_summary->setText(summary);
}

void CodeStatisticsTool::parseFileCode(const QString& filePath, int& lineCode, int& lineNotes, int& lineBlank)
{
    lineCode = 0;
    lineNotes = 0;
    lineBlank = 0;

    QFile file(filePath);
    if (file.open(QFile::ReadOnly))
    {
        QTextStream out(&file);
        QString line;
        bool isNote = false;

        while (!out.atEnd())
        {
            line = out.readLine();

            if (line.startsWith(" "))
            {
                line.remove(" ");
            }

            if (line.startsWith("/*"))
            {
                isNote = true;
            }

            if (isNote)
            {
                lineNotes++;
            }
            else
            {
                if (line.startsWith("//") || line.startsWith("///"))
                {
                    lineNotes++;
                }
                else if (line.isEmpty())
                {
                    lineBlank++;
                }
                else
                {
                    lineCode++;
                }
            }

            if (line.endsWith("*/"))
            {
                isNote = false;
            }
        }
    }
}

void CodeStatisticsTool::onSelectDirButtonClicked()
{
    QString dir = QFileDialog::getExistingDirectory(this, "选择目录", "./", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    if (!dir.isEmpty())
    {
        m_dirContents->setText(dir);
        m_filePathList.clear();
        collectSuitFilePathList(dir, true, m_filePathList);
        parseAllFileCode(m_filePathList);
    }
}

void CodeStatisticsTool::onClearDirButtonClicked()
{
    m_dirContents->setText("");
    m_summary->setText("");
    m_parseFileInfoTable->setRowCount(0);
}

void CodeStatisticsTool::createMenu()
{
    m_menuBar = new QMenuBar();

    m_fileMenu = new QMenu("文件", this);
    m_exitAction = m_fileMenu->addAction("退出");
    m_menuBar->addMenu(m_fileMenu);

    connect(m_exitAction, SIGNAL(triggered()), this, SLOT(close()));
}

void CodeStatisticsTool::createSettingGroupBox()
{
    m_settingGroupBox = new QGroupBox("设置");
    QVBoxLayout* settingLayout = new QVBoxLayout();

    QHBoxLayout* selectDirLayout = new QHBoxLayout();
    m_dirLabel = new QLabel("目录:", this);
    m_dirContents = new QLineEdit(this);
    m_selectDirButton = new QPushButton("选择目录", this);
    m_selectDirButton->setToolTip("遍历目录中所有的源码文件");
    selectDirLayout->addWidget(m_dirLabel);
    selectDirLayout->addWidget(m_dirContents);
    selectDirLayout->addWidget(m_selectDirButton);
    settingLayout->addLayout(selectDirLayout);

    m_clearDirButton = new QPushButton("清空目录", this);
    settingLayout->addWidget(m_clearDirButton);

    QHBoxLayout* filterLayout = new QHBoxLayout();
    m_filterLabel = new QLabel("过滤:", this);
    m_filterContents = new QLineEdit(this);
    m_filterContents->setText("*.h *.hpp *.c *.cpp");
    filterLayout->addWidget(m_filterLabel);
    filterLayout->addWidget(m_filterContents);
    settingLayout->addLayout(filterLayout);

    m_settingGroupBox->setLayout(settingLayout);
}

参考链接:https://github.com/feiyangqingyun

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值