QT 组件化开发 自动生成基础组件

在做QT自定义组件开发的时候,拷贝代码,再修改太繁琐了,所以想着能不能自动生成下基础组件,于是有了自动生成组件的想法。一个基本的组件是长这个样子:
QT 组件化开发 自动生成基础组件
文章图片

.pri QT子工程配置文件 *.cpp,*.h, 组件内容 *plugin.cpp,*plugin.h,组件插件化配置,主要用于qt designer里进行拖拉

一开始的想法是使用bat脚本(因为里面使用了中文,所以此文件需要保存为ansi格式,保存成UTF-8的化执行会有问题)批处理,运行后先拷贝cpushbutton组件目录,然后遍历此目录,对文件进行重命名
@echo off set target=DialogButtonBox set cTarget=C%target% set qTarget=Q%target% set dir="%cd%/cpushbutton - 副本"set lowerCTarget=%cTarget% for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do call set lowerCTarget=%%lowerCTarget:%%i=%%i%%set upperCTarget=%cTarget% for %%i in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do call set upperCTarget=%%upperCTarget:%%i=%%i%%ren %dir% %lowerCTarget% set newDir="%cd%/%lowerCTarget%"for /r %newDir% %%i in (*.*) do ( if "%%~xi"==".pri" ( ren %%i "%lowerCTarget%%%~xi" )else ( echo "%%~ni"| findstr "plugin" >nul &&( ren %%i "%lowerCTarget%plugin%%~xi" )||( ren %%i "%lowerCTarget%%%~xi" ) ) )

重命名后需要的是文件内容替换,整理了一下后大概是这么些数据,为了方便,我在bat里自动生成了对应内容,在QT creator里直接拷贝过去,执行五次替换即可
echo CPUSHBUTTON-%upperCTarget% > 1.txt echo QPushButton-%qTarget% >> 1.txt echo CPushButton-%cTarget% >> 1.txt echo cpushbutton-%lowerCTarget% >> 1.txt echo cPushButton-c%target% >> 1.txt

感觉还是繁琐,就想着这五次替换能不能一部到位,可惜的是QT creator不能直接执行定义的脚本,直接做五次替换,所以萌生了自己写个程序呗,做文件替换。
【QT 组件化开发 自动生成基础组件】一、定义demo
demo.pri
HEADERS += $$PWD/{FILENAME}.h HEADERS += $$PWD/{FILENAME}plugin.h SOURCES += $$PWD/{FILENAME}.cpp SOURCES += $$PWD/{FILENAME}plugin.cpp

demo.h
/* * * @Authorclarence * @Time2022-06-28 T 14:32 * @Function* * * Copyright (c) 2022 * */ #ifndef {MACRO}_H #define {MACRO}_H#include <{PARENTCLASSNAME}> #include class QDESIGNER_WIDGET_EXPORT {CLASSNAME} : public {PARENTCLASSNAME} { Q_OBJECTpublic: {CLASSNAME}(QWidget *parent = 0); }; #endif // {MACRO}_H

demo.cpp
/* * * @Authorclarence * @Time2022-06-28 T 14:34 * @Function* * * Copyright (c) 2022 * */ #include "{FILENAME}.h"{CLASSNAME}::{CLASSNAME}(QWidget *parent) : {PARENTCLASSNAME}(parent) { }

dempplugin.h
/* * * @Authorclarence * @Time2022-06-28 T 14:33 * @Function* * * Copyright (c) 2022 * */ #ifndef {MACRO}PLUGIN_H #define {MACRO}PLUGIN_H#include class {CLASSNAME}Plugin : public QObject, public QDesignerCustomWidgetInterface { Q_OBJECT Q_INTERFACES(QDesignerCustomWidgetInterface)public: {CLASSNAME}Plugin(QObject *parent = nullptr); bool isContainer() const override; bool isInitialized() const override; QIcon icon() const override; QString domXml() const override; QString group() const override; QString includeFile() const override; QString name() const override; QString toolTip() const override; QString whatsThis() const override; QWidget *createWidget(QWidget *parent) override; void initialize(QDesignerFormEditorInterface *core) override; private: bool m_initialized; }; #endif // {MACRO}PLUGIN_H

demoplugin.cpp
/* * * @Authorclarence * @Time2022-06-28 T 14:34 * @Function* * * Copyright (c) 2022 * */ #include "{FILENAME}.h" #include "{FILENAME}plugin.h"#include {CLASSNAME}Plugin::{CLASSNAME}Plugin(QObject *parent) : QObject(parent) { m_initialized = false; }void {CLASSNAME}Plugin::initialize(QDesignerFormEditorInterface * /* core */) { if (m_initialized) return; // Add extension registrations, etc. herem_initialized = true; }bool {CLASSNAME}Plugin::isInitialized() const { return m_initialized; }QWidget *{CLASSNAME}Plugin::createWidget(QWidget *parent) { return new {CLASSNAME}(parent); }QString {CLASSNAME}Plugin::name() const { return QLatin1String("{SHOWNAME}"); }QString {CLASSNAME}Plugin::group() const { return QLatin1String("{GROUP}"); }QIcon {CLASSNAME}Plugin::icon() const { return QIcon(QLatin1String("")); }QString {CLASSNAME}Plugin::toolTip() const { return QLatin1String(""); }QString {CLASSNAME}Plugin::whatsThis() const { return QLatin1String(""); }bool {CLASSNAME}Plugin::isContainer() const { return false; }QString {CLASSNAME}Plugin::domXml() const { return QLatin1String(R"( > )" R"( {CLASSNAME} {FILENAME}.h {PARENTCLASSNAME} ") R"( )"); }QString {CLASSNAME}Plugin::includeFile() const { return QLatin1String(""); }

二、敲代码
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H#include #include #include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow { Q_OBJECTpublic: MainWindow(QWidget *parent = nullptr); ~MainWindow(); bool checkForms(); void toString(); bool CopyDirectoryFiles(const QString &fromDir,const QString &toDir); bool changeFiles(const QString &dir); void changeFile(const QString &filePath); QString replace(const QString sourceStr); void renderTreeView(QFileSystemModel *fileSystemModel,QTreeView *view,const QString &dir); private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked(); private: Ui::MainWindow *ui; QString m_sourceDir; QString m_targetDir; QString m_fileName; QString m_className; QString m_macro; QString m_caseName; QString m_parentClassName; QString m_group; QString m_showName; QFileSystemModel *sourceFileModel; QFileSystemModel *targetFileModel; }; #endif // MAINWINDOW_H

mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); this->setWindowTitle (tr("初始化组件自动生成")); QDir dir(QCoreApplication::applicationDirPath ()); dir.cdUp (); this->m_sourceDir = dir.absolutePath ()+ "/" + "demo"; sourceFileModel = new QFileSystemModel(this); targetFileModel = new QFileSystemModel(this); //初始化数据 QSettings settings("setting.ini",QSettings::IniFormat); ui->classNameQLE->setText (settings.value ("classNameQLE").toString ()); ui->parentClassNameQLE->setText (settings.value ("parentClassNameQLE").toString ()); ui->groupQLE->setText (settings.value ("groupQLE").toString ()); ui->showNameQLE->setText (settings.value ("showNameQLE").toString ()); ui->targetDirQLE->setText (settings.value ("targetDirQLE").toString ()); }MainWindow::~MainWindow() { //退出保存配置 QSettings settings("setting.ini",QSettings::IniFormat); settings.setValue ("classNameQLE",ui->classNameQLE->text ()); settings.setValue ("parentClassNameQLE",ui->parentClassNameQLE->text ()); settings.setValue ("groupQLE",ui->groupQLE->text ()); settings.setValue ("showNameQLE",ui->showNameQLE->text ()); settings.setValue ("targetDirQLE",ui->targetDirQLE->text ()); delete ui; }bool MainWindow::checkForms() { if(ui->classNameQLE->text ()== ""){ QMessageBox::critical (this,tr("错误"),tr("请输入类名")); return false; } if(ui->parentClassNameQLE->text ()== ""){ QMessageBox::critical (this,tr("错误"),tr("请输入父类名")); return false; } if(ui->groupQLE->text ()== ""){ QMessageBox::critical (this,tr("错误"),tr("请输入组信息")); return false; } if(ui->showNameQLE->text ()== ""){ QMessageBox::critical (this,tr("错误"),tr("请输入显示名称")); return false; } if(ui->targetDirQLE->text ()== ""){ QMessageBox::critical (this,tr("错误"),tr("请选择存放目录")); return false; } return true; }void MainWindow::toString() { qDebug()<<"文件名:" << m_fileName; qDebug()<<"类名:" << m_className; qDebug()<<"宏名:" << m_macro; qDebug()<<"实例名:" << m_caseName; qDebug()<<"父类名:" << m_parentClassName; qDebug()<<"组信息:" << m_group; qDebug()<<"显示名称:" << m_showName; qDebug()<<"源路径信息:" << m_sourceDir; qDebug()<<"目标路径信息:" << m_targetDir; }bool MainWindow::CopyDirectoryFiles(const QString &fromDir, const QString &toDir) { QDir sourceDir(fromDir); QDir targetDir(toDir); if(!targetDir.exists()) { if(!targetDir.mkdir(targetDir.absolutePath())) { return false; } }QFileInfoList list = sourceDir.entryInfoList(); for(int i = 0; i < list.size(); i++) { QFileInfo fileInfo = list.at(i); if(fileInfo.fileName()=="." || fileInfo.fileName()=="..") { continue; }if(fileInfo.isDir()) { if(!CopyDirectoryFiles(fileInfo.filePath(),targetDir.filePath(fileInfo.fileName()))) { return false; } } else { if(targetDir.exists(fileInfo.fileName())) { targetDir.remove(fileInfo.fileName()); //有相同的,直接删除 } if(!QFile::copy(fileInfo.filePath(),targetDir.filePath(fileInfo.fileName()))) { return false; } } } return true; }bool MainWindow::changeFiles(const QString &dir) { QDir sourceDir(dir); if(!sourceDir.exists()) { return false; }QFileInfoList list = sourceDir.entryInfoList(); for(int i = 0; i < list.size(); i++) { QFileInfo fileInfo = list.at(i); QString filePath = fileInfo.filePath (); QDir dir(filePath); if(fileInfo.fileName()=="." || fileInfo.fileName()=="..") { continue; } changeFile(filePath); //重命名 dir.cdUp (); QString newName = fileInfo.fileName ().replace("demo",m_fileName); QFile::rename (dir.absolutePath ()+"/"+fileInfo.fileName (),dir.absolutePath ()+"/"+newName); } return true; }void MainWindow::changeFile(const QString &filePath) { QFile file(filePath); //以文件方式读出 QString str; //读取内容 if (file.open(QIODevice::ReadOnly)) { QTextStream s(&file); //用文本流读取文件 str = s.readAll (); } file.close(); //清空内容 file.open(QIODevice::ReadWrite | QIODevice::Truncate); file.close (); //替换内容 str = replace(str); //写入新内容 if (file.open(QIODevice::WriteOnly)) { QTextStream s(&file); s << str; } file.close(); }QString MainWindow::replace(const QString sourceStr) { QString targetStr = sourceStr; //可以在这里增加其它变量替换 targetStr = targetStr.replace ("{FILENAME}",m_fileName); targetStr = targetStr.replace ("{CLASSNAME}",m_className); targetStr = targetStr.replace ("{PARENTCLASSNAME}",m_parentClassName); targetStr = targetStr.replace ("{MACRO}",m_macro); targetStr = targetStr.replace ("{SHOWNAME}",m_showName); targetStr = targetStr.replace ("{GROUP}",m_group); targetStr = targetStr.replace ("{CASENAME}",m_caseName); return targetStr; }void MainWindow::renderTreeView(QFileSystemModel *fileSystemModel,QTreeView *view, const QString &dir) { fileSystemModel->setRootPath(dir); view->setModel (fileSystemModel); view->setRootIndex(fileSystemModel->index(dir)); }void MainWindow::on_pushButton_clicked() { //校验数据 if(!checkForms ()){ return; }//赋值 QString classNameQLEText = ui->classNameQLE->text (); QString parentClassNameQLEText = ui->parentClassNameQLE->text (); QString groupQLEText = ui->groupQLE->text (); QString showNameQLEText = ui->showNameQLE->text (); QString targetDirQLEText = ui->targetDirQLE->text (); m_fileName = classNameQLEText.toLower (); m_className = classNameQLEText; m_macro = classNameQLEText.toUpper (); m_caseName = classNameQLEText.sliced (0,1).toLower() + classNameQLEText.sliced (1); m_parentClassName = parentClassNameQLEText; m_group = groupQLEText; m_showName = showNameQLEText; m_targetDir = targetDirQLEText + "/" + m_fileName; //拷贝目录 if(!CopyDirectoryFiles(m_sourceDir,m_targetDir)){ QMessageBox::critical (this,tr("错误"),tr("拷贝目录失败!")); return; }//读取文件并替换 if(!changeFiles(m_targetDir)){ QMessageBox::critical (this,tr("错误"),tr("文件修改失败!")); return; }//渲染view renderTreeView(sourceFileModel,ui->sourceTreeView,m_sourceDir); renderTreeView(targetFileModel,ui->targetTreeView,m_targetDir); QMessageBox::information (this,tr("成功"),tr("组件生成成功!")); }void MainWindow::on_pushButton_2_clicked() { QString dir = QFileDialog::getExistingDirectory (this,"Select Directory","/",QFileDialog::ShowDirsOnly); ui->targetDirQLE->setText (dir); }

最后的成型:
QT 组件化开发 自动生成基础组件
文章图片

QT 组件化开发 自动生成基础组件
文章图片

QT 组件化开发 自动生成基础组件
文章图片

    推荐阅读