五彩斑斓的黑:Fun with PyQt5+CMake+C++

news2024/11/15 8:40:33

Fun Pain Fun with PyQt5+CMake+C++

本文相关代码GitCode地址

这个项目与PyQt5只有半毛钱关系。事情是这样发生的。当时,我在一个新电脑上干活,装了miniconda,装了PyQt5,干着干着突然要整一个Qt5。我想也挺好,据说C++ 17里面lambda写得飞起,好久没有体验。

看了下这台windows笔记本的软件:

  • CMake 3.25.2
  • Windows SDK 10.0

没装QT,想到网上下,没网络。仔细想想,我miniconda的PyQt5不是好着的吗?

  • miniconda with PyQt5

好吧,删繁就简三秋树,什么什么二月花,全语言战神不惧断网……乙方就是我二大爷,五彩斑斓的黑那是小Case!

Objective

我们先设置一个小目标,报表:按钮被点击的次数,采用LCDNumber来显示;数据:通过按钮的clicked动作统计得到。整体效果如图:

在这里插入图片描述

我们先设计一个QMainWindow的子类,CountingMainWindow,具体UI我们通过designer来设计。按钮上的图标、程序的图标,我们都定义到资源文件中。这样一个程序就具备全部的特性。

CMakeLists.txt

首先,从CMakeLists.txt开始。

  • 文件开始规定cmake的版本;
  • 接下来工程名称;
  • 接下来是编译器支持的C++版本;
  • 接下来五个开关量,分别的意思是自动化moc文件、自动化资源文件、自动化ui文件、去掉终端黑框整windows程序、包含当前目录(这是考虑uic自动生成的头文件);
  • 接下来是最重要的部分:CMAKE_PREFIX_PATH,设置为miniconda3的安装目录下的Library文件,仔细看看,这里面的bin对应了QT的dll文件和各工具(包括designer,uic,rcc这些),cmake文件也在这个目录下的lib/cmake中;
  • 全新的Qt5连接方式,find_package全能工具;
  • 可执行文件的包含内容:add_executable
  • target_link_libraries:链接库文件
  • 后面if…endif() 拷贝dll文件,插件的dll文件
  • 最后的foreach……endforeach(),拷贝额外的dll文件
cmake_minimum_required(VERSION 3.25)
project(qthello)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_WIN32_EXECUTABLE ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)


set(CMAKE_PREFIX_PATH "C:\\ProgramData\\miniconda3\\Library")

find_package(Qt5 COMPONENTS
        Core
        Gui
        Widgets
        REQUIRED)

add_executable(${PROJECT_NAME} main.cpp countingmainwindow.cpp countingmainwindow.h countingmainwindow.ui resources.qrc)

target_link_libraries(${PROJECT_NAME}
        Qt5::Core
        Qt5::Gui
        Qt5::Widgets
        )

if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
    set(DEBUG_SUFFIX)
    if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
        set(DEBUG_SUFFIX "d")
    endif ()
    set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")

    if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
        set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
        if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
            set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
        endif ()
    endif ()
    if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E make_directory
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy
                "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
    endif ()

    foreach (QT_LIB Core Gui Widgets)
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy
                "${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}_conda.dll"
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
    endforeach (QT_LIB)
endif ()

foreach (LIB_DLL icuin58.dll zlib.dll icuuc58.dll zstd.dll icudt58.dll libpng16.dll)
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy
            "${QT_INSTALL_PATH}/bin/${LIB_DLL}"
            "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
endforeach (LIB_DLL)

整个这里面,比较关键的部分就是这里的"${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}_conda.dll",因为miniconda的dll文件名称增加了_conda,库文件依靠提供的CMake配置文件自动处理过,但是动态链接库需要自己确定。

    foreach (QT_LIB Core Gui Widgets)
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E copy
                "${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}_conda.dll"
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
    endforeach (QT_LIB)

Actual application

C++ source

首先是main.cpp

#include <QApplication>
#include <QPushButton>
#include <QStyleFactory>
#include <countingmainwindow.h>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    a.setStyle(QStyleFactory::create("Fusion"));

    my_ui::CountingMainWindow window;
    window.show();
    return QApplication::exec();
}

这里,所有的工作都在my_ui::CountingMainWindow这个类中完成。这个类的接口定义在countingmainwindow.h中。

//
// Created by User on 2023/5/7.
//

#ifndef QTHELLO_COUNTINGMAINWINDOW_H
#define QTHELLO_COUNTINGMAINWINDOW_H

#include <QMainWindow>

namespace my_ui {
    QT_BEGIN_NAMESPACE
    namespace Ui { class CountingMainWindow; }
    QT_END_NAMESPACE

    class CountingMainWindow : public QMainWindow {
    Q_OBJECT

    public:
        explicit CountingMainWindow(QWidget *parent = nullptr);

        ~CountingMainWindow() override;

    private:
        Ui::CountingMainWindow *ui;
    };
} // my_ui

#endif //QTHELLO_COUNTINGMAINWINDOW_H

这个类的接口中最重要的就是,那个私有变量Ui::CountingMainWindow *ui,这个类将由ui文件生成。

对应的cpp文件中,在构造函数中new Ui::CountingMainWindow来初始化私有变量,然后调用ui->setupUi(this);设置界面元素、布局之类。接下来就是引用资源,设置图标;链接点击事件和LCDNumber溢出归零。

//
// Created by User on 2023/5/7.
//

// You may need to build the project (run Qt uic code generator) to get "ui_CountingMainWindow.h" resolved

#include "countingmainwindow.h"
#include "ui_CountingMainWindow.h"

namespace my_ui {
    CountingMainWindow::CountingMainWindow(QWidget *parent) :
            QMainWindow(parent), ui(new Ui::CountingMainWindow) {
        ui->setupUi(this);

        setWindowIcon(QIcon(":imgs/icon.png"));

        ui->pushButton->setIcon(QIcon(":imgs/click.png"));
        ui->pushButton->setIconSize(QSize(36, 36));

        connect(ui->pushButton, &QPushButton::clicked, [=](bool checked){
           ui->lcdNumber->display(ui->lcdNumber->intValue()+1);
        });
        connect(ui->lcdNumber, &QLCDNumber::overflow, [=](){
           ui->lcdNumber->display(0);
        });
    }

    CountingMainWindow::~CountingMainWindow() {
        delete ui;
    }
} // my_ui

Resource

资源文件内容简单。

<RCC>
    <qresource>
        <file>imgs/icon.png</file>
        <file>imgs/click.png</file>
    </qresource>
</RCC>

ui definition

UI文件由Designer生成。

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>my_ui::CountingMainWindow</class>
 <widget class="QMainWindow" name="my_ui::CountingMainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>167</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>CountingMainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       <widget class="QPushButton" name="pushButton">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
          <horstretch>0</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="font">
         <font>
          <pointsize>24</pointsize>
         </font>
        </property>
        <property name="text">
         <string>Clicked:</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QLCDNumber" name="lcdNumber">
        <property name="font">
         <font>
          <pointsize>24</pointsize>
         </font>
        </property>
       </widget>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>400</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

Building process

所有的文件都已经介绍完成,代码在gitcode可以克隆。

git clone https://gitcode.net/withstand/qthello.git

确保cmake命令可以访问的情况下,在qthello目录下运行如下指令。

mkdir build
cd build
cmake ..

目录下就会生成qthello.sln文件等其他一堆工程文件。运行Visual Studio 20xx下面的工具链环境设置快捷方式。
在这里插入图片描述

在终端里切换到刚才的build目录,运行:

msbuild -property:Configuration=Release qthello.sln

就可以在Release文件中得到可执行文件。

结论

  1. miniconda3安装PyQt5之后带了全套的Qt环境,可以直接拿来开发Qt5程序;
  2. 没有debug版本的库和动态链接文件;
  3. "C:\ProgramData\miniconda3\Library\bin"没加到path的话,需要多拷贝好几个动态链接库文件,就是icuin58.dll zlib.dll icuuc58.dll zstd.dll icudt58.dll libpng16.dll这一堆,如果运行不正确,还有可能要增加其他的dll文件;
  4. cmake真香。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/498778.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Node.js和在浏览器之中的不同

