Qt从入门到入土(八) -打包Qt程序

打印 上一主题 下一主题

主题 1003|帖子 1003|积分 3009

前言

当你写完一个风趣的Qt程序时,想发给朋友或者家人,但是他们的电脑又没有安装Qt,那么怎样直接在他们电脑上运行又不需要安装Qt呢?本篇文章会告诉你答案,本文详细的介绍了界面设计和功能实现。读完本文你不但可以学会打包部署Qt程序而且还可以制作一个Qt打包程序的软件。
前期预备

创建Qt项目,CMakeLists.txt文件配置Qt。
  1. #使用此项目版本不能低于3.20
  2. cmake_minimum_required(VERSION 3.20)
  3. #项目名称 版本 语言   
  4. project(WindePloyGui VERSION 0.1 LANGUAGES CXX)   
  5. #查找QT包
  6. find_package(Qt6 REQUIRED COMPONENTS Widgets)
  7.    
  8. #设置变量
  9. set(PROJECT_SOURCES
  10.    main.cpp
  11.    )   
  12. #添加可执行文件
  13. add_executable(WindePloyGui ${PROJECT_SOURCES})   
  14. #添加Qt链接库
  15. target_link_libraries(WindePloyGui Qt6::Widgets)  
复制代码
创建main.cpp,构建项目查看是否配置错误。
  1. #include <QApplication>
  2. #include <QWidget>
  3. int main(int argc, char* argv[])
  4. {
  5.     QApplication app(argc, argv);
  6.     QWidget window;
  7.     window.show();
  8.     return app.exec();
  9. }
复制代码
创建WindePloyGui.h
  1. #ifndef PACKAGEQTGUI_H
  2. #define PACKAGEQTGUI_H
  3. #include <QWidget>
  4. QT_BEGIN_NAMESPACE
  5. namespace Ui {
  6. class PackageQtGui;
  7. }
  8. QT_END_NAMESPACE
  9. class PackageQtGui : public QWidget
  10. {
  11.     Q_OBJECT
  12. public:
  13.     PackageQtGui(QWidget *parent = nullptr);
  14.     ~PackageQtGui();
  15. public:
  16.     void initUI();
  17. private:
  18.     Ui::PackageQtGui *ui;
  19. };
  20. #endif // PACKAGEQTGUI_H
复制代码
创建WindePloyGui.cpp
  1. #include "packageqtgui.h"
  2. #include "./ui_packageqtgui.h"
  3. PackageQtGui::PackageQtGui(QWidget *parent)
  4.     : QWidget(parent)
  5.     , ui(new Ui::PackageQtGui)
  6. {
  7.     ui->setupUi(this);
  8. }
  9. PackageQtGui::~PackageQtGui()
  10. {
  11.     delete ui;
  12. }
复制代码
界面初始化

本次界面使用到了QFormLayout,QComboBox等控件。
QFormLayoutFormLayout 是 Qt 提供的一种结构工具,专门用来生成类似表单的界面。它答应您将控件以“标签-控件”对的情势分列,通常用于输入表单、设置界面等场景。
QComboBox:创建下拉列表,用户可以从列表中选择一个选项。
       this->m_qtVersionListCmb= new QComboBox;
    this->m_qtKitsListCmb = new QComboBox;
      //给QComboBox添加项
      //this->m_qtVersionListCmb->addItems({"one","two","three"});
      auto flayout = new QFormLayout;
    flayout->addRow("选择Qt版本",this->m_qtVersionListCmb);
    flayout->addRow("选择Qt编译套件",this->m_qtKitsListCmb);
  当前初始化UI代码
  1. void PackageQtGui::initUI()
  2. {
  3.     this->m_qtVersionListCmb= new QComboBox;
  4.     this->m_qtKitsListCmb = new QComboBox;
  5.     auto selectExeBtn = new QPushButton("选择exe文件");
  6.     auto createBtn = new QPushButton("生成");
  7.     auto testBtn = new QPushButton("测试");
  8.     auto aboutBtn = new QPushButton("关于");
  9.     auto flayout = new QFormLayout;
  10.     flayout->addRow("选择Qt版本",this->m_qtVersionListCmb);
  11.     flayout->addRow("选择Qt编译套件",this->m_qtKitsListCmb);
  12.     auto hlayout = new QHBoxLayout;
  13.     hlayout->addWidget(testBtn);
  14.     hlayout->addWidget(aboutBtn);
  15.     auto vlayout = new QVBoxLayout(this);
  16.     vlayout->addLayout(flayout);
  17.     vlayout->addWidget(selectExeBtn);
  18.     vlayout->addWidget(createBtn);
  19.     vlayout->addLayout(hlayout);
  20. }
