当前位置:

首页 > 编程开发 > 基于Qt的实用二维码生成解决方案

基于Qt的实用二维码生成解决方案

纯C++且无任何依赖的nayukiqrcode库最适合Qt项目集成二维码功能,通过QRCodeWidget类可方便实现生成、保存、添加Logo及自定义样式设置。该库轻量高效,无需额外配置。相比之下,QZXing和libqrencode因体积较大或需编译而推荐度较低。

在Qt项目中集成二维码生成功能,通常有几种主流选择。下面把各方案的优劣势摆出来,再结合集成难度和实际使用场景,给出一份靠谱的推荐。

一、解决方案架构

1.1 技术选型比较

方案优点缺点推荐度
qrcode (nayuki)纯C++, 轻量, 无依赖功能基础★★★★★
QZXing功能强大, 支持多种格式体积大, 依赖多★★★★
libqrencode性能好, 广泛使用需要额外编译★★★★
ZXing-C++Google出品, 功能全编译复杂★★★

推荐方案:qrcode (nayuki) - 最适合Qt集成

基于Qt的实用二维码生成解决方案

二、核心实现方案

2.1 方案一:使用 qrcode (nayuki) - 推荐

要说最轻量、最容易集成的方案,非它莫属。纯C++实现,没有任何外部依赖,直接扔进项目就能用。

下载qrcode库

# 下载qrcode库
git clone https://github.com/nayuki/QR-Code-generator.git

Qt项目集成

文件结构:

QRCodeDemo/

├── main.cpp

├── QRCodeWidget.h

├── QRCodeWidget.cpp

├── qrcode/

│ ├── BitBuffer.hpp

│ ├── QrCode.hpp

│ ├── QrSegment.hpp

│ └── README.md

└── QRCodeDemo.pro

QRCodeWidget.h:

#ifndef QRCODEWIDGET_H
#define QRCODEWIDGET_H
#include 
#include 
#include 
#include 
#include 
class QRCodeWidget : public QWidget
{
    Q_OBJECT
public:
    explicit QRCodeWidget(QWidget *parent = nullptr);
    // 生成二维码
    bool generateQRCode(const QString& text, 
                       int version = 5,  // 二维码版本(1-40)
                       int eccLevel = 1, // 纠错等级(0-3)
                       int border = 4);  // 边距
    // 获取二维码图片
    QImage getQRCodeImage() const { return m_qrCodeImage; }
    // 保存二维码图片
    bool sa veToFile(const QString& filename, 
                   int scale = 4,  // 缩放倍数
                   const QString& format = "PNG");
    // 设置样式
    void setForegroundColor(const QColor& color) { m_foregroundColor = color; }
    void setBackgroundColor(const QColor& color) { m_backgroundColor = color; }
    void setDrawStyle(bool rounded = false, bool useGradient = false);
    // 添加Logo
    bool addLogo(const QImage& logo, int logoSizePercentage = 20);
    // 二维码信息
    int getVersion() const { return m_version; }
    int getEccLevel() const { return m_eccLevel; }
    QString getEccLevelName() const;
    int getSize() const { return m_qrSize; }
protected:
    void paintEvent(QPaintEvent *event) override;
signals:
    void qrCodeGenerated(bool success, const QString& error = QString());
private:
    // 绘制二维码
    void drawQRCode(QPainter& painter, int x, int y, int size);
    // 绘制Logo
    void drawLogo(QPainter& painter, int x, int y, int size);
    // 计算版本容量
    static int getMaxCapacity(int version, int eccLevel);
private:
    QImage m_qrCodeImage;
    QImage m_logoImage;
    QColor m_foregroundColor = Qt::black;
    QColor m_backgroundColor = Qt::white;
    int m_version = 5;
    int m_eccLevel = 1;  // 1 = LOW, 0 = MEDIUM, 2 = QUARTILE, 3 = HIGH
    int m_border = 4;
    int m_qrSize = 0;
    bool m_roundedModules = false;
    bool m_useGradient = false;
    std::vector m_qrData;
};
#endif // QRCODEWIDGET_H

QRCodeWidget.cpp:

#include "QRCodeWidget.h"
#include "qrcode/QrCode.hpp"
#include 
#include 
#include 
#include 
#include 

using qrcodegen::QrCode;
using qrcodegen::QrSegment;

QRCodeWidget::QRCodeWidget(QWidget *parent) 
    : QWidget(parent) {
    setMinimumSize(200, 200);
}

bool QRCodeWidget::generateQRCode(const QString& text, int version, int eccLevel, int border) {
    if (text.isEmpty()) {
        emit qrCodeGenerated(false, "文本不能为空");
        return false;
    }
    
    if (version < 1 || version > 40) {
        emit qrCodeGenerated(false, "版本必须在1-40之间");
        return false;
    }
    
    if (eccLevel < 0 || eccLevel > 3) {
        emit qrCodeGenerated(false, "纠错等级必须在0-3之间");
        return false;
    }
    
    m_version = version;
    m_eccLevel = eccLevel;
    m_border = border;
    
    try {
        // 将QString转换为UTF-8字节
        QByteArray utf8Data = text.toUtf8();
        std::vector data(utf8Data.begin(), utf8Data.end());
        
        // 创建QR码
        QrCode::Ecc ecc = static_cast(eccLevel);
        QrCode qr = QrCode::encodeBytes(data, ecc, version, version);
        
        m_qrSize = qr.getSize();
        m_qrData.clear();
        
        // 复制二维码数据
        for (int y = 0; y < m_qrSize; y++) {
            for (int x = 0; x < m_qrSize; x++) {
                m_qrData.push_back(qr.getModule(x, y) ? 1 : 0);
            }
        }
        
        // 创建图片
        int imgSize = m_qrSize + 2 * m_border;
        m_qrCodeImage = QImage(imgSize, imgSize, QImage::Format_ARGB32);
        m_qrCodeImage.fill(m_backgroundColor);
        
        QPainter painter(&m_qrCodeImage);
        painter.setRenderHint(QPainter::Antialiasing);
        drawQRCode(painter, m_border, m_border, m_qrSize);
        
        // 如果有Logo,绘制Logo
        if (!m_logoImage.isNull()) {
            drawLogo(painter, m_border, m_border, m_qrSize);
        }
        
        painter.end();
        
        update();  // 触发重绘
        emit qrCodeGenerated(true);
        return true;
        
    } catch (const std::exception& e) {
        qWarning() << "生成二维码失败:" << e.what();
        emit qrCodeGenerated(false, QString("生成失败: %1").arg(e.what()));
        return false;
    }
}

