Qt应用开发--国产工业开发板全志T113-i的部署教程

Qt在工业上的使用场景包括工业自动化、嵌入式系统、汽车行业、航空航天、医疗设备、制造业和物联网应用。Qt被用来开发工业设备的用户界面、控制系统、嵌入式应用和其他工业应用,因其跨平台性和丰富的功能而备受青睐。

Qt能够为工业领域带来什么好处:
- Qt提供了强大的图形引擎,使开发人员能够创建具有吸引力和高性能的用户界面
- Qt允许开发人员根据具体需求定制用户界面和功能。这对于满足不同行业和项目的独特需求至关重要,使工业应用能够实现个性化的解决方案
- Qt提供了丰富的库和工具,涵盖了各种应用程序开发需求,包括图形、网络通信、多媒体处理、数据存储等。这简化了工业应用程序的开发流程
- Qt可以轻松与各种硬件设备和通信协议集成,这对于工业自动化和控制系统来说非常重要,因为它们需要与各种传感器、执行器和其他工业设备进行通信

创龙科技基于全志双核Cortex-A7@1.2GHz处理器T113-i,精心设计的全国产工业开发板,它提供了Qt的运行环境,可以让我们快速的部署工业领域的用户交互界面,控制系统等。

接下来我们来聊聊如何在创龙科技T113-i工业开发板上部署Qt应用。

开发板Qt运行环境

开发板SDK准备
  • 创龙科技的资料中提供了开发板的SDK-T113-i_v1.0.tar.gz,需要解压ubuntu中解压出来:
rice@rice:~$ mkdir t113             //创建t113工作目录,然后将压缩包拷贝到此目录
rice@rice:~$ cd t113
....

rice@rice:~/t113$ tar -zxvf SDK-T113-i_v1.0.tar.gz
rice@rice:~/t113$ cd T113-i_v1.0/
rice@rice:~/t113/T113-i_v1.0$ ls
brandy  buildroot  device  install_tools.sh  out       rtos-dsp  tools
build   build.sh   kernel  platform          test
  • 安装依赖软件,创龙科技提供了安装脚本:install_tools.sh,我们执行该脚本即可完成依赖工具的安装:
rice@rice:~/t113/T113-i_v1.0$ ./install_tools.sh
[sudo] password for rice: 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
texinfo is already the newest version (6.5.0.dfsg.1-2).
0 upgraded, 0 newly installed, 0 to remove and 121 not upgraded.
Reading package lists... Done
Building dependency tree       
Reading state information... Done
pkg-config is already the newest version (0.29.1-0ubuntu2).
0 upgraded, 0 newly installed, 0 to remove and 121 not upgraded.
Reading package lists... Done

......

  • 解压Buildroot dl–dl.tar.gz,其为 Buildroot dl 目录压缩包,用于存放从官网下载的开源软件包:
rice@rice:~/t113$ tar -xvf dl.tar.gz -C ~/t113/buildroot/buildroot-201902/
构建Qt固件
  • 在编译固件前,先清理一下SDK的编译和配置生成文件:
rice@rice:~/t113/T113-i_v1.0$ ./build.sh distclean
  • 配置linux内核,处理器型号,显示方式,编译器等信息
rice@rice:~/t113/T113-i_v1.0$ ./build.sh config
Welcome to mkscript setup progress
All available platform:
 0. linux
Choice [linux]: 0
All available linux_dev:
 0. bsp
 1. dragonboard
 2. longan
 3. tinyos
Choice [longan]: 2
All available kern_ver:
 0. linux-5.4
Choice [linux-5.4]: 0
All available ic:
 0. t113
 1. t113_i
Choice [t113_i]: 1
All available board:
 0. evb1
 1. evb1_auto
 2. evb1_auto_nand
 3. evb1_auto_nor
 4. tlt113-evm-emmc
 5. tlt113-evm-nand
 6. tlt113-minievm-emmc
 7. tlt113-minievm-nand
Choice [tlt113-evm-nand]: 5
All available output_configs:
 0. hdmi
 1. lvds-lcd
 2. mipi-lcd
 3. tft-lcd
 4. cvbs