复制代码
当前效果

调整控件大小
使用setSizePolicy函数来调整控件大小。
    selectExeBtn->setSizePolicy(QSizePolicy:olicy::Expanding,QSizePolicy:olicy::Expanding);
  美化QComboBox中的drop-down
有时直接给子控件设置图片大概会因为QComboBox::drop-down 的表现区域大概太小,导致图片无法完全表现。可以通过设置 width 和 height 来调整表现区域。
   QComboBox::drop-down{
image:url(':/Recourses/Icons/drop-down.png');
subcontrol-origin: padding;
subcontrol-position: right center;
width: 20px; /* 调整箭头宽度 */
height: 20px; /* 调整箭头高度 */
}
  QComboBox::drop-down:hover{
image:url(':/Recourses/Icons/drop-down-hover.png');
}
  QComboBox::drop-down:checked{
image:url(':/Recourses/Icons/drop-down-on.png');
}
  QComboBox::drop-down:checked:hover{
image:url(':/Recourses/Icons/drop-down-on-hover.png');
}
  初始化UI代码
  1. void PackageQtGui::initUI()
  2. {
  3.     this->setWindowTitle("QT程序打包工具");
  4.     this->setFixedSize(640,510);
  5.     this->m_qtVersionListCmb= new QComboBox;
  6.     this->m_qtKitsListCmb = new QComboBox;
  7.     auto selectExeBtn = new QPushButton("选择exe文件");
  8.     auto createBtn = new QPushButton("生成");
  9.     auto testBtn = new QPushButton("测试");
  10.     auto aboutBtn = new QPushButton("关于");
  11.     selectExeBtn->setObjectName("selectExeBtn");
  12.     selectExeBtn->setSizePolicy(QSizePolicy::Policy::Expanding,QSizePolicy::Policy::Expanding);
  13.     auto flayout = new QFormLayout;
  14.     flayout->addRow("选择 Qt 版本",this->m_qtVersionListCmb);
  15.     flayout->addRow("选择编译套件",this->m_qtKitsListCmb);
  16.     auto hlayout = new QHBoxLayout;
  17.     hlayout->addWidget(testBtn);
  18.     hlayout->addWidget(aboutBtn);
  19.     auto vlayout = new QVBoxLayout(this);
  20.     vlayout->addLayout(flayout);
  21.     vlayout->addWidget(selectExeBtn);
  22.     vlayout->addWidget(createBtn);
  23.     vlayout->addLayout(hlayout);
  24. }
复制代码
css界面美化代码
  1. /*通用的样式*/
  2. *{
  3. background-color:white;
  4. font:normal 15px "楷体";
  5. }
  6. QPushButton,QComboBox{
  7. border:1px solid rgb(213,213,213);
  8. border-radius:8px;
  9. }
  10. QComboBox:hover{
  11. border-color:rgb(100,100,100);
  12. }
  13. QComboBox::drop-down{
  14. image:url(':/Recourses/Icons/drop-down.png');
  15. subcontrol-origin: padding;
  16. subcontrol-position: right center;
  17. width: 20px; /* 调整箭头宽度 */
  18. height: 20px; /* 调整箭头高度 */
  19. }
  20. QComboBox::drop-down:hover{
  21. image:url(':/Recourses/Icons/drop-down-hover.png');
  22. }
  23. QComboBox::drop-down:checked{
  24. image:url(':/Recourses/Icons/drop-down-on.png');
  25. }
  26. QComboBox::drop-down:checked:hover{
  27. image:url(':/Recourses/Icons/drop-down-on-hover.png');
  28. }
  29. QPushButton:hover{
  30. background:rgb(220,220,220);
  31. }
  32. /*设置特定样式*/
  33. QPushButton#selectExeBtn{
  34. border-width:2px;
  35. font:italic 20px "楷体";
  36. color:rgb(174,174,174);
  37. }
复制代码
功能实现

首先,找到Qt版本编译的套件

构建QtEnvSearch类用于获取体系的应用程序可写路径,因为不同的电脑路径不同但可以通过QStandardPaths来获取到当前电脑的路径
   QString path = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
  查找Qt版本的文件夹,获取一个目录中所有以 "Qt" 开头的子目录的信息列表
   QFileInfoList info_list = dir.entryInfoList({"Qt*"},QDir:irs);
  筛选出不为空的文件夹
   for(auto& info:info_list)
    {
        //筛选出体系路径中名称带有Qt的文件夹
        // 查抄文件夹是否为空
        QDir subDir(info.absoluteFilePath());
        if (!subDir.isEmpty()) {
            qDebug() << "Non-empty Qt version folder:" << info.absoluteFilePath();
            infoList.append(info.absoluteFilePath());
        }
    }
  再次筛选Qt目录中Qt版本号文件夹,并清除空文件夹
   QStringList resultList;
    for(auto &info:infoList)
    {
        //QDir:irs 表示只获取子目录。
        //QDir::NoDotAndDotDot 是一个常用的过滤器,用于清除 . 和 .. 这两个特殊目录。
        QFileInfoList sub_info_list = QDir(info).entryInfoList(QDir:irs | QDir::NoDotAndDotDot);
        for(auto& i:sub_info_list)
        {
            QDir subDir(i.absoluteFilePath());
            if(!subDir.isEmpty())
            {
                resultList.append(i.absoluteFilePath());
            }
        }
    }
  获取到所选版本目录中的Qt编译套件
   QStringList QtEnvSearch::m_qtKitsLists()
{
    if(m_currentVersion.isEmpty())
    {
        m_currentVersion = m_versionMap.firstKey();
    }
      auto path = m_versionMap.value(m_currentVersion);
    QDir dir(path);
    if(!dir.exists())
    {
        qWarning()<<path<<"not exists!";
        return QStringList{};
    }
      return dir.entryList(QDir:irs|QDir::NoDotAndDotDot);
}
  把获取到的版本号和套件列表添加到QComboBox的item中
   this->m_qtVersionListCmb->addItems({m_envSearch.m_qtVersionLists()});
this->m_qtKitsListCmb->addItems({m_envSearch.m_qtKitsLists()});
  当选择的Qt版本改变时需要更新所对应的选择编译套件
   connect(this->m_qtVersionListCmb,&QComboBox::currentTextChanged,[=](const QString& ver)
    {
        this->m_envSearch.setCurrentVersion(ver);
        this->m_qtKitsListCmb->clear();
        this->m_qtKitsListCmb->addItems(this->m_envSearch.m_qtKitsLists());
    });
  当选择编译套件发生改变的时候需要更新对应的Qt版本
   connect(this->m_qtKitsListCmb,&QComboBox::currentTextChanged,&this->m_envSearch,&QtEnvSearch::setCurrentKits);
  当前效果

接下来要实现selectExeBtn,点击该按钮即可打开文件(这里使用QFileDialog),并将按钮文本修改成获取到的文件名。
   connect(selectExeBtn,&QPushButton::clicked,[=](){
        auto filename = QFileDialog::getOpenFileName(this,"选择exe文件",QStandardPaths::writableLocation(QStandardPaths:esktopLocation)
                 ,"exe(*.exe);;all(*.*)");
        if(filename.isEmpty())
            return;
        selectExeBtn->setText(QFileInfo(filename).fileName());
        qDebug()<<filename;
      });
  

之后,点击生成按钮完成部署。怎样完成部署呢?首先进入到套件目录,根据快捷方式找到指定的bin目录。
   bool QtEnvSearch::generate()
{
    //进入套件目录
    QDir dir(m_versionMap.value(m_currentVersion));
    if(!dir.cd(m_currentKits))
    {
        qWarning()<<"cd"<<m_currentKits<<"failed~";
        return false;
    }
      //找到一个快捷方式,并进入指向的目标
    auto all_entry = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries);
    if(all_entry.isEmpty())
    {
        qWarning()<<"生成失败,套件无效";
        return false;
    }
    //qDebug()<<all_entry;
      //获取qt的bin目录
    auto qtBin = QFileInfo(all_entry.first().symLinkTarget()).path();
    //qDebug()<<qtBin;
    return true;
}
  使用system函数举行部署
   // 传入qtbin目录中的windeployqt.exe和待部署的exe文件的路径
  system(QString(qtBin + "/windeployqt.exe " + m_exeFile).toStdString().data());
  使用QProcess::startDetached举行部署
   bool success = QProcess::startDetached(QString(qtBin + "/windeployqt.exe"),{m_exeFile});
  点击测试按钮打开程序
       // 同样使用QProcess::startDetached来打开EXE程序
    return QProcess::startDetached(m_exeFile);
  至此,打包Qt程序的软件就已经完成了,固然另有一个关于按钮你可以写上你的信息表明你是创作者或是对这个软件的介绍,这里就不一一赘述了。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

卖不甜枣

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表