首页 > 数据库 >【Qt初入江湖】Qt QSqlRelationalDelegate 底层架构、原理详细描述

【Qt初入江湖】Qt QSqlRelationalDelegate 底层架构、原理详细描述

时间:2023-09-03 21:34:25浏览次数:44  
标签:index Qt 表格 QSqlRelationalDelegate 初入 字段 relModel


鱼弦:全栈领域创作新星创作者 、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)

【Qt初入江湖】Qt QSqlRelationalDelegate 底层架构、原理详细描述_字段

 

Qt 的 QSqlRelationalDelegate 类是用于在 Qt 模型/视图框架中使用带有外键关系的数据库表格数据的委托类。它提供了一组用于在表格视图中显示和编辑包含外键关系的数据库表格数据的函数和方法。

 

下面是 QSqlRelationalDelegate 类的底层架构图:

+----------------------+
|   QSqlRelationalDelegate |
+----------------------+
| - model              |
+----------------------+
          /_\
           |
           | 继承
           |
+----------------------+
|   QStyledItemDelegate |
+----------------------+

在这个架构中,QSqlRelationalDelegate 类是对一个包含外键关系的数据库表格的抽象,它包含了与该表格相关的模型信息。QStyledItemDelegate 类是 QSqlRelationalDelegate 类的基类,它实现了在 Qt 模型/视图框架中使用委托类的基本功能。

QSqlRelationalDelegate 类主要用于实现外键关系的编辑功能。它可以将外键列的值显示为一个可编辑的下拉框,其中包含了参考表格中的所有选项。当用户选择了一个选项时,QSqlRelationalDelegate 类会将其对应的值保存到外键列中,并将显示的值转换为参考表格中的值。

Qt QSqlRelationalDelegate是Qt中用于实现关系表格的委托类,它继承自QStyledItemDelegate。Qt QSqlRelationalDelegate提供了在关系表格中显示和编辑关联字段的功能。在本文中,我们将详细介绍Qt QSqlRelationalDelegate的底层架构、原理和实现方法。

Qt QSqlRelationalDelegate的底层架构和Qt QSqlRelationalTableModel类似,不同之处在于QSqlRelationalDelegate不需要设置要操作的数据库表格,而是通过关联字段来实现关系表格的显示和编辑。Qt QSqlRelationalDelegate通过QSqlRelationalTableModel类来获取关联字段的信息,并将关联字段的值和描述显示在关系表格中。Qt QSqlRelationalDelegate还封装了一些方法,用于处理关系表格中的编辑操作。

在Qt中,我们可以使用以下方法来操作Qt QSqlRelationalDelegate:

  1. QSqlRelationalDelegate::paint()

paint()方法用于在关系表格中绘制关联字段的值和描述。例如:

void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (index.column() == 1) {
        // 获取关联字段的值和描述
        QVariant value = index.data(Qt::DisplayRole);
        QVariant description = index.data(Qt::UserRole + 1);

        // 在关系表格中绘制关联字段的值和描述
        QStyleOptionViewItem opt = option;
        opt.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
        opt.text = description.toString();
        drawDisplay(painter, opt, option.rect, value.toString());
    } else {
        QStyledItemDelegate::paint(painter, option, index);
    }
}

在上述示例中,我们重写了paint()方法,在关系表格中绘制了关联字段的值和描述。

  1. QSqlRelationalDelegate::createEditor()

createEditor()方法用于创建关系表格中指定单元格的编辑器。例如:

QWidget *MyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if (index.column() == 1) {
        // 创建关联字段的编辑器
        QComboBox *editor = new QComboBox(parent);
        editor->setEditable(true);

        // 获取关联字段的值和描述
        QSqlRelationalTableModel *model = qobject_cast<QSqlRelationalTableModel *>(index.model());
        QSqlRelation relation = model->relation(index.column());
        QSqlTableModel *relModel = model->relationModel(index.column());
        QString displayColumn = relModel->record().fieldName(relation.displayColumn());
        QString filter = relModel->filter();
        QString sort = relModel->sort();

        // 设置关联字段的选项
        relModel->setFilter(filter.isEmpty() ? "" : QString("(%1)").arg(filter));
        relModel->setSort(relModel->fieldIndex(displayColumn), Qt::AscendingOrder);
        relModel->select();
        for (int i = 0; i < relModel->rowCount(); ++i) {
            QModelIndex relIndex = relModel->index(i, relation.displayColumn());
            QVariant value = relModel->data(relIndex, Qt::DisplayRole);
            QVariant key = relModel->data(relIndex, Qt::UserRole);
            editor->addItem(value.toString(), key);
        }

        // 返回关联字段的编辑器
        return editor;
    } else {
        return QStyledItemDelegate::createEditor(parent, option, index);
    }
}

在上述示例中,我们重写了createEditor()方法,在关系表格中创建了关联字段的编辑器,并设置了关联字段的选项。

  1. QSqlRelationalDelegate::setEditorData()

