Qt的复杂代理使用总结

简介: Qt的复杂代理使用总结

代理的基本使用


一般代理只需要继承QStyledItemDelegate类,然后重写createEditor,setEditorData和setModelData接口即可。

// COpratorDelegate.h
class COpratorDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    explicit COpratorDelegate(QObject *parent = nullptr, const ColType &type=STRING);
    QWidget *createEditor(QWidget *parent,  const QStyleOptionViewItem &option,
                                   const QModelIndex &index) const override;
    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
    void setModelData(QWidget *editor,  QAbstractItemModel *model,
                              const QModelIndex &index) const override;
private:
    CModel *_pModel = nullptr;
};


在createEditor中创建控件,然后返回,在setEditorData中从模型中获取数据,然后填充到控件中,setModelData从控件中获取数据设置到model中。


在view中使用代理,如下:

COpratorDelegate *pCOD = new COpratorDelegate(_pTableView, COpratorDelegate::MULBTN);
_pTableView->setItemDelegateForColumn(1, pCOD);


在代理中使用复杂控件


在代理中使用复杂控件,比如使用布局添加多个控件,如下:

// 创建一个多按键的QWidget页面, MulBtnWiget.h
class MulBtnWiget : public QWidget
{
    Q_OBJECT
public:
    explicit MulBtnWiget(const QModelIndex &index, QWidget *parent = nullptr);
    void setBtnData(const QVariant &data);
signals:
    void btnColor(const QString &color, const int &row);
private:
    QPushButton *_pButton1;
    QPushButton *_pButton2;
    QPushButton *_pButton3;
    QModelIndex _index;
};


此页面包含三个按钮,分别为红色,绿色和重置,用来改变颜色,如下:

MulBtnWiget::MulBtnWiget(const QModelIndex &index, QWidget *parent/* = nullptr*/)
    : QWidget(parent), _index(index)
{
    QHBoxLayout *pLayout = new QHBoxLayout();
    _pButton1 = new QPushButton("red");
    pLayout->addWidget(_pButton1);
    _pButton2 = new QPushButton("green");
    pLayout->addWidget(_pButton2);
    _pButton3 = new QPushButton("reset");
    pLayout->addWidget(_pButton3);
    pLayout->setContentsMargins(0, 0, 0, 0);
    this->setLayout(pLayout);
    this->setContentsMargins(0, 0, 0, 0);
    _pButton1->setEnabled(false);
    _pButton2->setEnabled(false);
    _pButton3->setEnabled(false);
    _pButton1->setStyleSheet("color: red;");
    _pButton2->setStyleSheet("color: green;");
    _pButton3->setStyleSheet("color: black;");
    connect(_pButton1, &QPushButton::clicked, this, [this](){
        emit btnColor("red", _index.row());
    });
    connect(_pButton2, &QPushButton::clicked, this, [this](){
        emit btnColor("green", _index.row());
    });
    connect(_pButton3, &QPushButton::clicked, this, [this](){
        emit btnColor("black", _index.row());
    });
}


创建了这个页面之后,可以使用这个页面作为代理,使用的方式非常简单,直接new出来,然后返回即可:

QWidget *COpratorDelegate::createEditor(QWidget *parent,
                                        const QStyleOptionViewItem &option,
                                        const QModelIndex &index) const
{
    MulBtnWiget *pMulBtnWidget = new MulBtnWiget(index, parent);
    return pMulBtnWidget;
}


使用这种方式既可以使用复杂的控件代理,如果需要使用数据进行设置,只需要定义一个数据类,然后注册,如下:

struct Person
{
    int id;
    QString name;
    qint8 age;
 };
 Q_DECLARE_METATYPE(Person)


但是这种情况只有在双击的时候代理才会显示,如果需要一直显示,或者在标题栏中是无法实现的。


让代理一直显示


使用自绘的方式


使用自绘的方式主要是paint和editorEvent两个接口,自己手动绘制,这种方式最原始的方案,但是面对复杂的布局和多个控件的时候就比较麻烦。如下:


还可以参考Qt的例子: Star Delegate example 的实现,网上大部分添加一直显示的控件就是使用此方式实现的。


使用View的接口设置一直显示


针对代理一直显示,Qt的View中三个接口能完成此事,分别为: openPersistentEditor(), closePersistentEditor() 和 isPersistentEditorOpen()方法。使用方法非常简单:

_pTableView->openPersistentEditor(pModel->index(1, 1));


比如需要给某一列进行设置就可以使用循环遍历所有列进行设置即可。但是,在使用排序过滤QSortFilterProxyModel会导致设置的一直显示失效, 主要原因在于通过_pTableView->model()获取的model已经是QSortFilterProxyModel,因此设置的索引不对,排序过滤后导致,需要将真正的数据类模型指针传递到代理中,并且过滤时手动调用openPersistentEditor接口。


最终实现的结果展示



至于自定义QHeaderView参考: https://blog.csdn.net/beichen_yx/article/details/105599995


示例代码


// CDelegate.h
#ifndef CDELEGATE_H
#define CDELEGATE_H
#include <QObject>
#include <QStyledItemDelegate>
#include <QWidget>
#include <QComboBox>
#include <QProgressBar>
class QWidget;
class QVariant;
class QPushButton;
class CModel;
class MulBtnWiget : public QWidget
{
    Q_OBJECT
public:
    explicit MulBtnWiget(const QModelIndex &index, QWidget *parent = nullptr);
    void setBtnData(const QVariant &data);
signals:
    void btnColor(const QString &color, const int &row);
private:
    QPushButton *_pButton1;
    QPushButton *_pButton2;
    QPushButton *_pButton3;
    QModelIndex _index;
};
class COpratorDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    enum ColType {
        STRING,
        COMBOBOX,
        PROGRESSBAR,
        MULBTN
    };
    explicit COpratorDelegate(QObject *parent = nullptr, const ColType &type=STRING);
    QWidget *createEditor(QWidget *parent,
                          const QStyleOptionViewItem &option,
                          const QModelIndex &index) const override;
    void setEditorData(QWidget *editor, const QModelIndex &index) const override;
    void setModelData(QWidget *editor,
                      QAbstractItemModel *model,
                      const QModelIndex &index) const override;
    void setCModel(CModel * const pModel) { _pModel = pModel; }
signals:
    void btnColor(const QString &color, const QModelIndex &index);
private:
    CModel *_pModel = nullptr;
    ColType _colType = STRING;
};
#endif // CDELEGATE_H
#include "CDelegate.h"
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVariant>
#include "CModel/CModel.h"
MulBtnWiget::MulBtnWiget(const QModelIndex &index, QWidget *parent/* = nullptr*/)
    : QWidget(parent), _index(index)
{
    QHBoxLayout *pLayout = new QHBoxLayout();
    _pButton1 = new QPushButton("red");
    pLayout->addWidget(_pButton1);
    _pButton2 = new QPushButton("green");
    pLayout->addWidget(_pButton2);
    _pButton3 = new QPushButton("reset");
    pLayout->addWidget(_pButton3);
    pLayout->setContentsMargins(0, 0, 0, 0);
    this->setLayout(pLayout);
    this->setContentsMargins(0, 0, 0, 0);
    _pButton1->setEnabled(false);
    _pButton2->setEnabled(false);
    _pButton3->setEnabled(false);
    _pButton1->setStyleSheet("color: red;");
    _pButton2->setStyleSheet("color: green;");
    _pButton3->setStyleSheet("color: black;");
    connect(_pButton1, &QPushButton::clicked, this, [this](){
        emit btnColor("red", _index.row());
    });
    connect(_pButton2, &QPushButton::clicked, this, [this](){
        emit btnColor("green", _index.row());
    });
    connect(_pButton3, &QPushButton::clicked, this, [this](){
        emit btnColor("black", _index.row());
    });
}
void MulBtnWiget::setBtnData(const QVariant &data)
{
    int type = qvariant_cast<int>(data);
    if (type <= 3) {
        _pButton1->setEnabled(true);
        _pButton2->setEnabled(true);
        _pButton3->setEnabled(true);
        _pButton1->setStyleSheet("color: red;");
        _pButton2->setStyleSheet("color: green;");
    } else if (type >3 && type <=4) {
        _pButton1->setEnabled(false);
        _pButton1->setStyleSheet("color: black;");
        _pButton2->setEnabled(true);
        _pButton3->setEnabled(true);
    } else {
        _pButton1->setEnabled(true);
        _pButton2->setEnabled(false);
        _pButton2->setStyleSheet("color: black;");
        _pButton3->setEnabled(true);
    }
}
COpratorDelegate::COpratorDelegate(QObject *parent/* = nullptr*/,
                                   const ColType &type/*=STRING*/)
    : QStyledItemDelegate(parent),
      _colType(type)
{
}
QWidget *COpratorDelegate::createEditor(QWidget *parent,
                                        const QStyleOptionViewItem &option,
                                        const QModelIndex &index) const
{
    if (_colType == STRING) {
        return QStyledItemDelegate::createEditor(parent, option, index);
    } else if (_colType == COMBOBOX) {
        auto *pCbx = new QComboBox(parent);
        pCbx->addItems({"test1", "test1", "test2", "test3"});
        return pCbx;
    } else if (_colType == PROGRESSBAR) {
        auto *pProgressbar = new QProgressBar(parent);
        pProgressbar->setRange(0, 10);
        return pProgressbar;
    } else if (_colType == MULBTN) {
        MulBtnWiget *pMulBtnWidget = new MulBtnWiget(index, parent);
        connect(pMulBtnWidget, &MulBtnWiget::btnColor, this,
                [this](const QString &color, const int &row){
            // index.model()返回的模型不一定是自定义的数据模型,可能是代理模型
            if (_pModel == nullptr) { return; }
            _pModel->setRowColor(row, color);
        });
        return pMulBtnWidget;
    } else {
        return QStyledItemDelegate::createEditor(parent, option, index);
    }
}
void COpratorDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if (_colType == STRING) {
    } else if (_colType == COMBOBOX) {
        QComboBox *pWidget = qobject_cast<QComboBox*>(editor);
        auto tmp = QString::number(index.data().toInt());
        if (pWidget->findText(tmp) < 0) {
            pWidget->addItem(tmp);
        }
        pWidget->setCurrentText(tmp);
    } else if (_colType == PROGRESSBAR) {
        QProgressBar *pWidget = qobject_cast<QProgressBar*>(editor);
        pWidget->setValue(index.data().toInt());
    } else if (_colType == MULBTN) {
        MulBtnWiget *pWidget = qobject_cast<MulBtnWiget*>(editor);
        pWidget->setBtnData(index.data());
    } else {
    }
}
void COpratorDelegate::setModelData(QWidget *editor,
                                    QAbstractItemModel *model,
                                    const QModelIndex &index) const
{
    QStyledItemDelegate::setModelData(editor, model, index);
}
#include "CDelegate.h"
#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVariant>
#include "CModel/CModel.h"
MulBtnWiget::MulBtnWiget(const QModelIndex &index, QWidget *parent/* = nullptr*/)
    : QWidget(parent), _index(index)
{
    QHBoxLayout *pLayout = new QHBoxLayout();
    _pButton1 = new QPushButton("red");
    pLayout->addWidget(_pButton1);
    _pButton2 = new QPushButton("green");
    pLayout->addWidget(_pButton2);
    _pButton3 = new QPushButton("reset");
    pLayout->addWidget(_pButton3);
    pLayout->setContentsMargins(0, 0, 0, 0);
    this->setLayout(pLayout);
    this->setContentsMargins(0, 0, 0, 0);
    _pButton1->setEnabled(false);
    _pButton2->setEnabled(false);
    _pButton3->setEnabled(false);
    _pButton1->setStyleSheet("color: red;");
    _pButton2->setStyleSheet("color: green;");
    _pButton3->setStyleSheet("color: black;");
    connect(_pButton1, &QPushButton::clicked, this, [this](){
        emit btnColor("red", _index.row());
    });
    connect(_pButton2, &QPushButton::clicked, this, [this](){
        emit btnColor("green", _index.row());
    });
    connect(_pButton3, &QPushButton::clicked, this, [this](){
        emit btnColor("black", _index.row());
    });
}
void MulBtnWiget::setBtnData(const QVariant &data)
{
    int type = qvariant_cast<int>(data);
    if (type <= 3) {
        _pButton1->setEnabled(true);
        _pButton2->setEnabled(true);
        _pButton3->setEnabled(true);
        _pButton1->setStyleSheet("color: red;");
        _pButton2->setStyleSheet("color: green;");
    } else if (type >3 && type <=4) {
        _pButton1->setEnabled(false);
        _pButton1->setStyleSheet("color: black;");
        _pButton2->setEnabled(true);
        _pButton3->setEnabled(true);
    } else {
        _pButton1->setEnabled(true);
        _pButton2->setEnabled(false);
        _pButton2->setStyleSheet("color: black;");
        _pButton3->setEnabled(true);
    }
}
COpratorDelegate::COpratorDelegate(QObject *parent/* = nullptr*/,
                                   const ColType &type/*=STRING*/)
    : QStyledItemDelegate(parent),
      _colType(type)
{
}
QWidget *COpratorDelegate::createEditor(QWidget *parent,
                                        const QStyleOptionViewItem &option,
                                        const QModelIndex &index) const
{
    if (_colType == STRING) {
        return QStyledItemDelegate::createEditor(parent, option, index);
    } else if (_colType == COMBOBOX) {
        auto *pCbx = new QComboBox(parent);
        pCbx->addItems({"test1", "test1", "test2", "test3"});
        return pCbx;
    } else if (_colType == PROGRESSBAR) {
        auto *pProgressbar = new QProgressBar(parent);
        pProgressbar->setRange(0, 10);
        return pProgressbar;
    } else if (_colType == MULBTN) {
        MulBtnWiget *pMulBtnWidget = new MulBtnWiget(index, parent);
        connect(pMulBtnWidget, &MulBtnWiget::btnColor, this,
                [this](const QString &color, const int &row){
            // index.model()返回的模型不一定是自定义的数据模型,可能是代理模型
            if (_pModel == nullptr) { return; }
            _pModel->setRowColor(row, color);
        });
        return pMulBtnWidget;
    } else {
        return QStyledItemDelegate::createEditor(parent, option, index);
    }
}
void COpratorDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if (_colType == STRING) {
    } else if (_colType == COMBOBOX) {
        QComboBox *pWidget = qobject_cast<QComboBox*>(editor);
        auto tmp = QString::number(index.data().toInt());
        if (pWidget->findText(tmp) < 0) {
            pWidget->addItem(tmp);
        }
        pWidget->setCurrentText(tmp);
    } else if (_colType == PROGRESSBAR) {
        QProgressBar *pWidget = qobject_cast<QProgressBar*>(editor);
        pWidget->setValue(index.data().toInt());
    } else if (_colType == MULBTN) {
        MulBtnWiget *pWidget = qobject_cast<MulBtnWiget*>(editor);
        pWidget->setBtnData(index.data());
    } else {
    }
}
void COpratorDelegate::setModelData(QWidget *editor,
                                    QAbstractItemModel *model,
                                    const QModelIndex &index) const
{
    QStyledItemDelegate::setModelData(editor, model, index);
}
#include "CModel/CModel.h"
#include <ctime>
#include <algorithm>
#include <QDebug>
CModel::CModel(QAbstractItemModel *parent) : QAbstractItemModel(parent)
{
    for (int i=0; i<10; ++i) {
        m_stocks.append({i, i*100, rand() % 100, rand() % 300, i, i});
        _colors.append(QColor(Qt::black));
    }
}
void CModel::setRowColor(const int &row, const QString &color)
{
    QColor txtColor;
    if (color == "red") {
        txtColor = Qt::red;
    } else if (color == "green") {
        txtColor = Qt::green;
    } else {
        txtColor = Qt::black;
    }
    _colors[row] = txtColor;
    auto start = this->index(row, 0);
    auto end = this->index(row, this->columnCount(QModelIndex()) - 1);
    emit dataChanged(start, end);
}
int CModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_stocks.length();
}
int CModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_names.length();
}
QVariant CModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid()){
        qDebug() << "index is valid: " << index.row() << ":" << index.column();
        return QVariant();
    }
    if(index.row() > m_stocks.length() || index.column() > m_names.length()){
        qDebug() << "m_stocks len: " << m_stocks.length() << " " << index.row() << ":" << index.column();
        return QVariant();
    }
    if(role == Qt::DisplayRole){
        auto stock = m_stocks.at(index.row());
        return (index.column() > stock.length() || index.column() < 0) ? QVariant() : stock.at(index.column());
    } else if(role == Qt::EditRole){
        auto stock = m_stocks.at(index.row());
        return (index.column() > stock.length() || index.column() < 0) ? QVariant() : stock.at(index.column());
    } else if (role == Qt::TextColorRole) {
        return QVariant(_colors.at(index.row()));
    } else if (role == Qt::TextAlignmentRole) {
        return QVariant(Qt::AlignCenter|Qt::AlignVCenter);
    }
    return QVariant();
}
bool CModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid()){
        qDebug() << "index is valid: " << index.row() << ":" << index.column();
        return false;
    }
    if(role == Qt::EditRole){
        auto stock = m_stocks.at(index.row());
        stock[index.column()] = value;
        emit dataChanged(index, index);
        return true;
    }
    return false;
}
QVariant CModel::headerData(int section, Qt::Orientation orientation, int role) const
{
//    if(role != Qt::DisplayRole){
//        return QVariant();
//    }
//    if(orientation == Qt::Horizontal){
//        if(section < 0 || section > m_names.length()){return  QVariant();}
//        return QVariant(m_names.at(section));
//    }else {
//        return QVariant(QString::number(section));
//    }
    if(orientation == Qt::Horizontal){
        if (role == Qt::DisplayRole) {
            return QVariant(m_names.at(section));
        } else {
           qDebug() << role;
        }
    } else if (orientation == Qt::Vertical) {
        if (role == Qt::DisplayRole) {
            return QVariant(QString::number(section));
        }
    }
    return QVariant();
}
bool CModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{
    if(role != Qt::EditRole){
        return false;
    }
    if(orientation == Qt::Horizontal){
        m_names.replace(section, value.toString());
        emit headerDataChanged(Qt::Horizontal, section, section);
        return true;
    }else{
        return false;
    }
}
Qt::ItemFlags CModel::flags(const QModelIndex &index) const
{
//    if(index.isValid()){
//         Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemNeverHasChildren | Qt::ItemIsEditable;
//         return flags;
//    }
//    return QAbstractItemModel::flags(index);
    if(index.isValid()){
        Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable
                | Qt::ItemNeverHasChildren | Qt::ItemIsEditable;
        return flags | QAbstractItemModel::flags(index);
    }
    return QAbstractItemModel::flags(index);
}
QModelIndex CModel::index(int row, int column, const QModelIndex &parent) const
{
    if (row < 0 || column < 0 || column >= columnCount(parent) || column > m_names.length())
        return QModelIndex();
    return createIndex(row,column);
}
QModelIndex CModel::parent(const QModelIndex &child) const
{
    Q_UNUSED(child);
    return QModelIndex();
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "CView/CTableView.h"
#include "CModel/CModel.h"
#include "CDelegate/CDelegate.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    _pTableView(new CTableView(this)),
    _pModel(new CModel())
{
    ui->setupUi(this);
    this->setWindowTitle("Custom MVC");
    this->setCentralWidget(_pTableView);
    this->setContentsMargins(0, 0, 0, 0);
    _pTableView->setModel(_pModel);
    this->initUi();
    this->resize(1024, 768);
}
MainWindow::~MainWindow()
{
    delete ui;
    delete _pModel;
    delete _pTableView;
}
void MainWindow::initUi()
{
    int colCount = _pModel->columnCount(_pModel->index(0, 0));
    _pTableView->resizeColumnsToContents();
    for (int i=0; i<colCount; ++i) {
        _pTableView->setColumnWidth(i, 300);
    }
    COpratorDelegate *pCOD = new COpratorDelegate(_pTableView, COpratorDelegate::MULBTN);
    pCOD->setCModel(_pModel);
    _pTableView->setItemDelegateForColumn(colCount - 1, pCOD);
    auto *pModel = _pTableView->model();
    int row = pModel->rowCount();
    for (int i=0; i<row; ++i) {
        _pTableView->openPersistentEditor(pModel->index(i, colCount - 1));
    }
    _columns.append(colCount - 1);
    COpratorDelegate *pProcessCOD = new COpratorDelegate(_pTableView, COpratorDelegate::PROGRESSBAR);
    pProcessCOD->setCModel(_pModel);
    _pTableView->setItemDelegateForColumn(colCount - 2, pProcessCOD);
    for (int i=0; i<row; ++i) {
        _pTableView->openPersistentEditor(pModel->index(i, colCount - 2));
    }
    _columns.append(colCount - 2);
    COpratorDelegate *pCbxCOD = new COpratorDelegate(_pTableView, COpratorDelegate::COMBOBOX);
    pCbxCOD->setCModel(_pModel);
    _pTableView->setItemDelegateForColumn(colCount - 3, pCbxCOD);
    for (int i=0; i<row; ++i) {
        _pTableView->openPersistentEditor(pModel->index(i, colCount - 3));
    }
    _columns.append(colCount - 3);
    connect(_pTableView, &CTableView::filterUpdate, this,  &MainWindow::openPersistentForColumns );
}
void MainWindow::openPersistentForColumns()
{
    auto *pModel = _pTableView->model();
    int row = _pModel->rowCount();
    for (int i=0; i<row; ++i) {
        for (int &col : _columns) {
            _pTableView->openPersistentEditor(pModel->index(i, col));
        }
    }
}


详细代码参见: https://gitee.com/BeiChen_XQ/custom-delegate.git

相关文章
|
6月前
|
监控 数据可视化 Linux
Qt Model&View&Delegate(模型-视图-代理) 介绍和使用
Qt Model&View&Delegate(模型-视图-代理) 介绍和使用
Qt Model&View&Delegate(模型-视图-代理) 介绍和使用
|
5月前
|
XML JSON 前端开发
Qt委托代理机制之《Model/View/Delegate使用方法》
Qt委托代理机制之《Model/View/Delegate使用方法》
457 1
|
6月前
|
C++
【qt】自定义代理类
【qt】自定义代理类
59 0
|
6月前
Qt表格中的自定义编辑组件---------------自定义代理QStyledItemDelegate
Qt表格中的自定义编辑组件---------------自定义代理QStyledItemDelegate
77 5
|
SQL 关系型数据库 数据库连接
2.关于QT中数据库操作,简单数据库连接操作,数据库的增删改查,QSqlTableModel和QTableView,事务操作,关于QItemDelegate 代理
 Linux下的qt安装,命令时:sudoapt-get install qt-sdk 安装mysql数据库,安装方法参考博客:http://blog.csdn.net/tototuzuoquan/article/details/39565783 如果行想进数据库开发,需要安装libqt5sql5-mysql.命令是: sudo apt-g
4369 0
|
4月前
|
数据安全/隐私保护 C++ 计算机视觉
Qt(C++)开发一款图片防盗用水印制作小工具
文本水印是一种常用的防盗用手段,可以将文本信息嵌入到图片、视频等文件中,用于识别和证明文件的版权归属。在数字化和网络化的时代,大量的原创作品容易被不法分子盗用或侵犯版权,因此加入文本水印成为了保护原创作品和维护知识产权的必要手段。 通常情况下,文本水印可以包含版权声明、制作者姓名、日期、网址等信息,以帮助识别文件的来源和版权归属。同时,为了增强防盗用效果,文本水印通常会采用字体、颜色、角度等多种组合方式,使得水印难以被删除或篡改,有效地降低了盗用意愿和风险。 开发人员可以使用图像处理技术和编程语言实现文本水印的功能,例如使用Qt的QPainter类进行文本绘制操作,将文本信息嵌入到图片中,
181 1
Qt(C++)开发一款图片防盗用水印制作小工具
|
3月前
|
监控 C++ 容器
【qt】MDI多文档界面开发
【qt】MDI多文档界面开发
88 0
|
2月前
|
开发工具 C++
qt开发技巧与三个问题点
本文介绍了三个Qt开发中的常见问题及其解决方法,并提供了一些实用的开发技巧。
|
2月前