Choice [hdmi]: 0
All available flash:
 0. default
 1. nor
Choice [default]: 0
All available build_root:
 0. buildroot-201902
 1. ubuntu
Choice [buildroot-201902]: 0
All available gnueabi:
 0. gnueabi
 1. gnueabihf
Choice [gnueabi]: 0

  • 设置编译的环境变量:
rice@rice:~/t113/T113-i_v1.0$ source ./build/envsetup.sh
  • 我们采用一键编译 SPL、U-Boot、Linux 内核和 buildroot文件系统。
rice@rice:~/t113/T113-i_v1.0$ ./build.sh
ACTION List: mklichee;========
Execute command: mklichee 
INFO: ----------------------------------------
INFO: build lichee ...
INFO: chip: sun8iw20p1
INFO: platform: linux
INFO: kernel: linux-5.4
INFO: board: tlt113-evm-nand
INFO: output: /home/rice/t113/T113-i_v1.0/out/t113_i/tlt113-evm-nand/longan
INFO: ----------------------------------------
INFO: build buildroot ...
Prepare br toolchain gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabi.tar.xz...
make: Entering directory '/home/rice/t113/T113-i_v1.0/buildroot/buildroot-201902'

...

  • 编译Qt库,使其开发板固件支持Qt应用运行环境:
rice@rice:~/t113/T113-i_v1.0$ ./build.sh qt
ACTION List: mkqt;========
Execute command: mkqt 
INFO: build Qt ...
INFO: build arm-linux-gnueabi version's Qt
/home/rice/t113/T113-i_v1.0/platform/framework/qt/qt-everywhere-src-5.12.5
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix

.....

  • 打包系统镜像文件,执行之后,可以看到生成的固件文件,它默认生成两个版本的固件,分别是:nand固件和SD卡固件,我们是采用SD卡启动,所以使用SD卡固件。
rice@rice:~/t113/T113-i_v1.0$ ./build.sh pack
ACTION List: mkpack ;========
Execute command: mkpack  
INFO: packing firmware ...
INFO: Use BIN_PATH: /home/rice/t113/T113-i_v1.0/device/config/chips/t113_i/bin
copying tools file
copying configs file
copying product configs file
/home/rice/t113/T113-i_v1.0/out/pack_out/aultls32.fex
/home/rice/t113/T113-i_v1.0/out/pack_out/aultools.fex
/home/rice/t113/T113-i_v1.0/out/pack_out/boot_package.cfg
/home/rice/t113/T113-i_v1.0/out/pack_out/boot_package.fex

...... 

dsp0.fex Len: 0x3fc78
Vdsp0.fex Len: 0x4
BuildImg 0
Dragon execute image.cfg SUCCESS !
----------image is at----------

size:613M  /home/rice/t113/T113-i_v1.0/out/t113_i_linux_tlt113-evm-nand-sdboot_uart0.img

pack finish

运行环境验证

下载运行实例
  • 将编译打包后的固件(t113_i_linux_tlt113-evm-nand-sdboot_uart0.img)放到windows上,通过工具PhoenixCard.exe烧录到SD卡上。将SD卡插到读卡器上,然后插进电脑:

  • 创龙科技提供了qt的demo,我们将led_control的实例拷贝到板子上:
rice@rice:~/t113/qt-demos/led_control/bin$ scp led_control root@ip:~/
创龙T113-i上运行实例
  • 关闭默认的Qt运行程序,设置qt的环境变量
root@T113-Tronlong:~# killall Launcher
root@T113-Tronlong:~# source /etc/qtenv.sh 
add /dev/input/event1 to Qt Application.
find qt5 installed done
  • 运行实例验证Qt功能,运行效果如图:
root@T113-Tronlong:~# ./led_control

Qt开发环境

开发环境下载
  • Qt开发环境下载,作者是使用Qt 5.12.0,下载链接:https://download.qt.io/archive/qt/5.12/5.12.0/,Ubuntu需要下载:qt-opensource-linux-x64-5.12.0.run

开发环境交叉编译环境配置
  • 配置Debuggers
    • 点击菜单栏"Tools -> Options"
    • 击"Kits -> Debuggers -> Add -> Browse…"
    • 选择目标平台的GDB,路径:/home/rice/t113/T113-i_v1.0/out/t113_i/tlt113-evm-nand/longan/buildroot/host/usr/bin/arm-linux-gnueabi-gdb

  • 配置交叉工具链
    • 点击菜单栏"Tools -> Options"
    • 击"Kits -> Compilers -> Add -> GCC -> C++ -> Browse…"
    • 选择目标平台的交叉工具链,路径:/home/rice/t113/T113-i_v1.0/out/t113_i/tlt113-evm-nand/longan/buildroot/host/usr/bin/arm-linux-gnueabi-g++

  • 配置Qt Versions
    • 点击菜单栏"Tools -> Options"
    • 击"Kits -> Qt Versions -> Add -> GCC -> C++ -> Browse…"
    • 选择目标平台的Qt Versions,路径:/home/rice/t113/T113-i_v1.0/platform/framework/qt/qt-everywhere-src-5.12.5/Qt_5.12.5/bin/qmake

  • 配置Kits
    • 点击菜单栏"Tools -> Options"
    • 击"Kits -> Kits"
    • 将 Name 修改为"T113",Device type 选择"Generic Linux Device",Compiler 的 C++选择"T113-GCC",Debugger 选择"T113-Debugger",Qt version 选择"T113-qt5",点击 Apply,然后点击 OK 完成配置

开发Qt应用

  • 作者开发了一个快速验证硬件功能的,主要功能包含:
  1. 板载LED灯控制,代码实现:
static QString ledPath = "/sys/class/leds/user-led0";

void rice::ledInit()
{
    setLedStatus(0);

    ui->ledPushButton->setText("LED OFF");
    ui->ledPushButton->setStyleSheet("border-width:1px;"
                                     "border-style:solid; "
                                     "border-color:white;"
                                     "background-color:rgba(88, 88, 88, 200)");
}

void rice::ledDeinit()
{

}

bool rice::setLedStatus(int status)
{
    QString cmd = "echo " + QString::number(status) + " > " + ledPath + "/brightness";
    if (system(cmd.toStdString().c_str()) == -1) {
        printf("set led status failed!\n");
        return false;
    }
    return true;
}

int rice::getLedStatus(void)
{
    QString cmd = "cat " + ledPath + "/brightness";
    FILE *fp = popen(cmd.toStdString().c_str(), "r");
    if (fp == nullptr) {
        return -1;
    }

    char led_status[32];
    if (fgets(led_status, sizeof(led_status), fp) == nullptr) {
        printf("fgets error: %s\n", cmd.toStdString().c_str());
        pclose(fp);
        return -1;
    }

    pclose(fp);
    return atoi(led_status);
}

void rice::on_ledPushButton_clicked()
{
    int ledStatus = getLedStatus();
    if (ledStatus == 0) {
        setLedStatus(1);
        ui->ledPushButton->setText("LED ON");
        ui->ledPushButton->setStyleSheet("border-width:1px;"
                                         "border-style:solid; "
                                         "border-color:white;"
                                         "background-color:rgba(00, 205, 00, 255)");
    }
    else {
        setLedStatus(0);
        ui->ledPushButton->setText("LED OFF");
        ui->ledPushButton->setStyleSheet("border-width:1px;"
                                         "border-style:solid; "
                                         "border-color:white;"
                                         "background-color:rgba(88, 88, 88, 200)");
    }
}
  1. 板载按键检测,代码实现:
void rice::keyInit()
{
    keyFd = open(keyPath.toUtf8().data(), O_RDONLY);
    if(keyFd == -1)
    {
        printf("Can not open file(%s)", keyPath.toUtf8().data());
        return;
    }
    ui->keyTextEdit->append("Key Monitor!\n");
    ui->keyTextEdit->append("Key user0 pressed!");

    keyNotify = new QSocketNotifier(this->keyFd, QSocketNotifier::Read, this);
    connect(this->keyNotify, SIGNAL(activated(int)), this, SLOT(keyHandler()));
}

void rice::keyDeinit()
{

}

void rice::keyHandler()
{
    struct input_event buf;

    if(read(keyFd, &buf, sizeof(struct input_event)) > 0)
    {
        if(buf.code == KEY_PROG1 && buf.value == 1)
        {
            ui->keyTextEdit->append("Key user0 pressed!");
        }
    }
}
  1. RTC时钟获取并显示,代码实现:
void rice::dateInit()
{
    struct rtc_time rtc_tm_temp;
    dateFd = open(datePath.toUtf8().data(), O_RDONLY);
    if(dateFd == -1)
    {
        printf("Can not open file(%s)", keyPath.toUtf8().data());
        return;
    }
    if(ioctl(dateFd, RTC_RD_TIME, &rtc_tm_temp) < 0)
    {
        printf("Get date failed");
        return;
    }
    ui->yearLineEdit->setText(QString::number(rtc_tm_temp.tm_year + 1900));
    ui->monthLineEdit->setText(QString::number(rtc_tm_temp.tm_mon + 1));
    ui->dayLineEdit->setText(QString::number(rtc_tm_temp.tm_mday));
}

void rice::dateDeint()
{

}
  1. 网络调试助手,代码实现:
void rice::netInit()
{
    server = new QTcpServer();
    socket = new QTcpSocket();
}

void rice::netDeint()
{

}

void rice::netNewClientConnect()
{
    socket = server->nextPendingConnection();
    connect(socket, &QTcpSocket::readyRead, this, &rice::netNewRcve);
}

void rice::on_netPushButton_clicked()
{
    int port = ui->portLineEdit->text().toInt();
    if(ui->netPushButton->text() == tr("Open"))
    {
        if(ui->typeComboBox->currentText() == tr("Server"))
        {
            connect(server, &QTcpServer::newConnection, this, &rice::netNewClientConnect);
            if(!server->listen(QHostAddress::Any, port))
            {
                printf("Listen failed\n");
                return;
            }
        }
        else if(ui->typeComboBox->currentText() == tr("Client"))
        {
            QString ip = ui->ipComboBox->currentText();
            socket->abort();
            socket->connectToHost(ip, port);

            if(!socket->waitForConnected(3000))
            {
                printf("Connect server failed");
                return;
            }
            connect(socket, &QTcpSocket::readyRead, this, &rice::netNewRcve);
        }
        ui->netPushButton->setText("Close");
    }
    else if(ui->netPushButton->text() == tr("Close"))
    {
        if(ui->typeComboBox->currentText() == tr("Server"))
        {
            socket->abort();
            server->close();
        }
        else if(ui->typeComboBox->currentText() == tr("Client"))
        {
            socket->disconnectFromHost();
        }
        ui->netPushButton->setText("Open");
    }
}

void rice::on_sendPushButton_clicked()
{
    if(socket->isOpen())
    {
        socket->write(ui->sendLineEdit->text().toUtf8().data());
    }
}

void rice::netNewRcve()
{
    ui->recvTextEdit->append(socket->readAll());
}

void rice::on_typeComboBox_currentIndexChanged(const QString &arg1)
{
    if(arg1 == tr("Server"))
    {
        ui->ipComboBox->setEditable(false);
    }
    else
    {
        ui->ipComboBox->setEditable(true);
    }
}

Qt应用验证

  1. 板载LED灯控制验证,当点击开关LED按钮时,LED灯会根据状态亮灭:

  1. 当应用运行起来时,会获取RTC时间,并显示:

  1. 当板载按键按下时,窗口会显示按键按下:

  1. 网络调试助手支持TCP客户端和TCP服务器两种类型,下面演示服务器验证。开发板上设置板子的IP,和端口号,然后通过PC上网络调试助手连接上板子,并克实现数据的收发:
  • 客户端往服务器发送数据

  • 服务器往客户端发送数据

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