void QRCodeWidget::drawQRCode(QPainter& painter, int x, int y, int size) {
    int moduleSize = size / m_qrSize;
    
    painter.setPen(Qt::NoPen);
    
    if (m_useGradient) {
        QLinearGradient gradient(x, y, x + size, y + size);
        gradient.setColorAt(0, m_foregroundColor);
        gradient.setColorAt(1, m_foregroundColor.darker(150));
        painter.setBrush(gradient);
    } else {
        painter.setBrush(m_foregroundColor);
    }
    
    for (int row = 0; row < m_qrSize; row++) {
        for (int col = 0; col < m_qrSize; col++) {
            if (m_qrData[row * m_qrSize + col]) {
                int px = x + col * moduleSize;
                int py = y + row * moduleSize;
                
                if (m_roundedModules) {
                    painter.drawRoundedRect(px, py, moduleSize, moduleSize, 
                                           moduleSize / 3, moduleSize / 3);
                } else {
                    painter.drawRect(px, py, moduleSize, moduleSize);
                }
            }
        }
    }
}

void QRCodeWidget::drawLogo(QPainter& painter, int x, int y, int size) {
    if (m_logoImage.isNull()) return;
    
    int logoSize = size * 0.2;  // Logo大小为二维码的20%
    int centerX = x + (size - logoSize) / 2;
    int centerY = y + (size - logoSize) / 2;
    
    QPixmap logoPixmap = QPixmap::fromImage(m_logoImage)
        .scaled(logoSize, logoSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    
    // 绘制白色背景
    painter.setBrush(Qt::white);
    painter.setPen(Qt::NoPen);
    painter.drawRoundedRect(centerX - 2, centerY - 2, 
                           logoSize + 4, logoSize + 4, 8, 8);
    
    // 绘制Logo
    painter.drawPixmap(centerX, centerY, logoPixmap);
}

bool QRCodeWidget::sa veToFile(const QString& filename, int scale, const QString& format) {
    if (m_qrCodeImage.isNull()) {
        return false;
    }
    
    QImage scaledImage = m_qrCodeImage.scaled(
        m_qrCodeImage.width() * scale,
        m_qrCodeImage.height() * scale,
        Qt::KeepAspectRatio,
        Qt::SmoothTransformation
    );
    
    return scaledImage.sa ve(filename, format.toUpper().toUtf8());
}

void QRCodeWidget::setDrawStyle(bool rounded, bool useGradient) {
    m_roundedModules = rounded;
    m_useGradient = useGradient;
    update();
}

bool QRCodeWidget::addLogo(const QImage& logo, int logoSizePercentage) {
    if (logo.isNull()) {
        m_logoImage = QImage();
        return false;
    }
    
    m_logoImage = logo;
    update();
    return true;
}

QString QRCodeWidget::getEccLevelName() const {
    switch (m_eccLevel) {
    case 0: return "LOW (7%)";
    case 1: return "MEDIUM (15%)";
    case 2: return "QUARTILE (25%)";
    case 3: return "HIGH (30%)";
    default: return "UNKNOWN";
    }
}

int QRCodeWidget::getMaxCapacity(int version, int eccLevel) {
    // 简化的容量表(数字模式)
    static const int capacityTable[4][4] = {
        {17, 32, 53, 78},     // 版本1
        {32, 61, 100, 127},   // 版本2
        {53, 101, 165, 198},  // 版本3
        {78, 127, 198, 242}   // 版本4
    };
    
    if (version >= 1 && version <= 4 && eccLevel >= 0 && eccLevel <= 3) {
        return capacityTable[version-1][eccLevel];
    }
    return 0;
}

void QRCodeWidget::paintEvent(QPaintEvent *event) {
    Q_UNUSED(event);
    
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    
    if (!m_qrCodeImage.isNull()) {
        // 居中显示
        int x = (width() - m_qrCodeImage.width()) / 2;
        int y = (height() - m_qrCodeImage.height()) / 2;
        painter.drawImage(x, y, m_qrCodeImage);
    } else {
        // 显示提示
        painter.setPen(Qt::gray);
        painter.drawText(rect(), Qt::AlignCenter, "没有二维码数据");
    }
}

main.cpp:

#include "MainWindow.h"
#include 

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    // 设置应用程序信息
    app.setApplicationName("QR Code Generator");
    app.setOrganizationName("MyCompany");
    app.setApplicationVersion("1.0.0");
    
    MainWindow window;
    window.show();
    
    return app.exec();
}

2.2 方案二:使用QZXing库

QZXing是Qt生态里功能比较全面的二维码处理库,不光能生成,还能解码,支持多种格式。

安装QZXing

# 方法1:通过vcpkg
vcpkg install qzxing

# 方法2:手动编译
git clone https://github.com/ftylitak/qzxing.git
cd qzxing
mkdir build && cd build
cmake ..
make
make install

使用QZXing生成二维码

// QZXingGenerator.h
#ifndef QZXINGGENERATOR_H
#define QZXINGGENERATOR_H

#include 
#include 
#include 
#include 

class QZXingGenerator : public QObject
{
    Q_OBJECT
    
public:
    explicit QZXingGenerator(QObject *parent = nullptr);
    
    // 生成二维码
    QImage generateQRCode(const QString& data, 
                         const QSize& size = QSize(200, 200),
                         const QColor& foreground = Qt::black,
                         const QColor& background = Qt::white,
                         QZXing::EncoderCorrectionLevel correction = QZXing::EncodeErrorCorrectionLevel_M);
    
    // 生成带Logo的二维码
    QImage generateQRCodeWithLogo(const QString& data, 
                                 const QImage& logo,
                                 const QSize& size = QSize(200, 200));
    
    // 批量生成
    QList batchGenerate(const QStringList& dataList, 
                               const QSize& size = QSize(200, 200));
    
    // 保存到文件
    bool sa veQRCode(const QString& data, 
                   const QString& filename,
                   const QSize& size = QSize(200, 200));
    
signals:
    void generationComplete(const QImage& qrCode);
    void generationError(const QString& error);
    
private:
    QZXing m_qzxing;
};
#endif // QZXINGGENERATOR_H
// QZXingGenerator.cpp
#include "QZXingGenerator.h"
#include 
#include 
#include 

QZXingGenerator::QZXingGenerator(QObject *parent) 
    : QObject(parent) {
    // 初始化QZXing
    m_qzxing.setDecoder(QZXing::DecoderFormat_QR_CODE);
}

