Qt 自定义代理类

一.使用步骤

  1. 继承QStyledItemDelegate类:首先创建一个新的类并继承自QStyledItemDelegate类,作为您的自定义代理类。

  2. 实现代理类的构造函数:在代理类中实现构造函数,并在构造函数中调用基类的构造函数,可以选择传入一个QObject类型的父对象。

  3. 重写需要定制的函数:根据您的需求,重写QStyledItemDelegate类中的需要进行定制的函数。常用的函数包括paint、sizeHint、createEditor等。根据您的需求决定需要重写哪些函数。

  4. 修改绘制逻辑(可选):在重写的paint函数中修改绘制逻辑,根据数据的类型或特定条件进行不同的绘制操作。例如,在上面的例子中,根据数据类型添加货币符号。

  5. 在视图中应用代理:将您自定义的代理类设置给视图部件的setItemDelegate()函数,这样视图中的数据显示就会按照您的定制进行展示。

  6. 调试和优化:在应用自定义代理后,可以进行调试和优化,确保显示效果符合预期。

二.具体实现 

1.继承QStyledItemDelegate类

class CurrencyDelegate : public QStyledItemDelegate
{
public:
    CurrencyDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent)
    {
    }
};

问题1:CurrencyDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent)参入如何传递

在上面的例子中,通过CurrencyDelegate类的构造函数,将parent参数传递给QStyledItemDelegate的构造函数,从而在实例化CurrencyDelegate时,也对QStyledItemDelegate进行了初始化。这种方式可以确保自定义代理类和基类之间的关联,使得自定义代理类可以继承QStyledItemDelegate的属性和行为。

2.对代理类进行实现

对继承的父类的函数进行重写。

//创建代理编辑器
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 updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override;

示例如下:

/创建代理组件的时候,调用这个虚函数
QWidget *QIntSalaryDelagate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //不使用参数
    Q_UNUSED(option);
    Q_UNUSED(index);



    QSpinBox*editor=new QSpinBox(parent);

    editor->setFrame(false);//无边框
    editor->setMinimum(2000);
    editor->setMaximum(100000);
    editor->setSingleStep(100);

    return editor;
}

void QIntSalaryDelagate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
   int value = index.model()->data(index).toInt();//数据模型中的数据

   QSpinBox*spinBox=static_cast<QSpinBox*>(editor);//这是上面创建的东西

   spinBox->setValue(value);


}

void QIntSalaryDelagate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{

     QSpinBox*spinBox=static_cast<QSpinBox*>(editor);//这是上面创建的东西

     spinBox->interpretText();//解释数据

     int value=spinBox->value();//获取编辑代理的值

     model->setData(index,value);

}

void QIntSalaryDelagate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    editor->setGeometry(option.rect);//就原来的位置
}

 代码解读:

int value = index.model()->data(index).toInt();

这段代码的作用是从数据模型中获取特定索引处的数据,并将其转换为整数类型。

  • index.model():通过QModelIndex对象的model()方法获取索引所属的数据模型。
  • data(index):通过数据模型的data()方法获取指定索引位置的数据。
  • toInt():将获取到的数据转换为整数类型。

因此,int value将存储从数据模型中获取的指定索引位置的数据,并转换为整数类型,以便在后续代码中使用。

问题: 代理就是对模型的数据进行二次加工,然后以另外一种方式放回到模型中吗

代理(Delegate)在模型视图编程中扮演着重要角色,用于对模型的数据进行二次加工或自定义呈现方式,使其能够以不同的方式呈现给视图控件(如表格、列表等)。代理常用于定制数据的展示形式、编辑方式或交互行为。

在您提供的代码中,QIntSalaryDelagate代理的setEditorData函数就是一个很好的例子。它通过获取模型中的数据并将其设置到编辑器小部件中,实现了以特定方式呈现数据给用户进行编辑的功能。编辑器中修改后的数据经过处理后可以再次存回到模型中。

因此,代理可用于数据的二次处理、自定义展示逻辑以及用户交互的控制,使模型能够以更灵活、符合需求的方式与视图进行交互。

三. static_cast<>介绍

static_cast<> 是 C++ 中的一种类型转换操作符,用于执行编译时的静态类型转换。它可以进行标准数据类型之间的转换(例如整数转换为浮点数)、基类指针或引用到派生类指针或引用的转换等。

QSpinBox* spinBox = static_cast<QSpinBox*>(editor);

 这行代码将 editor 作为 QWidget 类型的指针,转换为 QSpinBox 类型的指针。这种类型转换是在编译时进行的,因此需要开发者明确确认这两种类型之间存在继承或兼容关系,否则会造成编译错误。

 示例分析:

#include <iostream>

class Base {
public:
    virtual void display() {
        std::cout << "Base class" << std::endl;
    }
};

class Derived : public Base {
public:
    void display() override {
        std::cout << "Derived class" << std::endl;
    }
};

int main() {
    Base baseObj;
    Derived derivedObj;

    Base* basePtr = &derivedObj;
    Derived* derivedPtr = static_cast<Derived*>(basePtr);

    derivedPtr->display(); // Output: "Derived class"

    return 0;
}

在上面的示例中,我们创建了一个基类 Base 和一个派生类 Derived。通过将 Derived 类对象的地址赋给 Base 类指针,我们可以使用 static_cast 将其转换回 Derived 类指针,并调用 Derived 类的成员函数。

需要注意的是,对于存在多态的情况(基类有虚函数,派生类重写了这些虚函数),最好使用 dynamic_cast 进行转换,因为 dynamic_cast 运行时执行类型检查,能够确定是否安全进行类型转换。

问题1:int value = index.model()->data(index).toInt();

这行代码是将当前选定项目的数据从模型中读取,并将其转换为整数型。具体来说,代码中的工作步骤如下:

  1. 通过index.model()方法获取当前选定项目所在的模型。
  2. 调用data(index)方法获取当前选定项目的数据。
  3. 使用.toInt()方法将获取的数据转换为整数类型,并将结果存储在名为value的整型变量中。

这段代码通常会在Qt中的视图(例如QListView、QTableView等)中使用,用于从模型中获取特定项目的数据,并进行必要的处理或操作。

问题2:代理类每次只修改一次索引数据吗? 

Qt中的代理类通常是用来处理单个数据项的显示和编辑,而不是整体的数据修改。当涉及到列表视图(如QComboBox、QListView、QTreeView等)中多个数据项的修改时,代理类通常只会处理当前索引对应的数据项的显示和编辑,而不会直接修改整个数据模型。

代理类是用来解决特定单元格或项的展示和编辑问题的,例如在列表中显示不同格式的文本、使用自定义控件进行编辑等。代理类通过重写paint、createEditor、setEditorData和setModelData等方法,来实现对特定数据项的定制显示和编辑行为。

问题3:QcomboBox代理时的过程分析 

用户点击表格时,代理类会调用CreateEdit函数以展示用户选择的值。当用户最终确定索引后,代理会将当前的值设置到编辑器中,然后通过编辑器将值设置到模型中。这样用户就可以通过QComboBox来编辑表格中的数值。

用户选择时的值索引通常是QComboBox中的值。用户在QComboBox中选择一个选项,代理会将该选项在QComboBox中的索引作为值进行处理,并将其设置到编辑器中,然后根据用户的操作将该值传递到模型中。模型中可能保存着与QComboBox中选项对应的具体数值或其他数据,而在代理中会根据索引来获取相应的数据并进行处理

QWidget *JobDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QComboBox*editor=new QComboBox(parent);

    //设置属性
    QStringList list={"软件工程师","经理","程序员","助理"};
    editor->addItems(list);
    return editor;
}

void JobDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    
    Q_UNUSED(index);
    //设置编辑器数据
    QComboBox*combox=static_cast<QComboBox*>(editor);

    combox->setCurrentText(index.model()->data(index).toString());
}

void JobDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    //设置模型的数据

     QComboBox*combox=static_cast<QComboBox*>(editor);

     QString str=combox->currentText();


     model->setData(index,str);


}

JobDelegate::setEditorData 函数中的 index 参数代表的是要编辑的索引,通常是代理所管理的表格模型中的一个特定索引。在这里,index 参数表示要编辑的单元格在模型中的位置,而不是 QComboBox 控件本身的索引。

在这个函数中,index.model() 表示从 index 中获取对应的模型,然后通过 index.model()->data(index) 获取该索引位置的数据,并将其作为文本设置为 QComboBox 的当前文本内容。

因此,index.model() 不是指代 QComboBox 控件自身,而是指代表的是表格模型中的数据。代理类在这里是用来管理如何显示和编辑模型中数据的。

四.QComboBox作为其他组件的代理

#include <QComboBox>
#include <QStyledItemDelegate>
#include <QModelIndex>
#include <QVariant>
#include <QWidget>
#include <QPainter>
#include <QApplication>

class ComboBoxDelegate : public QStyledItemDelegate
{
public:
    ComboBoxDelegate(QObject *parent = nullptr)
        : QStyledItemDelegate(parent)
    {
    }

    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
    {
        QComboBox *editor = new QComboBox(parent);
        editor->addItem("Option 1");
        editor->addItem("Option 2");
        editor->addItem("Option 3");

        return editor;
    }

    void setEditorData(QWidget *editor, const QModelIndex &index) const override
    {
        QString value = index.model()->data(index, Qt::EditRole).toString();
        QComboBox *comboBox = qobject_cast<QComboBox *>(editor);
        comboBox->setCurrentText(value);
    }

    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
    {
        QComboBox *comboBox = qobject_cast<QComboBox *>(editor);
        QString value = comboBox->currentText();
        model->setData(index, value, Qt::EditRole);
    }

    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override
    {
        editor->setGeometry(option.rect);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QComboBox comboBox;
    comboBox.addItem("Item 1");
    comboBox.addItem("Item 2");
    comboBox.addItem("Item 3");

    comboBox.setItemDelegate(new ComboBoxDelegate(&comboBox));

    comboBox.show();

    return a.exec();
}

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值