一、主要功能与逻辑
- 选择根目录。
- 从根目录开始选取文件。
- 获取选取文件的相对路径,计算MD5值。
- 输入版本号与URL。
- 获取当前时间。
- 生成XML。
二、界面样式
生成的XML配置文件格式如下
三、代码实现
widget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1048</width>
<height>765</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,8,0">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>工作目录:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditRoot">
<property name="minimumSize">
<size>
<width>40</width>
<height>25</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnChoose">
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>添加</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6" stretch="4,1,4,1,4">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnAdd">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>添加文件</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnClear">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>清空文件</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0">
<item>
<widget class="QTableView" name="tableView"/>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="5,3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,0">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>URL:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditURL"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="0,5">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>版本号:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditVersion"/>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7" stretch="4,1,4">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnBuild">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>生成</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8" stretch="1,5">
<item>
<widget class="QLabel" name="labelDateTime">
<property name="text">
<string>time</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QFileSystemModel>
#include <QTableView>
#include <QStandardItemModel>
#include <QDateTime>
#include <QFileDialog>
#include <QDebug>
#include <QCryptographicHash>
#include <QXmlStreamWriter>
#include <QFile>
#include <QMessageBox>
#include <QHash>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnChoose_clicked();
void on_btnAdd_clicked();
void on_btnBuild_clicked();
void on_btnClear_clicked();
private:
Ui::Widget *ui;
QString m_rootPath;
QHash<QString, QString> m_fileHashes; // 存储文件相对路径和MD5值的哈希表
QStandardItemModel *headerModel;
void addFileToMap(const QString &filePath);
void displayOnView();
QString calculateFileMD5(const QString &filePath);
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QStandardItem>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 显示当前日期和时间
QDateTime currentDateTime = QDateTime::currentDateTime();
ui->labelDateTime->setText(currentDateTime.toString("yyyy-MM-dd hh:mm:ss"));
ui->lineEditURL->setText("http://");
// 创建TableView
headerModel = new QStandardItemModel(this);
headerModel->setColumnCount(3); // 设置列数为3
headerModel->setHorizontalHeaderLabels(QStringList() << QStringLiteral("文件名") << QStringLiteral("相对路径") << QStringLiteral("MD5值"));
ui->tableView->setModel(headerModel);
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // 让列自动拉伸
ui->btnAdd->setEnabled(false);
ui->btnClear->setEnabled(false);
ui->btnBuild->setEnabled(false);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnChoose_clicked()
{
// 选择根目录
QString rootPath = QFileDialog::getExistingDirectory(this, QStringLiteral("选择文件夹"), QDir::homePath());
if(!rootPath.isEmpty())
{
ui->lineEditRoot->setText(rootPath);
m_rootPath = rootPath;
ui->btnAdd->setEnabled(true);
}
}
void Widget::on_btnAdd_clicked()
{
QStringList fileNames = QFileDialog::getOpenFileNames(this, QStringLiteral("选择文件"), m_rootPath);
//将文件信息存入Map
for(const QString &fileName : fileNames)
{
addFileToMap(fileName);
}
displayOnView();
ui->btnClear->setEnabled(true);
ui->btnBuild->setEnabled(true);
}
void Widget::on_btnBuild_clicked()
{
// 获取URL、版本号和当前日期时间
QString globalURL = ui->lineEditURL->text();
if (!globalURL.endsWith('/'))
globalURL.append('/');
QString version = ui->lineEditVersion->text();
QString currentDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
// 创建XML文件并设置文件名
QString fileName = "ServerVersionInfo.xml";
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::warning(this, "Error", "Failed to open file for writing.");
return;
}
// 创建XML写入器
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("Config");
xmlWriter.writeStartElement("Server");
xmlWriter.writeTextElement("XMLURL", globalURL + fileName);
xmlWriter.writeTextElement("MAINVER", version);
xmlWriter.writeTextElement("VERDATE", currentDateTime);
xmlWriter.writeTextElement("AUTHOR", "Measgeek");
// 获取文件信息并写入XML文件
xmlWriter.writeStartElement("FILECOUNT");
xmlWriter.writeCharacters(QString::number(m_fileHashes.count()));
xmlWriter.writeEndElement();
xmlWriter.writeStartElement("FILES");
for (auto it = m_fileHashes.begin(); it != m_fileHashes.end(); ++it) {
QString filePath = it.key();
QString fileURL = globalURL + filePath;
QString fileHash = it.value();
xmlWriter.writeStartElement("FILE");
xmlWriter.writeTextElement("FILENAME", filePath);
xmlWriter.writeTextElement("FILEURL", fileURL);
xmlWriter.writeTextElement("FILEHASH", fileHash);
xmlWriter.writeEndElement(); // End of FILE
}
xmlWriter.writeEndElement(); // End of FILES
xmlWriter.writeEndElement(); // End of Server
xmlWriter.writeEndElement(); // End of Config
xmlWriter.writeEndDocument();
file.close();
QMessageBox::information(this, "Success", "Server version info generated successfully.");
}
void Widget::addFileToMap(const QString &filePath)
{
// 获取文件名、相对路径和MD5值
QString fileName = QFileInfo(filePath).fileName();
QString relativePath = QDir(m_rootPath).relativeFilePath(filePath);
QString fileHash = calculateFileMD5(filePath);
// 添加到哈希表中
m_fileHashes.insert(relativePath, fileHash);
qDebug() <<fileName<<"-"<<relativePath<<"-"<<fileHash;
// 添加到TableView中显示
QList<QStandardItem*> rowItems;
rowItems.append(new QStandardItem(fileName));
rowItems.append(new QStandardItem(relativePath));
rowItems.append(new QStandardItem(fileHash));
headerModel->appendRow(rowItems);
}
void Widget::displayOnView()
{
ui->tableView->setModel(headerModel);
}
QString Widget::calculateFileMD5(const QString &filePath)
{
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly))
{
qDebug() << "Failed to open file for reading: " << filePath;
return QString();
}
QCryptographicHash hash(QCryptographicHash::Md5);
if(hash.addData(&file))
{
return hash.result().toHex();
}
qDebug() << "Failed to calculate MD5 for file: " << filePath;
return QString();
}
void Widget::on_btnClear_clicked()
{
m_fileHashes.clear();
// 获取行数
int rowCount = headerModel->rowCount();
// 从末尾开始删除行
for (int i = rowCount - 1; i >= 0; --i) {
headerModel->removeRow(i);
}
displayOnView();
ui->btnBuild->setEnabled(false);
ui->btnClear->setEnabled(false);
}
四、模块讲解
获取当前时间
QDateTime currentDateTime = QDateTime::currentDateTime();
ui->labelDateTime->setText(currentDateTime.toString("yyyy-MM-dd hh:mm:ss"));
设置tableView的表头
headerModel->setColumnCount(3); // 设置列数为3
headerModel->setHorizontalHeaderLabels(QStringList() << QStringLiteral("文件名") << QStringLiteral("相对路径") << QStringLiteral("MD5值"));
ui->tableView->setModel(headerModel);
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // 让列自动拉伸
触发根目录选择按钮的点击事件
将根目录存入成员变量m_rootPath中
void Widget::on_btnChoose_clicked()
{
// 选择根目录
QString rootPath = QFileDialog::getExistingDirectory(this, QStringLiteral("选择文件夹"), QDir::homePath());
if(!rootPath.isEmpty())
{
ui->lineEditRoot->setText(rootPath);
m_rootPath = rootPath;
ui->btnAdd->setEnabled(true);
}
}
获取文件的相对路径与MD5值
void Widget::addFileToMap(const QString &filePath)
{
// 获取文件名、相对路径和MD5值
QString fileName = QFileInfo(filePath).fileName();
QString relativePath = QDir(m_rootPath).relativeFilePath(filePath);
QString fileHash = calculateFileMD5(filePath);
// 添加到哈希表中
m_fileHashes.insert(relativePath, fileHash);
qDebug() <<fileName<<"-"<<relativePath<<"-"<<fileHash;
// 添加到TableView中显示
QList<QStandardItem*> rowItems;
rowItems.append(new QStandardItem(fileName));
rowItems.append(new QStandardItem(relativePath));
rowItems.append(new QStandardItem(fileHash));
headerModel->appendRow(rowItems);
}