QImage QZXingGenerator::generateQRCode(const QString& data, 
                                      const QSize& size,
                                      const QColor& foreground,
                                      const QColor& background,
                                      QZXing::EncoderCorrectionLevel correction) {
    if (data.isEmpty()) {
        emit generationError("数据不能为空");
        return QImage();
    }
    
    try {
        // 设置编码参数
        QZXing::EncodeErrorCorrectionLevel eccLevel = correction;
        
        // 生成二维码
        QImage qrCode = m_qzxing.encodeData(data, size, foreground, background, eccLevel);
        
        if (qrCode.isNull()) {
            emit generationError("生成二维码失败");
            return QImage();
        }
        
        emit generationComplete(qrCode);
        return qrCode;
        
    } catch (const std::exception& e) {
        emit generationError(QString("生成错误: %1").arg(e.what()));
        return QImage();
    }
}

QImage QZXingGenerator::generateQRCodeWithLogo(const QString& data, 
                                              const QImage& logo,
                                              const QSize& size) {
    // 先生成基本二维码
    QImage qrCode = generateQRCode(data, size);
    if (qrCode.isNull() || logo.isNull()) {
        return qrCode;
    }
    
    // 在二维码中心添加Logo
    QImage result = qrCode.copy();
    QPainter painter(&result);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    
    // 计算Logo位置和大小
    int logoSize = qMin(size.width(), size.height()) * 0.2;  // Logo大小为20%
    int x = (size.width() - logoSize) / 2;
    int y = (size.height() - logoSize) / 2;
    
    // 绘制白色背景
    painter.setBrush(Qt::white);
    painter.setPen(Qt::NoPen);
    painter.drawRoundedRect(x-2, y-2, logoSize+4, logoSize+4, 5, 5);
    
    // 绘制Logo
    QPixmap scaledLogo = QPixmap::fromImage(logo)
        .scaled(logoSize, logoSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    painter.drawPixmap(x, y, scaledLogo);
    
    return result;
}

QList QZXingGenerator::batchGenerate(const QStringList& dataList, 
                                            const QSize& size) {
    QList result;
    
    for (const QString& data : dataList) {
        QImage qrCode = generateQRCode(data, size);
        if (!qrCode.isNull()) {
            result.append(qrCode);
        }
    }
    
    return result;
}

bool QZXingGenerator::sa veQRCode(const QString& data, 
                                const QString& filename,
                                const QSize& size) {
    QImage qrCode = generateQRCode(data, size);
    if (qrCode.isNull()) {
        return false;
    }
    
    return qrCode.sa ve(filename);
}

2.3 方案三:使用libqrencode

这是一款C语言写的二维码生成库,性能相当不错,在很多开源项目里都有它的身影。

安装libqrencode

# Ubuntu/Debian
sudo apt-get install libqrencode-dev
# macOS
brew install qrencode
# Windows (vcpkg)
vcpkg install qrencode

libqrencode封装

// LibQRencodeWrapper.h
#ifndef LIBQRENCODEWRAPPER_H
#define LIBQRENCODEWRAPPER_H

#include 
#include 
#include 

class LibQRencodeWrapper
{
public:
    enum QRCorrectionLevel {
        QR_ECLEVEL_L = 0,  // 7% 纠错
        QR_ECLEVEL_M = 1,  // 15% 纠错
        QR_ECLEVEL_Q = 2,  // 25% 纠错
        QR_ECLEVEL_H = 3   // 30% 纠错
    };
    
    struct QRCodeOptions {
        int version = 0;           // 0 = 自动选择
        QRCorrectionLevel level = QR_ECLEVEL_M;
        int margin = 4;            // 边距
        int scale = 4;             // 缩放倍数
        bool caseSensitive = true; // 大小写敏感
    };
    
    static QImage generateQRCode(const QString& text, 
                                const QRCodeOptions& options = QRCodeOptions());
    
    static QString getLibraryVersion();
    
    static int getMaxVersion() { return 40; }
    static int getMinVersion() { return 1; }
    
private:
    static QRcode* encodeString(const QString& text, 
                               const QRCodeOptions& options);
};
#endif // LIBQRENCODEWRAPPER_H
// LibQRencodeWrapper.cpp
#include "LibQRencodeWrapper.h"
#include 
#include 

QImage LibQRencodeWrapper::generateQRCode(const QString& text, 
                                         const QRCodeOptions& options) {
    if (text.isEmpty()) {
        return QImage();
    }
    
    QRcode* qr = encodeString(text, options);
    if (!qr) {
        qWarning() << "Failed to generate QR code";
        return QImage();
    }
    
    // 计算图片大小
    int qrSize = qr->width;
    int imageSize = (qrSize + 2 * options.margin) * options.scale;
    
    QImage image(imageSize, imageSize, QImage::Format_ARGB32);
    image.fill(Qt::white);
    
    QPainter painter(&image);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(Qt::black);
    painter.setPen(Qt::NoPen);
    
    // 绘制二维码
    for (int y = 0; y < qrSize; y++) {
        for (int x = 0; x < qrSize; x++) {
            if (qr->data[y * qrSize + x] & 1) {
                int px = (options.margin + x) * options.scale;
                int py = (options.margin + y) * options.scale;
                painter.drawRect(px, py, options.scale, options.scale);
            }
        }
    }
    
    painter.end();
    QRcode_free(qr);
    
    return image;
}

QRcode* LibQRencodeWrapper::encodeString(const QString& text, 
                                        const QRCodeOptions& options) {
    QRecLevel level = static_cast(options.level);
    QRecLevel* hint = options.caseSensitive ? QR_MODE_8 : QR_MODE_KANJI;
    
    QRcode* qr = nullptr;
    
    if (options.version > 0) {
        // 指定版本
        qr = QRcode_encodeString(text.toUtf8().constData(),
                                 options.version,
                                 level,
                                 hint,
                                 1);
    } else {
        // 自动选择版本
        qr = QRcode_encodeString(text.toUtf8().constData(),
                                 0,
                                 level,
                                 hint,
                                 1);
    }
    
    return qr;
}

QString LibQRencodeWrapper::getLibraryVersion() {
    return QString("libqrencode %1").arg(qrencode_version());
}

三、功能丰富的二维码生成器

3.1 主窗口设计

// MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
#include "QRCodeWidget.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    
private slots:
    void onGenerateClicked();
    void onSa veClicked();
    void onClearClicked();
    void onAddLogoClicked();
    void onRemoveLogoClicked();
    void onTextChanged();
    void onStyleChanged();
    void onQRCodeGenerated(bool success, const QString& error = QString());
    void onUpdatePreview();
    
private:
    void setupUI();
    void setupConnections();
    void updateCapacityInfo();
    void loadSettings();
    void sa veSettings();
    
private:
    Ui::MainWindow *ui;
    QRCodeWidget *m_qrCodeWidget;
    QImage m_logoImage;
    QTimer *m_previewTimer;
};
#endif // MAINWINDOW_H
// MainWindow.cpp
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include 
#include 
#include 
#include 
#include 
#include 

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , m_qrCodeWidget(new QRCodeWidget(this))
    , m_previewTimer(new QTimer(this)) {
    
    ui->setupUI(this);
    setupUI();
    setupConnections();
    loadSettings();
    
    m_previewTimer->setSingleShot(true);
    m_previewTimer->setInterval(500);  // 500ms延迟预览
}

MainWindow::~MainWindow() {
    sa veSettings();
    delete ui;
}

void MainWindow::setupUI() {
    // 设置中心窗口
    setCentralWidget(m_qrCodeWidget);
    
    // 创建工具栏
    QToolBar *toolBar = addToolBar("Main");
    toolBar->setMovable(false);
    
    toolBar->addAction("生成", this, &MainWindow::onGenerateClicked);
    toolBar->addAction("保存", this, &MainWindow::onSa veClicked);
    toolBar->addAction("清除", this, &MainWindow::onClearClicked);
    toolBar->addSeparator();
    toolBar->addAction("添加Logo", this, &MainWindow::onAddLogoClicked);
    toolBar->addAction("移除Logo", this, &MainWindow::onRemoveLogoClicked);
    
    // 创建状态栏
    statusBar()->showMessage("就绪");
    
    // 初始化控件
    for (int i = 1; i <= 10; i++) {
        ui->comboVersion->addItem(QString("V%1").arg(i), i);
    }
    ui->comboVersion->setCurrentIndex(4);  // 默认V5
    
    ui->comboECC->addItem("LOW (7%)", 0);
    ui->comboECC->addItem("MEDIUM (15%)", 1);
    ui->comboECC->addItem("QUARTILE (25%)", 2);
    ui->comboECC->addItem("HIGH (30%)", 3);
    ui->comboECC->setCurrentIndex(1);  // 默认MEDIUM
    
    ui->spinBorder->setValue(4);
    ui->spinScale->setValue(4);
    
    updateCapacityInfo();
}

void MainWindow::setupConnections() {
    connect(ui->btnGenerate, &QPushButton::clicked, 
            this, &MainWindow::onGenerateClicked);
    connect(ui->btnSa ve, &QPushButton::clicked, 
            this, &MainWindow::onSa veClicked);
    connect(ui->btnClear, &QPushButton::clicked, 
            this, &MainWindow::onClearClicked);
    connect(ui->btnAddLogo, &QPushButton::clicked, 
            this, &MainWindow::onAddLogoClicked);
    connect(ui->btnRemoveLogo, &QPushButton::clicked, 
            this, &MainWindow::onRemoveLogoClicked);
    connect(ui->textContent, &QTextEdit::textChanged, 
            this, &MainWindow::onTextChanged);
    connect(ui->checkRounded, &QCheckBox::toggled, 
            this, &MainWindow::onStyleChanged);
    connect(ui->checkGradient, &QCheckBox::toggled, 
            this, &MainWindow::onStyleChanged);
    connect(ui->btnCopy, &QPushButton::clicked,  {
        QApplication::clipboard()->setPixmap(
            QPixmap::fromImage(m_qrCodeWidget->getQRCodeImage())
        );
        statusBar()->showMessage("二维码已复制到剪贴板", 2000);
    });
    
    connect(m_qrCodeWidget, &QRCodeWidget::qrCodeGenerated,
            this, &MainWindow::onQRCodeGenerated);
    connect(m_previewTimer, &QTimer::timeout,
            this, &MainWindow::onUpdatePreview);
}

void MainWindow::onGenerateClicked() {
    QString text = ui->textContent->toPlainText().trimmed();
    if (text.isEmpty()) {
        QMessageBox::warning(this, "警告", "请输入要编码的内容");
        return;
    }
    
    int version = ui->comboVersion->currentData().toInt();
    int eccLevel = ui->comboECC->currentData().toInt();
    int border = ui->spinBorder->value();
    
    // 检查内容长度是否超过容量限制
    int maxCapacity = m_qrCodeWidget->getMaxCapacity(version, eccLevel);
    if (text.length() > maxCapacity) {
        QMessageBox::warning(this, "警告", 
            QString("内容过长!最大容量为%1字符,当前%2字符")
            .arg(maxCapacity).arg(text.length()));
        return;
    }
    
    statusBar()->showMessage("正在生成二维码...");
    m_qrCodeWidget->generateQRCode(text, version, eccLevel, border);
}

void MainWindow::onSa veClicked() {
    if (m_qrCodeWidget->getQRCodeImage().isNull()) {
        QMessageBox::warning(this, "警告", "没有可保存的二维码");
        return;
    }
    
    QString filter = "PNG 图片 (*.png);;JPEG 图片 (*.jpg *.jpeg);;BMP 图片 (*.bmp)";
    QString filename = QFileDialog::getSa veFileName(this, "保存二维码", 
                                                   "qrcode.png", filter);
    
    if (!filename.isEmpty()) {
        int scale = ui->spinScale->value();
        QString format = QFileInfo(filename).suffix().toUpper();
        
        if (m_qrCodeWidget->sa veToFile(filename, scale, format)) {
            statusBar()->showMessage(QString("保存成功: %1").arg(filename), 3000);
        } else {
            QMessageBox::critical(this, "错误", "保存失败");
        }
    }
}

void MainWindow::onClearClicked() {
    ui->textContent->clear();
    m_qrCodeWidget->addLogo(QImage());  // 移除Logo
    statusBar()->showMessage("已清除", 2000);
}

void MainWindow::onAddLogoClicked() {
    QString filename = QFileDialog::getOpenFileName(this, "选择Logo图片", 
                                                   "", 
                                                   "图片文件 (*.png *.jpg *.jpeg *.bmp)");
    if (!filename.isEmpty()) {
        m_logoImage.load(filename);
        if (m_logoImage.isNull()) {
            QMessageBox::warning(this, "警告", "无法加载图片");
            return;
        }
        
        m_qrCodeWidget->addLogo(m_logoImage, ui->spinLogoSize->value());
        statusBar()->showMessage("Logo已添加", 2000);
    }
}

void MainWindow::onRemoveLogoClicked() {
    m_logoImage = QImage();
    m_qrCodeWidget->addLogo(QImage());  // 移除Logo
    statusBar()->showMessage("Logo已移除", 2000);
}

void MainWindow::onTextChanged() {
    // 延迟预览
    m_previewTimer->start();
    updateCapacityInfo();
}

void MainWindow::onStyleChanged() {
    bool rounded = ui->checkRounded->isChecked();
    bool gradient = ui->checkGradient->isChecked();
    m_qrCodeWidget->setDrawStyle(rounded, gradient);
}

void MainWindow::onQRCodeGenerated(bool success, const QString& error) {
    if (success) {
        QString info = QString("版本: V%1, 纠错: %2, 尺寸: %3×%3")
            .arg(m_qrCodeWidget->getVersion())
            .arg(m_qrCodeWidget->getEccLevelName())
            .arg(m_qrCodeWidget->getSize());
        statusBar()->showMessage(info);
    } else {
        QMessageBox::critical(this, "错误", error);
        statusBar()->showMessage("生成失败");
    }
}

void MainWindow::onUpdatePreview() {
    if (ui->checkAutoPreview->isChecked()) {
        onGenerateClicked();
    }
}

void MainWindow::updateCapacityInfo() {
    int version = ui->comboVersion->currentData().toInt();
    int eccLevel = ui->comboECC->currentData().toInt();
    int currentLength = ui->textContent->toPlainText().length();
    int maxCapacity = m_qrCodeWidget->getMaxCapacity(version, eccLevel);
    
    QString info = QString("长度: %1 / %2").arg(currentLength).arg(maxCapacity);
    ui->labelCapacity->setText(info);
    
    // 进度条显示
    int percent = qMin(100, (currentLength * 100) / maxCapacity);
    ui->progressCapacity->setValue(percent);
    
    // 颜色指示
    if (percent > 90) {
        ui->progressCapacity->setStyleSheet("QProgressBar::chunk { background-color: red; }");
    } else if (percent > 70) {
        ui->progressCapacity->setStyleSheet("QProgressBar::chunk { background-color: orange; }");
    } else {
        ui->progressCapacity->setStyleSheet("");
    }
}

void MainWindow::loadSettings() {
    QSettings settings;
    
    // 加载窗口位置和大小
    if (settings.contains("geometry")) {
        restoreGeometry(settings.value("geometry").toByteArray());
    }
    
    // 加载上次的内容
    QString lastContent = settings.value("lastContent").toString();
    if (!lastContent.isEmpty()) {
        ui->textContent->setPlainText(lastContent);
    }
}

void MainWindow::sa veSettings() {
    QSettings settings;
    
    // 保存窗口位置和大小
    settings.setValue("geometry", sa veGeometry());
    
    // 保存当前内容
    settings.setValue("lastContent", ui->textContent->toPlainText());
}

3.2 UI界面设计 (ui_MainWindow.h)

// UI设计文件 (通过Qt Designer创建)
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

class Ui_MainWindow {
public:
    QWidget *centralWidget;
    QVBoxLayout *verticalLayout;
    QHBoxLayout *horizontalLayout;
    QVBoxLayout *leftLayout;
    QTextEdit *textContent;
    QHBoxLayout *buttonLayout;
    QPushButton *btnGenerate;
    QPushButton *btnSa ve;
    QPushButton *btnClear;
    QPushButton *btnCopy;
    QVBoxLayout *rightLayout;
    QGroupBox *groupSettings;
    QVBoxLayout *settingsLayout;
    QHBoxLayout *layoutVersion;
    QLabel *labelVersion;
    QComboBox *comboVersion;
    QHBoxLayout *layoutECC;
    QLabel *labelECC;
    QComboBox *comboECC;
    QHBoxLayout *layoutBorder;
    QLabel *labelBorder;
    QSpinBox *spinBorder;
    QHBoxLayout *layoutScale;
    QLabel *labelScale;
    QSpinBox *spinScale;
    QHBoxLayout *layoutLogo;
    QLabel *labelLogo;
    QSpinBox *spinLogoSize;
    QPushButton *btnAddLogo;
    QPushButton *btnRemoveLogo;
    QGroupBox *groupStyle;
    QVBoxLayout *styleLayout;
    QCheckBox *checkRounded;
    QCheckBox *checkGradient;
    QCheckBox *checkAutoPreview;
    QGroupBox *groupInfo;
    QVBoxLayout *infoLayout;
    QLabel *labelCapacity;
    QProgressBar *progressCapacity;
    
    void setupUI(QMainWindow *MainWindow) {
        if (MainWindow->objectName().isEmpty())
            MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
        MainWindow->resize(800, 600);
        
        centralWidget = new QWidget(MainWindow);
        centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
        
        verticalLayout = new QVBoxLayout(centralWidget);
        verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
        
        horizontalLayout = new QHBoxLayout();
        horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
        
        // 左侧:输入区域
        leftLayout = new QVBoxLayout();
        leftLayout->setObjectName(QString::fromUtf8("leftLayout"));
        
        textContent = new QTextEdit(centralWidget);
        textContent->setObjectName(QString::fromUtf8("textContent"));
        textContent->setPlaceholderText("请输入要编码的内容...");
        leftLayout->addWidget(textContent);
        
        buttonLayout = new QHBoxLayout();
        buttonLayout->setObjectName(QString::fromUtf8("buttonLayout"));
        
        btnGenerate = new QPushButton(centralWidget);
        btnGenerate->setObjectName(QString::fromUtf8("btnGenerate"));
        btnGenerate->setText("生成二维码");
        buttonLayout->addWidget(btnGenerate);
        
        btnSa ve = new QPushButton(centralWidget);
        btnSa ve->setObjectName(QString::fromUtf8("btnSa ve"));
        btnSa ve->setText("保存");
        buttonLayout->addWidget(btnSa ve);
        
        btnClear = new QPushButton(centralWidget);
        btnClear->setObjectName(QString::fromUtf8("btnClear"));
        btnClear->setText("清除");
        buttonLayout->addWidget(btnClear);
        
        btnCopy = new QPushButton(centralWidget);
        btnCopy->setObjectName(QString::fromUtf8("btnCopy"));
        btnCopy->setText("复制");
        buttonLayout->addWidget(btnCopy);
        
        leftLayout->addLayout(buttonLayout);
        horizontalLayout->addLayout(leftLayout, 2);
        
        // 右侧:设置区域
        rightLayout = new QVBoxLayout();
        rightLayout->setObjectName(QString::fromUtf8("rightLayout"));
        
        // 设置组
        groupSettings = new QGroupBox(centralWidget);
        groupSettings->setObjectName(QString::fromUtf8("groupSettings"));
        groupSettings->setTitle("设置");
        settingsLayout = new QVBoxLayout(groupSettings);
        
        // 版本
        layoutVersion = new QHBoxLayout();
        labelVersion = new QLabel(groupSettings);
        labelVersion->setText("版本:");
        layoutVersion->addWidget(labelVersion);
        
        comboVersion = new QComboBox(groupSettings);
        layoutVersion->addWidget(comboVersion);
        settingsLayout->addLayout(layoutVersion);
        
        // 纠错等级
        layoutECC = new QHBoxLayout();
        labelECC = new QLabel(groupSettings);
        labelECC->setText("纠错等级:");
        layoutECC->addWidget(labelECC);
        
        comboECC = new QComboBox(groupSettings);
        layoutECC->addWidget(comboECC);
        settingsLayout->addLayout(layoutECC);
        
        // 边距
        layoutBorder = new QHBoxLayout();
        labelBorder = new QLabel(groupSettings);
        labelBorder->setText("边距:");
        layoutBorder->addWidget(labelBorder);
        
        spinBorder = new QSpinBox(groupSettings);
        spinBorder->setRange(0, 20);
        spinBorder->setValue(4);
        layoutBorder->addWidget(spinBorder);
        settingsLayout->addLayout(layoutBorder);
        
        // 缩放
        layoutScale = new QHBoxLayout();
        labelScale = new QLabel(groupSettings);
        labelScale->setText("保存缩放:");
        layoutScale->addWidget(labelScale);
        
        spinScale = new QSpinBox(groupSettings);
        spinScale->setRange(1, 10);
        spinScale->setValue(4);
        layoutScale->addWidget(spinScale);
        settingsLayout->addLayout(layoutScale);
        
        // Logo设置
        layoutLogo = new QHBoxLayout();
        labelLogo = new QLabel(groupSettings);
        labelLogo->setText("Logo大小:");
        layoutLogo->addWidget(labelLogo);
        
        spinLogoSize = new QSpinBox(groupSettings);
        spinLogoSize->setRange(5, 50);
        spinLogoSize->setValue(20);
        spinLogoSize->setSuffix("%");
        layoutLogo->addWidget(spinLogoSize);
        
        btnAddLogo = new QPushButton(groupSettings);
        btnAddLogo->setText("添加");
        layoutLogo->addWidget(btnAddLogo);
        
        btnRemoveLogo = new QPushButton(groupSettings);
        btnRemoveLogo->setText("移除");
        layoutLogo->addWidget(btnRemoveLogo);
        settingsLayout->addLayout(layoutLogo);
        
        rightLayout->addWidget(groupSettings);
        
        // 样式组
        groupStyle = new QGroupBox(centralWidget);
        groupStyle->setObjectName(QString::fromUtf8("groupStyle"));
        groupStyle->setTitle("样式");
        styleLayout = new QVBoxLayout(groupStyle);
        
        checkRounded = new QCheckBox(groupStyle);
        checkRounded->setText("圆角模块");
        styleLayout->addWidget(checkRounded);
        
        checkGradient = new QCheckBox(groupStyle);
        checkGradient->setText("渐变颜色");
        styleLayout->addWidget(checkGradient);
        
        checkAutoPreview = new QCheckBox(groupStyle);
        checkAutoPreview->setText("实时预览");
        styleLayout->addWidget(checkAutoPreview);
        
        rightLayout->addWidget(groupStyle);
        
        // 信息组
        groupInfo = new QGroupBox(centralWidget);
        groupInfo->setObjectName(QString::fromUtf8("groupInfo"));
        groupInfo->setTitle("信息");
        infoLayout = new QVBoxLayout(groupInfo);
        
        labelCapacity = new QLabel(groupInfo);
        labelCapacity->setText("长度: 0/0");
        infoLayout->addWidget(labelCapacity);
        
        progressCapacity = new QProgressBar(groupInfo);
        progressCapacity->setRange(0, 100);
        infoLayout->addWidget(progressCapacity);
        
        rightLayout->addWidget(groupInfo);
        rightLayout->addStretch();
        
        horizontalLayout->addLayout(rightLayout, 1);
        verticalLayout->addLayout(horizontalLayout);
        
        MainWindow->setCentralWidget(centralWidget);
    }
};
#endif // UI_MAINWINDOW_H

四、高级功能扩展

4.1 批量生成工具

// BatchQRCodeGenerator.h
#ifndef BATCHQRCODEGENERATOR_H
#define BATCHQRCODEGENERATOR_H

#include 
#include 
#include 
#include 

class BatchQRCodeGenerator : public QObject, public QRunnable
{
    Q_OBJECT
    
public:
    struct BatchItem {
        QString id;
        QString content;
        QString filename;
        int version = 5;
        int eccLevel = 1;
        int scale = 4;
    };
    
    explicit BatchQRCodeGenerator(QObject *parent = nullptr);
    
    void addBatch(const QList& items);
    void clear();
    
    void run() override;
    
    void setOutputDir(const QString& dir) { m_outputDir = dir; }
    void setThreadCount(int count);
    
signals:
    void progress(int current, int total, const QString& id);
    void finished(int successCount, int failedCount);
    void error(const QString& id, const QString& error);
    
private:
    QList m_items;
    QString m_outputDir;
    QThreadPool m_threadPool;
};
#endif // BATCHQRCODEGENERATOR_H

4.2 二维码解码功能

// QRCodeDecoder.h
#ifndef QRCODEDECODER_H
#define QRCODEDECODER_H

#include 
#include 
#include 

class QRCodeDecoder : public QObject
{
    Q_OBJECT
    
public:
    explicit QRCodeDecoder(QObject *parent = nullptr);
    
    // 从图片文件解码
    QString decodeFromFile(const QString& filename);
    
    // 从QImage解码
    QString decodeFromImage(const QImage& image);
    
    // 从剪贴板解码
    QString decodeFromClipboard();
    
    // 从摄像头捕获
    void startCameraCapture();
    void stopCameraCapture();
    
signals:
    void decoded(const QString& result);
    void cameraFrameCaptured(const QImage& frame);
    
private:
    QZXing m_decoder;
};
#endif // QRCODEDECODER_H

4.3 样式化二维码

// StyledQRCodeGenerator.h
#ifndef STYLEDQRCODEGENERATOR_H
#define STYLEDQRCODEGENERATOR_H

#include 

class StyledQRCodeGenerator
{
public:
    enum PatternStyle {
        StyleDefault,
        StyleDots,
        StyleRounded,
        StyleStars,
        StyleHearts
    };
    
    struct StyleOptions {
        PatternStyle patternStyle = StyleDefault;
        QColor primaryColor = Qt::black;
        QColor secondaryColor = Qt::white;
        QColor gradientStart = Qt::black;
        QColor gradientEnd = Qt::darkGray;
        bool useGradient = false;
        int cornerRadius = 5;
    };
    
    static QImage generateStyledQRCode(const QString& text, 
                                      const QSize& size,
                                      const StyleOptions& options);
    
private:
    static void applyPattern(QImage& image, const QImage& pattern, 
                            const QColor& color, int moduleSize);
    static QImage createDotPattern(int size);
    static QImage createStarPattern(int size);
    static QImage createHeartPattern(int size);
};
#endif // STYLEDQRCODEGENERATOR_H

五、项目配置

5.1 CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(QRCodeGenerator)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 查找Qt
find_package(Qt6 COMPONENTS Core Widgets REQUIRED)
# 包含目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/qrcode)
# 源文件
set(SOURCES
    main.cpp
    QRCodeWidget.cpp
    MainWindow.cpp
    QRCodeGenerator.cpp
)
# 头文件
set(HEADERS
    QRCodeWidget.h
    MainWindow.h
    QRCodeGenerator.h
)
# UI文件
set(FORMS
    MainWindow.ui
)
# 资源文件
set(RESOURCES
    resources.qrc
)
# 生成MOC文件
qt6_wrap_cpp(MOC_SOURCES ${HEADERS})
qt6_wrap_ui(UI_SOURCES ${FORMS})
qt6_add_resources(RES_SOURCES ${RESOURCES})
# 可执行文件
add_executable(${PROJECT_NAME}
    ${SOURCES}
    ${MOC_SOURCES}
    ${UI_SOURCES}
    ${RES_SOURCES}
)
# 链接库
target_link_libraries(${PROJECT_NAME}
    Qt6::Core
    Qt6::Widgets
)

5.2 .pro 文件 (qmake)

# QRCodeGenerator.pro
QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = QRCodeGenerator
TEMPLATE = app
# 源文件
SOURCES += 
    main.cpp 
    QRCodeWidget.cpp 
    MainWindow.cpp
HEADERS += 
    QRCodeWidget.h 
    MainWindow.h
FORMS += 
    MainWindow.ui
# 包含qrcode库
INCLUDEPATH += $$PWD/qrcode
# 编译选项
QMAKE_CXXFLAGS += -std=c++17
CONFIG += c++17
# 发布配置
CONFIG(release, debug|release) {
    DEFINES += QT_NO_DEBUG_OUTPUT
    QMAKE_CXXFLAGS += -O2
}
# 调试配置
CONFIG(debug, debug|release) {
    DEFINES += QT_DEBUG
    QMAKE_CXXFLAGS += -g
}

5.3 资源文件



    
        
        icons/app.png
        icons/generate.png
        icons/sa ve.png
        icons/clear.png
        icons/logo.png
        
        styles/style.qss
        
        logo/default.png
    
/* styles/style.qss */
QMainWindow {
    background-color: #f5f5f5;
}
QGroupBox {
    font-weight: bold;
    border: 1px solid #ccc;
    border-radius: 5px;
    margin-top: 10px;
    padding-top: 10px;
}
QGroupBox::title {
    subcontrol-origin: margin;
    left: 10px;
    padding: 0 5px 0 5px;
}
QPushButton {
    padding: 8px 16px;
    border-radius: 4px;
    font-weight: bold;
}
QPushButton:hover {
    background-color: #e0e0e0;
}
QTextEdit {
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 8px;
    font-family: "Microsoft YaHei", "SimSun";
}
QProgressBar {
    border: 1px solid #ccc;
    border-radius: 4px;
    text-align: center;
}
QProgressBar::chunk {
    background-color: #4CAF50;
    border-radius: 4px;
}

六、使用示例

6.1 基本使用

#include "QRCodeGenerator.h"
#include 
#include 

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    // 创建二维码生成器
    QRCodeGenerator generator;
    
    // 生成基本二维码
    QImage qrCode = generator.generateQRCode("https://www.example.com", 
                                            QSize(200, 200));
    
    if (!qrCode.isNull()) {
        // 保存到文件
        qrCode.sa ve("qrcode.png");
        
        // 显示二维码
        QLabel label;
        label.setPixmap(QPixmap::fromImage(qrCode));
        label.show();
        
        return app.exec();
    }
    
    return 0;
}

6.2 高级功能

// 高级使用示例
void advancedExample() {
    QRCodeGenerator generator;
    
    // 1. 生成带Logo的二维码
    QImage logo(":/logo/company.png");
    QImage qrWithLogo = generator.generateQRCodeWithLogo(
        "https://www.company.com", logo, QSize(300, 300));
    
    // 2. 生成样式化二维码
    StyledQRCodeGenerator::StyleOptions options;
    options.patternStyle = StyledQRCodeGenerator::StyleDots;
    options.useGradient = true;
    options.gradientStart = QColor("#FF5722");
    options.gradientEnd = QColor("#FF9800");
    
    QImage styledQR = generator.generateStyledQRCode(
        "特殊样式", QSize(250, 250), options);
    
    // 3. 批量生成
    QList items;
    for (int i = 0; i < 10; i++) {
        BatchQRCodeGenerator::BatchItem item;
        item.id = QString("QR%1").arg(i+1);
        item.content = QString("https://example.com/item/%1").arg(i+1);
        item.filename = QString("qrcode_%1.png").arg(i+1);
        items.append(item);
    }
    
    BatchQRCodeGenerator batchGenerator;
    batchGenerator.addBatch(items);
    batchGenerator.setOutputDir("./qrcodes");
    
    QObject::connect(&batchGenerator, &BatchQRCodeGenerator::progress,
        int current, int total, const QString& id {
            qDebug() << "进度:" << current << "/" << total << id;
        });
    
    batchGenerator.run();
}

6.3 命令行工具