在Node.js中编写JavaScript应用程序与在浏览器中为Web编程有何不同 1、在浏览器中&#xff0c;大多数时候您所做的是与DOM或其他Web平台API&#xff08;如Cookie&#xff09;进行交互。当然&#xff0c;Node.js中并不存在这些。您没有浏览器提供的文档、窗口和所有其他对象。 …

让测试更轻松:学习Selenium进行Web应用程序自动化测试

B站首推&#xff01;2023最详细自动化测试合集&#xff0c;小白皆可掌握&#xff0c;让测试变得简单、快捷、可靠https://www.bilibili.com/video/BV1ua4y1V7Db 目录 摘要&#xff1a; 什么是Selenium 安装Selenium 编写自动化测试脚本 第一步&#xff1a;导入Selenium库 …

前端006_头部快捷导航_标签导航栏

效果如下,红色方框里面有快捷导航 1、添加标签栏导航组件 拷贝vue-element-admin 的 @/layout/components/TagsView 目录及文件到 mengxuegu-blog-admin 对应目录下 [root@pgdb vue-element-admin]# cp -r src/layout/components/TagsView ../db-manager-system/src/layou…

UE蓝图基础学习笔记(未完待续2023/05/06)

文章目录 一、项目创建1&#xff09;准备流程&#xff08;选择模板、开发语言、平台、质量等&#xff09;2&#xff09;界面介绍 二、Actor三、操作关卡对象&#xff08;旋转、移动、缩放和坐标轴&#xff09;四、常用快捷键五、运行游戏六、蓝图介绍七、蓝图节点八、操作事件图…

Vben Admin 自学记录 —— Drawer组件的基本使用及练习(持续更新中...)

Drawer 抽屉组件 对 antv 的 drawer 组件进行封装&#xff0c;扩展拖拽&#xff0c;全屏&#xff0c;自适应高度等功能。 Drawer相关使用及概念 练习 —— 在之前table基础上&#xff0c;添加查看功能&#xff0c;点击查看按钮&#xff0c;弹出抽屉显示单条表格数据&#xf…

基于80C51单片机的电子钟设计与仿真

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/87761539?spm1001.2014.3001.5503 源码获取 主要内容&#xff1a; 电子钟是一种利用数字电路来显示秒、分、时的计时装置&#xff0c;与传统的机械钟相比&#xf…

SpringBatch之实际操作

文章目录 1 SpringBatch操作1.1 SpringBatch介绍1.2 依赖配置相关1.2.1 pom.xml1.2.2 mysql 依赖库表1.2.3 启动配置1.2.4 数据库配置 1.3 示例Demo1.3.1 简单执行1.3.2 报错 1.4 流程控制1.4.1 多步骤任务1.4.2 Flow用法1.4.3 并发执行1.4.4 任务决策1.4.5 任务嵌套 1.5 数据操…

Illustrator如何使用图层与蒙版之实例演示?

文章目录 0.引言1.绘制可爱冰淇淋图标2.霓虹渐变立体文字海报3.炫彩花纹背景 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对Illustrator进行了学习&#xff0c;本文通过《Illustrator CC2018基础与实战》及其配套素材结合网上相关资料进行学习笔记总结&#xff0c;…

电影推荐算法2

模型创建 title _ count, title _ set, genres2int, features, targets _ values, ratings, users, movies, data, movies _ orig, users _ orig pickle.load (open (‘preprocess.p’, mode ‘rb’)) 加载数据后定义神经网络的模型结构&#xff1a; 1&#xff09;定义参数…

u盘文件名乱码的恢复方法

文件名全部变乱码了怎么恢复&#xff1f;U盘数据恢复方法 电脑里的目录文件名乱码了&#xff0c;这是什么状况呢&#xff1f;好端端的电脑突然就成这个样子了&#xff0c;真是令人摸不着头脑&#xff0c;对于这样的状况&#xff0c;多半是文件类型引起的&#xff0c;那么接下来…