setEditorData()方法用于设置关系表格中指定单元格的编辑器的数据。例如:

void MyDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if (index.column() == 1) {
        // 获取关联字段的值
        QVariant value = index.data(Qt::EditRole);

        // 设置关联字段的编辑器的数据
        QComboBox *comboBox = qobject_cast<QComboBox *>(editor);
        if (comboBox) {
            int index = comboBox->findData(value, Qt::UserRole);
            comboBox->setCurrentIndex(index);
        }
    } else {
        QStyledItemDelegate::setEditorData(editor, index);
    }
}

在上述示例中,我们重写了setEditorData()方法,在关系表格中设置了关联字段的编辑器的数据。

  1. QSqlRelationalDelegate::setModelData()

setModelData()方法用于将关系表格中指定单元格的编辑器中的数据设置到模型中。例如:

void MyDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    if (index.column() == 1) {
        // 获取关联字段的值
        QComboBox *comboBox = qobject_cast<QComboBox *>(editor);
        if (comboBox) {
            QVariant value = comboBox->currentData(Qt::UserRole);
            model->setData(index, value, Qt::EditRole);
        }
    } else {
        QStyledItemDelegate::setModelData(editor, model, index);
    }
}

在上述示例中,我们重写了setModelData()方法,将关系表格中指定单元格的编辑器中的数据设置到模型中。

下面是一个完整的示例代码,演示了如何使用Qt QSqlRelationalDelegate:

#include <QtWidgets>

class MyDelegate : public QSqlRelationalDelegate
{
public:
    MyDelegate(QObject *parent = nullptr) : QSqlRelationalDelegate(parent) {}

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
    {
        if (index.column() == 1) {
            // 获取关联字段的值和描述
            QVariant value = index.data(Qt::DisplayRole);
            QVariant description = index.data(Qt::UserRole + 1);

            // 在关系表格中绘制关联字段的值和描述
            QStyleOptionViewItem opt = option;
            opt.displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
            opt.text = description.toString();
            drawDisplay(painter, opt, option.rect, value.toString());
        } else {
            QSqlRelationalDelegate::paint(painter, option, index);
        }
    }

    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
    {
        if (index.column() == 1) {
            // 创建关联字段的编辑器
            QComboBox *editor = new QComboBox(parent);
            editor->setEditable(true);

            // 获取关联字段的值和描述
            QSqlRelationalTableModel *model = qobject_cast<QSqlRelationalTableModel *>(index.model());
            QSqlRelation relation = model->relation(index.column());
            QSqlTableModel *relModel = model->relationModel(index.column());
            QString displayColumn = relModel->record().fieldName(relation.displayColumn());
            QString filter = relModel->filter();
            QString sort = relModel->sort();

            // 设置关联字段的选项
            relModel->setFilter(filter.isEmpty() ? "" : QString("(%1)").arg(filter));
            relModel->setSort(relModel->fieldIndex(displayColumn), Qt::AscendingOrder);
            relModel->select();
            for (int i = 0; i < relModel->rowCount(); ++i) {
                QModelIndex relIndex = relModel->index(i, relation.displayColumn());
                QVariant value = relModel->data(relIndex, Qt::DisplayRole);
                QVariant key = relModel->data(relIndex, Qt::UserRole);
                editor->addItem(value.toString(), key);
            }

            // 返回关联字段的编辑器
            return editor;
        } else {
            return QSqlRelationalDelegate::createEditor(parent, option, index);
        }
    }

    void setEditorData(QWidget *editor, const QModelIndex &index) const override
    {
        if (index.column() == 1) {
            // 获取关联字段的值
            QVariant value = index.data(Qt::EditRole);

            // 设置关联字段的编辑器的数据
            QComboBox *comboBox = qobject_cast<QComboBox *>(editor);
            if (comboBox) {
                int index = comboBox->findData(value, Qt::UserRole);
                comboBox->setCurrentIndex(index);
            }
        } else {
            QSqlRelationalDelegate::setEditorData(editor, index);
        }
    }

    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
    {
        if (index.column() == 1) {
            // 获取关联字段的值
            QComboBox *comboBox = qobject_cast<QComboBox *>(editor);
            if (comboBox) {
                QVariant value = comboBox->currentData(Qt::UserRole);
                model->setData(index, value, Qt::EditRole);
            }
        } else {
            QSqlRelationalDelegate::setModelData(editor, model, index);
        }
    }
};

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

    // 创建数据库连接
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    if (!db.open()) {
        qWarning() << "Cannot open database:" << db.lastError().text();
        return 1;
    }

    // 创建模型
    QSqlTableModel *model = new QSqlTableModel;
    model->setTable("students");
    model->setRelation(2, QSqlRelation("courses", "id", "name"));
    model->select();

    // 创建视图
    QTableView *view = new QTableView;
    view->setModel(model);
    view->setItemDelegate(new MyDelegate(view));

    // 显示视图
    view->show();

    return app.exec();
}