// QRCodeCLI.cpp - 命令行工具
#include "QRCodeGenerator.h"
#include 
#include 
#include 

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);
    app.setApplicationName("QR Code CLI");
    app.setApplicationVersion("1.0.0");
    
    QCommandLineParser parser;
    parser.setApplicationDescription("命令行二维码生成器");
    parser.addHelpOption();
    parser.addVersionOption();
    
    // 定义参数
    parser.addPositionalArgument("content", "要编码的内容");
    parser.addPositionalArgument("output", "输出文件", "[output.png]");
    
    QCommandLineOption sizeOption("s", "图片大小", "size", "200");
    parser.addOption(sizeOption);
    
    QCommandLineOption versionOption("v", "二维码版本", "version", "5");
    parser.addOption(versionOption);
    
    QCommandLineOption eccOption("e", "纠错等级", "ecc", "1");
    parser.addOption(eccOption);
    
    QCommandLineOption logoOption("l", "Logo文件", "logo");
    parser.addOption(logoOption);
    
    parser.process(app);
    
    // 获取参数
    QStringList args = parser.positionalArguments();
    if (args.isEmpty()) {
        parser.showHelp(1);
    }
    
    QString content = args.at(0);
    QString output = args.value(1, "qrcode.png");
    int size = parser.value(sizeOption).toInt();
    int version = parser.value(versionOption).toInt();
    int ecc = parser.value(eccOption).toInt();
    QString logoFile = parser.value(logoOption);
    
    // 生成二维码
    QRCodeGenerator generator;
    QImage qrCode;
    
    if (!logoFile.isEmpty()) {
        QImage logo(logoFile);
        if (logo.isNull()) {
            qCritical() << "无法加载Logo文件:" << logoFile;
            return 1;
        }
        qrCode = generator.generateQRCodeWithLogo(content, logo, QSize(size, size));
    } else {
        qrCode = generator.generateQRCode(content, QSize(size, size), version, ecc);
    }
    
    if (qrCode.isNull()) {
        qCritical() << "生成二维码失败";
        return 1;
    }
    
    if (qrCode.sa ve(output)) {
        qInfo() << "二维码已保存到:" << output;
        return 0;
    } else {
        qCritical() << "保存失败:" << output;
        return 1;
    }
}
本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发 解决方案
相关文章 更多
C++动态数组初始化怎么写?常用语句与代码示例
C++动态数组初始化怎么写?常用语句与代码示例

深入解析C++中动态数组的初始化机制,涵盖new操作符的不同用法、基本类型与类对象的初始化差异,以及为何在现代C++开发中应优先使用std::vector。

加州大学圣地亚哥分校找到世界模型为何会
加州大学圣地亚哥分校找到世界模型为何会"说谎"的答案和解决方案

加州大学圣地亚哥分校研究发现世界模型产生幻觉的根源是训练数据覆盖不足,归纳为感知幻觉、动作边缘化幻觉和场景发散幻觉三类,并提出三种预测信号及覆盖感知训练、针对性数据收集两种干预方案。

行业首发「3+N」批量部署行业解决方案亮相WRC 2026
行业首发「3+N」批量部署行业解决方案亮相WRC 2026

WRC 2026 乐聚「3+N」全场景实干方案亮相2026年8月20日,世界机器人大会(WRC)于北京盛大开幕。乐聚机器人此次带来了行业首发的全栈国产化「3 + N」批量部署行业解决方案,其展台更是本届展会中唯一能实现全场景、全自主、全天候机器人不停机作业的。该展台展示内容涵盖科研、商服、工业三大领

跨越异构鸿沟,Redis迁移同步过程中的挑战与解决方案
跨越异构鸿沟,Redis迁移同步过程中的挑战与解决方案

随着云计算十余年的高速发展,作为目前可见的最新阶段,多云正在快步大踏步前进。而多云趋势所带来得数据云间迁移,也逐步常态化。因此,缓存 Redis 已成为高并发场景下提升数据访问速度的标配。不仅是数据云间迁移,目前大型系统对于缓存强依赖,致使大多数企业都会面临大量并发读写数据时访问速度慢、数据库压力大

云原生全链路灰度发布:阿里云MSE+ZadigX解决方案
云原生全链路灰度发布:阿里云MSE+ZadigX解决方案

01、企业发布现状痛点目前企业在选择和实施发布策略时面临以下困境:缺乏云原生能力:由于从传统部署转变为云原生模式后,技术架构改造需要具备相关能力的人才。这使得企业在发布策略方面难以入手。缺乏自动化平台支持:即使找到适合产品现状的发布策略,仍然依赖手工逐步执行。这可能导致流程遗漏或人工操作失误,造成生

破解器官移植供体短缺难题,组织器官生物制造未来将提供解决方案
破解器官移植供体短缺难题,组织器官生物制造未来将提供解决方案

杨华勇院士等专家探讨组织器官生物制造前沿进展。我国发明专利和科研产出居世界前列,骨科植入物等已进入临床。预计未来5-6年功能性皮肤、15-20年大型脏器、30年复杂器官有望临床应用。AI赋能与伦理问题引发关注。

南芯科技亮相慕展:高端消费全场景端到端解决方案
南芯科技亮相慕展:高端消费全场景端到端解决方案

南芯科技在2026慕尼黑上海电子展展出高端消费电子、汽车电子等产品线,覆盖AI眼镜、机器人、智能手机、笔记本电脑、电视、可穿戴及移动电源等领域,提供从电源管理到电机控制的端到端解决方案。

广立微打造3D IC 良率解决方案 助力韬定律生态发展
广立微打造3D IC 良率解决方案 助力韬定律生态发展

后摩尔时代,韬定律通过逻辑折叠、超细间距混合键合与TSV多层堆叠提升芯片性能,但面临键合缺陷、晶圆参数失配及DFT测试效率瓶颈。广立微打造涵盖DFM仿真、高速电性测试、AI晶圆配对及3D专用DFT的全链路国产方案,助力3DIC规模化量产。

Torna 1.35.6 & 2.1.20 发布,接口文档解决方案
Torna 1.35.6 & 2.1.20 发布,接口文档解决方案

Torna1.35.6与2.1.20版本发布,优化单值返回结果展示逻辑,修复接口名称为空时Tab标签消失问题,新增点击接口名称跳转预览页面,改进Markdown渲染。Torna是一款接口文档管理工具,支持多人协同编辑、多源文档统一归档,扩展了Swagger的易用性与集成性。

iPhone15软件删不掉怎么办?快速解决应用无法删除问题
iPhone15软件删不掉怎么办?快速解决应用无法删除问题

遇到iPhone15上的应用删不掉?别急,可以先强制重启设备,或者查查是不是屏幕使用时间给限制了。如果这俩办法都行不通,那么通过电脑上的iTunes(Windows)或Finder(Mac)来恢复系统,通常是解决问题的终极方案。 iPhone15应用删除失败的原因分析 你的iPhone15突然“挽留

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件
macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

Mac软件 更多
灵活计算器
灵活计算器
macOS/iOS/Android

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师
macOS

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

WINDOWS 更多
Windows 10
Windows 10
Windows

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式
Windows/macOS/Linux

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘
Windows/macOS/iOS/Android

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。