Python:Python进阶:Python整数与 Numpy的数据溢出

numpy数据溢出 1.python 3 的整数上限和 python 2 的整数上限1.1 python 2的整数范围1.2 python 3 的整数范围 2. numpy数值表示2.1 那么numpy支持的数据类型和 python有什么不同了2.2 如何解决整数溢出问题 总结 实验一&#xff1a;使用 numpy库来表示正数 import numpy as n…

redis(4)

1)使用StringTemplateRedis操作String类型 1)判断redis中是否拥有key所对应的值&#xff0c;如果有返回true&#xff0c;没有那么直接返回false redisTemplate.hasKey(key); 2)如果redis中有key那么直接取出key所对应的值 redisTemplate.opsForValue().get(key) 3)删除单个key值…

2023.05.07 学习周报

文章目录 摘要文献阅读1.题目2.现存问题和解决方法3.本文贡献及相关工作4.GRU5.模型5.1 SESSION-PARALLEL MINI-BATCHES5.2 SAMPLING ON THE OUTPUT5.3 RANKING LOSS 6.实验6.1 准备6.2 基线6.3 优化6.4 结果 7.结论 数学建模1.综合评价模型的一般步骤2.层次分析法3.主成分分析…

【Java】中的多线程线程锁

多线程 文章目录 多线程线程的创建和启动sleep()stop() 线程的休眠和中断线程的优先级线程的礼让和加入yield()stop() 线程锁和线程同步synchronized 关键字 死锁概念 wait & notify methodThreadLocal的使用定时器 Timer守护线程再谈集合类parallelStreamforEachOrdered()…

怎么将三张图片合成一张图片?

怎么将三张图片合成一张图片&#xff1f;遇到这个问题&#xff0c;我们其实有很多方法来处理。我们首当其冲想到的是其中最常见的&#xff0c;可以使用我们手机的APP来处理&#xff0c;比如某秀秀等。但是此方法比较适合于尺寸比较小的图片进行合并&#xff0c;如果图片比较大的…

Dockerfile创建镜像文件

Dockerfile Docker镜像原理 Linux文件系统有bootfs和rootfs两部分组成 Docker镜像由特殊文件系统叠加 最底端bootfs,使用宿主机bootfs 第二次时rootfs,被称为基础镜像 向上可以叠加其他镜像文件 同一文件系统能将多层整合成一层&#xff0c;隐藏了多层存在 镜像可以放置…

智能优化算法:鱼鹰优化算法-附代码

智能优化算法&#xff1a;鱼鹰优化算法 文章目录 智能优化算法&#xff1a;鱼鹰优化算法1. 鱼鹰优化算法1.1 初始化1.2 阶段一&#xff1a;定位和捕鱼&#xff08;探索阶段&#xff09;1.3 阶段二&#xff1a;把鱼带到合适的位置&#xff08;开发阶段&#xff09; 2.实验结果3.…

RISC-V U-Boot 启动 Linux 内核的参数

RISC-V U-Boot 启动 Linux 内核的参数 U-Boot (the Universal Boot Loader简写U-Boot) flyfish U-Boot 启动Linux内核的参数举例说明 RISC-V U-Boot 启动 Linux 内核的参数方式一 文本操作earlyprintksunxi-uart,0x02500000clk_ignore_unusedconsolettyS0,115200init/sbin/i…

go-resiliency源码解析之-batcher

go-resiliency源码解析之-batcher 源代码地址 &#xff1a; https://github.com/eapache/go-resiliency/blob/master/batcher/batcher.go 1.batcher定义 创建一个batch对象需要2个参数: Timeout:超时,这是一个batch对象收集输入参数的时间。 work函数变量&#xff1a;在ti…

使用Jumpserver+Frp集中管理远程内网服务器

我们设想这样一种情况&#xff0c;我们是一家小公司&#xff0c;在全国有几个小分支办公机构&#xff0c;每个机构有一台服务器&#xff0c;由于公司财务紧张&#xff0c;买不起专线&#xff0c;用的也是普通家用宽带&#xff0c;SD-WAN设备说实话也挺贵的&#xff0c;那么我们…