在做 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 不能间接执行定义的脚本,间接做五次替换,所以萌发了本人写个程序呗,做文件替换。
一、定义 demo
demo.pri
HEADERS += $$PWD/{FILENAME}.h
HEADERS += $$PWD/{FILENAME}plugin.h
SOURCES += $$PWD/{FILENAME}.cpp
SOURCES += $$PWD/{FILENAME}plugin.cpp
demo.h
/*
*
* @Author clarence
* @Time 2022-06-28 T 14:32
* @Function *
*
* Copyright (c) 2022
*
*/
#ifndef {MACRO}_H
#define {MACRO}_H
#include <{PARENTCLASSNAME}>
#include <QtUiPlugin/QDesignerExportWidget>
class QDESIGNER_WIDGET_EXPORT {CLASSNAME} : public {PARENTCLASSNAME}
{
Q_OBJECT
public:
{CLASSNAME}(QWidget *parent = 0);
};
#endif // {MACRO}_H
demo.cpp
/*
*
* @Author clarence
* @Time 2022-06-28 T 14:34
* @Function *
*
* Copyright (c) 2022
*
*/
#include "{FILENAME}.h"
{CLASSNAME}::{CLASSNAME}(QWidget *parent) :
{PARENTCLASSNAME}(parent)
{
}
dempplugin.h
/*
*
* @Author clarence
* @Time 2022-06-28 T 14:33
* @Function *
*
* Copyright (c) 2022
*
*/
#ifndef {MACRO}PLUGIN_H
#define {MACRO}PLUGIN_H
#include <QDesignerCustomWidgetInterface>
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
/*
*
* @Author clarence
* @Time 2022-06-28 T 14:34
* @Function *
*
* Copyright (c) 2022
*
*/
#include "{FILENAME}.h"
#include "{FILENAME}plugin.h"
#include <QtPlugin>
{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. here
m_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"(
<ui language="c++">>
<widget class="{CLASSNAME}" name="{CASENAME}"/>
)"R"(
<customwidgets>
<customwidget>
<class>{CLASSNAME}</class>
<header>{FILENAME}.h</header>
<extends>{PARENTCLASSNAME}</extends>
</customwidget>
</customwidgets>
")
R"(</ui>)");
}
QString {CLASSNAME}Plugin::includeFile() const
{return QLatin1String("");
}
二、敲代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFileSystemModel>
#include <QTreeView>
QT_BEGIN_NAMESPACE
namespace Ui {class MainWindow;}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
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 <QDebug>
#include <QMessageBox>
#include <QFileDialog>
#include <QSettings>
#include <QDir>
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);
}
最初的成型: