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

一、解决方案架构

1.1 技术选型比较

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

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


二、核心实现方案

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

这是最轻量、最易集成的方案,纯C++实现,无任何依赖。

2.1.1 下载qrcode库
bash 复制代码
# 下载qrcode库
git clone https://github.com/nayuki/QR-Code-generator.git
2.1.2 Qt项目集成

文件结构:

复制代码
QRCodeDemo/
├── main.cpp
├── QRCodeWidget.h
├── QRCodeWidget.cpp
├── qrcode/
│   ├── BitBuffer.hpp
│   ├── QrCode.hpp
│   ├── QrSegment.hpp
│   └── README.md
└── QRCodeDemo.pro

QRCodeWidget.h:

cpp 复制代码
#ifndef QRCODEWIDGET_H
#define QRCODEWIDGET_H

#include <QWidget>
#include <QImage>
#include <QString>
#include <QPen>
#include <QBrush>

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 saveToFile(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<uint8_t> m_qrData;
};
#endif // QRCODEWIDGET_H

QRCodeWidget.cpp:

cpp 复制代码
#include "QRCodeWidget.h"
#include "qrcode/QrCode.hpp"
#include <QPainter>
#include <QPainterPath>
#include <QLinearGradient>
#include <QFile>
#include <QDebug>

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<uint8_t> data(utf8Data.begin(), utf8Data.end());
        
        // 创建QR码
        QrCode::Ecc ecc = static_cast<QrCode::Ecc>(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::saveToFile(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.save(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:

cpp 复制代码
#include "MainWindow.h"
#include <QApplication>

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的二维码处理库,支持生成和解码。

2.2.1 安装QZXing
bash 复制代码
# 方法1:通过vcpkg
vcpkg install qzxing

# 方法2:手动编译
git clone https://github.com/ftylitak/qzxing.git
cd qzxing
mkdir build && cd build
cmake ..
make
make install
2.2.2 使用QZXing生成二维码
cpp 复制代码
// QZXingGenerator.h
#ifndef QZXINGGENERATOR_H
#define QZXINGGENERATOR_H

#include <QObject>
#include <QImage>
#include <QColor>
#include <QZXing.h>

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<QImage> batchGenerate(const QStringList& dataList, 
                               const QSize& size = QSize(200, 200));
    
    // 保存到文件
    bool saveQRCode(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
cpp 复制代码
// QZXingGenerator.cpp
#include "QZXingGenerator.h"
#include <QPainter>
#include <QBuffer>
#include <QDebug>

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<QImage> QZXingGenerator::batchGenerate(const QStringList& dataList, 
                                            const QSize& size) {
    QList<QImage> result;
    
    for (const QString& data : dataList) {
        QImage qrCode = generateQRCode(data, size);
        if (!qrCode.isNull()) {
            result.append(qrCode);
        }
    }
    
    return result;
}

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

2.3 方案三:使用libqrencode

这是一个C语言的二维码生成库,性能优秀。

2.3.1 安装libqrencode
bash 复制代码
# Ubuntu/Debian
sudo apt-get install libqrencode-dev

# macOS
brew install qrencode

# Windows (vcpkg)
vcpkg install qrencode
2.3.2 libqrencode封装
cpp 复制代码
// LibQRencodeWrapper.h
#ifndef LIBQRENCODEWRAPPER_H
#define LIBQRENCODEWRAPPER_H

#include <QImage>
#include <QString>
#include <qrencode.h>

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
cpp 复制代码
// LibQRencodeWrapper.cpp
#include "LibQRencodeWrapper.h"
#include <QPainter>
#include <QDebug>

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<QRecLevel>(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 主窗口设计

cpp 复制代码
// MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QImage>
#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 onSaveClicked();
    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 saveSettings();
    
private:
    Ui::MainWindow *ui;
    QRCodeWidget *m_qrCodeWidget;
    QImage m_logoImage;
    QTimer *m_previewTimer;
};
#endif // MAINWINDOW_H
cpp 复制代码
// MainWindow.cpp
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
#include <QTimer>
#include <QClipboard>
#include <QApplication>

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() {
    saveSettings();
    delete ui;
}

void MainWindow::setupUI() {
    // 设置中心窗口
    setCentralWidget(m_qrCodeWidget);
    
    // 创建工具栏
    QToolBar *toolBar = addToolBar("Main");
    toolBar->setMovable(false);
    
    toolBar->addAction("生成", this, &MainWindow::onGenerateClicked);
    toolBar->addAction("保存", this, &MainWindow::onSaveClicked);
    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->btnSave, &QPushButton::clicked, 
            this, &MainWindow::onSaveClicked);
    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::onSaveClicked() {
    if (m_qrCodeWidget->getQRCodeImage().isNull()) {
        QMessageBox::warning(this, "警告", "没有可保存的二维码");
        return;
    }
    
    QString filter = "PNG 图片 (*.png);;JPEG 图片 (*.jpg *.jpeg);;BMP 图片 (*.bmp)";
    QString filename = QFileDialog::getSaveFileName(this, "保存二维码", 
                                                   "qrcode.png", filter);
    
    if (!filename.isEmpty()) {
        int scale = ui->spinScale->value();
        QString format = QFileInfo(filename).suffix().toUpper();
        
        if (m_qrCodeWidget->saveToFile(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::saveSettings() {
    QSettings settings;
    
    // 保存窗口位置和大小
    settings.setValue("geometry", saveGeometry());
    
    // 保存当前内容
    settings.setValue("lastContent", ui->textContent->toPlainText());
}

3.2 UI界面设计 (ui_MainWindow.h)

cpp 复制代码
// UI设计文件 (通过Qt Designer创建)
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QWidget>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QTextEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QSpinBox>
#include <QtWidgets/QLabel>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QProgressBar>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QDockWidget>

class Ui_MainWindow {
public:
    QWidget *centralWidget;
    QVBoxLayout *verticalLayout;
    QHBoxLayout *horizontalLayout;
    QVBoxLayout *leftLayout;
    QTextEdit *textContent;
    QHBoxLayout *buttonLayout;
    QPushButton *btnGenerate;
    QPushButton *btnSave;
    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);
        
        btnSave = new QPushButton(centralWidget);
        btnSave->setObjectName(QString::fromUtf8("btnSave"));
        btnSave->setText("保存");
        buttonLayout->addWidget(btnSave);
        
        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 批量生成工具

cpp 复制代码
// BatchQRCodeGenerator.h
#ifndef BATCHQRCODEGENERATOR_H
#define BATCHQRCODEGENERATOR_H

#include <QObject>
#include <QRunnable>
#include <QThreadPool>
#include <QMap>

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<BatchItem>& 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<BatchItem> m_items;
    QString m_outputDir;
    QThreadPool m_threadPool;
};
#endif // BATCHQRCODEGENERATOR_H

4.2 二维码解码功能

cpp 复制代码
// QRCodeDecoder.h
#ifndef QRCODEDECODER_H
#define QRCODEDECODER_H

#include <QObject>
#include <QImage>
#include <QZXing.h>

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 样式化二维码

cpp 复制代码
// StyledQRCodeGenerator.h
#ifndef STYLEDQRCODEGENERATOR_H
#define STYLEDQRCODEGENERATOR_H

#include <QImage>

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 复制代码
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)

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 资源文件

xml 复制代码
<!-- resources.qrc -->
<RCC>
    <qresource prefix="/">
        <!-- 图标 -->
        <file>icons/app.png</file>
        <file>icons/generate.png</file>
        <file>icons/save.png</file>
        <file>icons/clear.png</file>
        <file>icons/logo.png</file>
        
        <!-- 样式表 -->
        <file>styles/style.qss</file>
        
        <!-- Logo示例 -->
        <file>logo/default.png</file>
    </qresource>
</RCC>
css 复制代码
/* 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;
}

参考代码 Qt非常实用的二维码生成代码 www.youwenfan.com/contentcsv/103314.html

六、使用示例

6.1 基本使用

cpp 复制代码
#include "QRCodeGenerator.h"
#include <QApplication>
#include <QDebug>

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.save("qrcode.png");
        
        // 显示二维码
        QLabel label;
        label.setPixmap(QPixmap::fromImage(qrCode));
        label.show();
        
        return app.exec();
    }
    
    return 0;
}

6.2 高级功能

cpp 复制代码
// 高级使用示例
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<BatchQRCodeGenerator::BatchItem> 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 命令行工具

cpp 复制代码
// QRCodeCLI.cpp - 命令行工具
#include "QRCodeGenerator.h"
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QFileInfo>

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.save(output)) {
        qInfo() << "二维码已保存到:" << output;
        return 0;
    } else {
        qCritical() << "保存失败:" << output;
        return 1;
    }
}
相关推荐
神仙别闹1 小时前
基于 Python 实现 ANN 与 KNN 的图像分类
开发语言·python·分类
_小许_1 小时前
Go语言导入与导出excel文件
开发语言·golang·excel
SilentSamsara1 小时前
高并发 API 压测与调优:locust + 火焰图 + 瓶颈定位
开发语言·python·青少年编程·docker·中间件
myenjoy_11 小时前
开源!Go+Wails+Vue3 手搓一个 PLC 实时监控桌面工具
开发语言·golang·开源
Flash.kkl1 小时前
C++基于websocketpp的多用户网页五子棋项目
开发语言·网络·数据库·c++·websocket·mysql
酉鬼女又兒1 小时前
零基础入门计算机网络物理层:核心概念、传输媒体、传输方式、编码调制与信道极限容量完整知识点总结
开发语言·网络·计算机网络·考研·职场和发展·php·信息与通信
曾几何时`2 小时前
Go(四)Channel
开发语言·后端·golang
未若君雅裁2 小时前
Java 线程基础:进程、线程、并发并行、创建方式与生命周期
java·开发语言
sugar__salt2 小时前
JS正则表达式与字符串高阶实战精讲
开发语言·javascript·正则表达式