scratch《贪吃蛇》改编版——设计方案

一、设计思路 设计想法来自《贪吃蛇》游戏改编。《贪吃蛇》游戏的背景源自古老的瑞典神话&#xff0c;讲述一条巨蛇在世间蔓延&#xff0c;吞噬一切的传说。游戏的玩法很简单&#xff0c;玩家通过上下左右键控制蛇的方向&#xff0c;使其在地图上移动并吞噬食物&#xff0c;随…

Android 12 及以上授权精确位置和模糊位置

请求位置信息权限 为了保护用户隐私&#xff0c;使用位置信息服务的应用必须请求位置权限。 请求位置权限时&#xff0c;请遵循与请求任何其他运行时权限相同的最佳做法。请求位置权限时的一个重要区别在于&#xff0c;系统中包含与位置相关的多项权限。具体请求哪项权限以及…

创新药集采中选后是否还需进行学术营销推广模式?

药品集采中选给药企带来了大幅降价和以价换量的趋势&#xff0c;同时也成为药企争夺的关键领域。对于是否继续进行推广活动&#xff0c;存在不同的观点和认知。 ▼需要还是不需要&#xff1f; 一些人认为集采后不再需要推广&#xff0c;因为药企无法承担高昂的销售费用&#x…

11.29 知识回顾(视图层、模板层)

一、视图层 1.1 响应对象 响应---》本质都是 HttpResponse -HttpResponse---》字符串 -render----》放个模板---》模板渲染是在后端完成 -js代码是在客户端浏览器里执行的 -模板语法是在后端执行的 -redirect----》重定向 -字符串参数不是…

Java实现socket编程案例

以下是一个基本的Java socket编程案例&#xff1a; 服务端代码&#xff1a; import java.net.*; import java.io.*;public class Server {public static void main(String[] args) throws IOException {ServerSocket serverSocket null;try {serverSocket new ServerSocket…

深度学习今年来经典模型优缺点总结,包括卷积、循环卷积、Transformer、LSTM、GANs等

文章目录 1、卷积神经网络&#xff08;Convolutional Neural Networks&#xff0c;CNN&#xff09;1.1 优点1.2 缺点1.3 应用场景1.4 网络图 2、循环神经网络&#xff08;Recurrent Neural Networks&#xff0c;RNNs&#xff09;2.1 优点2.2 缺点2.3 应用场景2.4 网络图 3、长短…

生产制造中4种导致产品成本、库存核算差错的问题!(化工/化妆品/生物制剂/混凝土等行业ODOO)

在化工/化妆品/生物制剂/混凝土等行业&#xff0c;因为其生产物料及产成品大都以液体&#xff08;或散颗粒&#xff09;形态为主&#xff0c;多以重量为计数方式&#xff1b;且液体&#xff08;或散颗粒&#xff09;相较于固体的较大区别就是产品计数上变数较大&#xff0c;固体…

什么是企业资金

我从两个方面来诠释企业资金管理&#xff1a; 1、企业资金管理是什么&#xff1f; 2、企业资金管理包括什么&#xff1f; 一、企业资金管理是什么&#xff1f; 众所周知&#xff0c;每个企业都有对应的财务部门&#xff0c;专门负责管理企业的“钱”&#xff0c;和企业的“帐…

企业软件手机app定制开发趋势|小程序网站搭建

企业软件手机app定制开发趋势|小程序网站搭建 随着移动互联网的快速发展和企业数字化转型的加速&#xff0c;企业软件手机App定制开发正成为一个新的趋势。这种趋势主要是由于企业对于手机App的需求增长以及现有的通用应用不能满足企业特定需求的情况下而产生的。 1.企业软件手…

【数据结构】—AVL树(C++实现)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 &#x1f49c;本文前置知识&#xff1a; 搜索二叉树 ♈️今日夜电波&#xff1a;Letter Song—ヲタみん 1:36━━━━━━️&#x1f49f;──────── 5:35 …

Ubuntu 20.04 for NVIDIA V100 GPU安装手册

安装Ubuntu 20.04.3 LTS版本 image.png 安装Ubuntu 20.04按照安装提示&#xff0c;仔细选择每一项&#xff0c;基本默认即可。 系统中查看GPU信息 系统安装完成之后&#xff0c;进入系统&#xff0c;使用lspci 命令查询一下GPU是否存在、型号信息是什么。 bpangbobpang:\~$…

C语言中一些有关字符串的常见函数的使用及模拟实现(2)

在编程的过程中&#xff0c;我们经常要处理字符和字符串&#xff0c;为了⽅便操作字符和字符串&#xff0c;C语⾔标准库中提供了\n⼀系列库函数&#xff0c;接下来我们就学习⼀下这些函数。 在上一篇博客中已经讲解了strlen&#xff0c;strcpy&#xff0c;strcmp&#xff0c;st…

XXL-Job详解(二):安装部署

目录 前言环境下载项目调度中心部署执行器部署 前言 看该文章之前&#xff0c;最好看一下之前的文章&#xff0c;比较方便我们理解 XXL-Job详解&#xff08;一&#xff09;&#xff1a;组件架构 环境 Maven3 Jdk1.8 Mysql5.7 下载项目 源码仓库地址链接: https://github.…

el-drawer抽屉组件弹窗遮挡问题解决

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 1、根据需要&#xff0c;需要在下面窗口里弹出抽屉组件&#xff0c;但出现遮挡问题&#xff0c;如下&…

阿里云刚崩完又崩了?部分地域云数据库控制台访问异常

11月27日&#xff0c;阿里云发布公告&#xff1a;您好&#xff01;北京时间2023年11月27日 09:16起&#xff0c;阿里云监控发现北京、上海、杭州、深圳、青岛 、香港以及美东、美西地域的数据库产品&#xff08;RDS、PolarDB、Redis等&#xff09;的控制台和OpenAPI访问出现异常…

【Openstack Train安装】一、虚拟机创建

Openstack是一个云平台管理的项目&#xff0c;它不是一个软件。这个项目由几个主要的组件组合起来完成一些具体的工作。Openstack是一个旨在为公共及私有云的建设与管理提供软件的开源项目。它的社区拥有超过130家企业及1350位开发者&#xff0c;这些机构与个人将 Openstack作为…

【Windows】内网穿透实现hMailServer远程发送邮件

目录 前言1. 安装hMailServer2. 设置hMailServer3. 客户端安装添加账号4. 测试发送邮件5. 安装cpolar6. 创建公网地址7. 测试远程发送邮件8. 固定连接公网地址9. 测试固定远程地址发送邮件 前言 hMailServer 是一个邮件服务器,通过它我们可以搭建自己的邮件服务,通过cpolar内网…

【RedisTemplate】SpringDataRedis(Spring中对Redis模块的整合)

SpringDataRedis简介&#xff1a; SpringData是Spring中数据操作的模块&#xff0c;包含对各种数据库的集成&#xff0c;其中对Redis的集成模块就叫做SpringDataRedis。 官网地址&#xff1a;https://spring.io/projects/spring-data-redis 提供了对不同Redis客户端的整合&a…

C++学习之路(十四)C++ 用Qt5实现一个工具箱(增加一个Base64图片编码预览功能)- 示例代码拆分讲解

上篇文章&#xff0c;我们用 Qt5 实现了在小工具箱中添加了《Base64加解密功能》功能。为了继续丰富我们的工具箱&#xff0c;今天我们就再增加一个平时经常用到的功能吧&#xff0c;就是「 Base64图片编码预览 」功能。下面我们就来看看如何来规划开发一个这样的小功能并且添加…

Redis的高可用模式

1. 什么是高可用&#xff1f; 高可用&#xff08;High Availability, HA&#xff09;是指在信息技术中确保系统、服务或应用程序在绝大多数时间内都是可操作和可访问的能力。这通常涉及以下几个关键方面&#xff1a; 最小化停机时间: 高可用系统的目标是减少因硬件故障、系统升…