上述示例代码中,我们首先创建了一个MyDelegate类,继承自QSqlRelationalDelegate类。在MyDelegate类中,我们重写了paint()、createEditor()、setEditorData()和setModelData()方法,实现了在关系表格中显示和编辑关联字段的功能。

然后,我们创建了一个数据库连接和一个QSqlTableModel模型,并将模型的第二列设置为关联字段,关联到courses表格的id字段。我们还创建了一个QTableView视图,并将模型和自定义的委托类设置到视图中。

最后,我们显示了QTableView视图,并运行程序。当我们在关系表格中编辑关联字段时,可以看到关联字段的选项和描述。

标签:index,Qt,表格,QSqlRelationalDelegate,初入,字段,relModel
From: https://blog.51cto.com/chenfenglove/7343338

相关文章

  • Qt中两个QLabel标签控件重叠的方法
       在项目中遇到这样的问题,需要开发一个电池控件,显示电量同时又能以数字标注电量的多少。效果如下图所示:      通常在Qt中图片的显示是用的QLabel标签控件。根据以往MFC开发的经验,想当然的是两个标签控件重叠排放,下面的标签控件显示图片,上面的标签控件显示数字。但......
  • 记录centos stream 9 编译qt5.15.10源码
    开始装的一些依赖库没有记录gcc之类的,都是通过dnf安装的主要是make过程中出现的问题(qtwebengine)及其如何解决编译的命令如下./configure-prefix/home/kun/usr/Qt/5.15.10-opensource-confirm-licensemake-j16makeinstallconfigure阶段失败一般都是缺少,都是dnf解决的......
  • ESP8266透明串口转MQTT模块使用说明
    ESP8266透明串口转MQTT模块使用说明 更新历史日期撰写备注2023.9.2YTH       目录1    模块功能...22    串口驱动...23    快速验证功能...33.1    模块默认功能:...33.2    手机开启热点.......
  • Qt编译报错:multiple definition of
    解决方法一:在.pro文件下查看SOURCES+=和HEADERS+=也没有重复引入文件,删除重复的文件即可。解决方法二:把debug文件夹下的.o文件都删除,然后再编译下。解决方法三:如果.h文件中有类的定义和实现,则实现时在每个成员前加inline。  转载于:QT项目出现multipledefinitionof错误......
  • qt读取json文件
    Qt读取json数据文件步骤:本条记录未进行判断,只是针对自己在已知json数据文件下的读取1、打开文件QFliefile("设置路径");2、设置文件打开方式file.open(QFile::ReadOnly|WriteOnly|ReadWrite);3、读取文件数据QByteArrayall=file.readAll();4、关闭文件file.cl......
  • Qt绘制3D图形例程
    本文主要内容是关于QOpenGLWidget的使用。此控件用于代替旧的QGLWidget类。关于此类的使用方法可以参考Qt帮助相关内容。glDrawArrays(...)函数参数说明:OpenGL理解GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN等绘制三角形序列的三种方式_匆忙拥挤repeat的博客-CSDN博客变量修饰符说明......
  • 『PyQt5-基础篇』| 03 基于PyQt5的第一个应用程序简单示例
    (03基于PyQt5的第一个应用程序简单示例)1导入必须的类需要两个类Application,QWidget;这两个类继承于QtWidgets;Application是应用程序类,QWidget是窗口类;sys模块是应用程序或窗口的参数会用到。importsysfromPyQt5.QtWidgetsimportQApplication,QWidget2创建Appli......
  • 【Python进阶-PyQt5】00PyQt5简介
    0.图形用户界面-开发选择在Python基础的教程中,我们程序的用户交互界面都是运行窗口。这个运行窗口对于我们编程者来说直观明了,但是对于一些相对复杂的程序,用户使用上就会变得十分麻烦。所以,我们要通过设计用户交互界面来解决这种问题。程序的图形用户交互界面,英文称之为GUI(Grap......
  • Virtualbox中FreeBSD安装lxqt桌面后鼠标无响应
    1程序版本及问题Virtualbox7.0FreeBSD13.1xorg7.7_3lxqt1.3.0virtualbox-ose-additions6.1.46问题:通过startx启动lxqt桌面后鼠标无响应。2问题解决步骤打开/etc/X11/xorg.conf文件1定位到ServerLayout新增一行Option"AutoAddDevices""false"如下:Section"S......
  • MQTT协议
    1.MQTT协议介绍官网:http://mqtt.p2hp.com/MQTThttps://blog.csdn.net/weixin_36173034/article/details/1125110142.MQTT协议原理3.MQTT协议数据包结构Byte1:低4位MQTT消息质量QoS取决于发布者发布消息的Qos与订阅者订阅消息的Qos,取他们两者Qos最小的,即”木桶原理......