基于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;
    }
}
相关推荐
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner1 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz6 天前
QML Hello World 入门示例
qt
xcyxiner9 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner10 天前
DicomViewer (添加模型类)3
qt
xcyxiner11 天前
DicomViewer (目录调整) 2
qt
xcyxiner11 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00613 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术13 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript