乐趣区

关于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 不能间接执行定义的脚本,间接做五次替换,所以萌发了本人写个程序呗,做文件替换。

一、定义 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);
}

最初的成型:

退出移动版