Qt扫盲-Model/View入门

这篇具有很好参考价值的文章主要介绍了Qt扫盲-Model/View入门。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、概述

每个UI开发人员都应该了解ModelView编程,

表格格控件、列表格控件和树控件是gui中经常使用的组件。这些控件有两种不同的方式访问它们的数据。

  • 1.传统方法
    传统的方法就是让控件本身去储存数据,在控件内部有数据容器,这种方法非常直观,但是,在许多重要的应用程序中,它会导致数据同步问题。
  • 2.Model/View 方法
    Model/View 也叫 模型/ 视图 编程,其中控件不维护内部数据容器。它们通过标准化接口访问外部数据,从而避免了数据重复。乍一看,这似乎很复杂,但一旦仔细研究,就会发现它不仅易于掌握,而且Model/View编程的许多好处也变得更加清晰。
    Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

在这个过程中,我们将学习Qt提供的一些基本技术,比如:

  • 标准部件和Model/View部件之间的区别
  • 表格单和 model 之间的适配器
  • 开发简单的Model/View应用程序
  • 预定义的 model
  • 中间主题,如:
    树 view
    选择
    代理
  • model 试验调试

我们还会了解使用Model/View编程是否可以更容易地编写新应用程序,或者传统的控件是否也可以正常工作。

二、介绍

Model/View是一种用于在处理数据集的控件中分离数据和 view 的技术。标准的控件不是为从 view 中分离数据而设计的,这就是Qt有两种不同类型的控件的原因。虽然这两种类型的控件看起来是一样的,但是它们与数据的交互方式不同。

标准控件使用的数据是控件的一部分。数据和界面是融在一起的
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++
view 类对外部数据( 模型 )进行操作,就是通过接口去分类界面和数据,model 存储数据,而view 则是 视图 类,显示UI。
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

1. 标准部件

让我们仔细看看一个标准的表格控件。表格控件是用户可以更改的数据元素的2D数组。通过读写表格控件提供的数据元素,可以将表格控件集成到程序流中。这种方法在许多应用程序中非常直观和有用,但是使用标准表格控件显示和编辑数据库表格可能会有问题。

什么问题呢?

那就是我们必须协调数据的两个副本:一个在控件外部;一个在控件内。开发人员负责同步这两个版本。手动同步容易出风险。

除此之外,表格示和数据的紧密耦合使得编写单元测试变得更加困难。不方便测试呐!

2. Model/View 控件

Model/View逐步提供了一个使用更通用架构的解决方案。 Model/View消除了标准控件可能出现的数据一致性问题。

Model/View还使使用相同数据的多个 view 变得更容易,因为一个 model 可以传递给多个 view 。

最重要的区别是Model/View控件不将数据存储在表格格单元格后面。事实上,它们直接根据您的数据进行操作。由于 view 类不知道数据的结构,因此需要提供一个包装器,使数据符合QAbstractItemModel接口。 view 使用该接口读取和写入数据。

实现QAbstractItemModel的类的任何实例都被称为 model 。一旦 view 接收到一个 model 的指针,它将读取并显示其内容,并成为其编辑器。

3. Model/View控件概述

下面是Model/View控件及其相应的标准控件的概述。

控件外观 标准部件(基于Item的便利类) Model/View view 类(用于外部数据)
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++ QListWidget QListView
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++ QTableWidget QTableView
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++ QTreeWidget QTreeView
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++ 很少用 QColumnView将树显示为列表格的层次结构
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++ QComboBox既可以作为 view 类,也可以作为传统的控件

4. 在表格单和 model 之间使用适配器 Adapters

在表格单和 model 之间使用适配器可以派上用场。

我们可以直接从表格本身编辑存储在表格中的数据,但是在文本字段中编辑数据要舒服得多。对于操作一个值(QLineEdit, QCheckBox…)而不是数据集的控件,没有直接的Model/View对应物来分离数据和 view ,因此我们需要一个适配器来将表格单连接到数据源。

QDataWidgetMapper是一个很好的解决方案,因为它将表格单控件映射到表格行,并使为数据库表格构建表格单变得非常容易。这个就相当于我们把修改的数据用QDataWidgetMapper 通过 model/view的方式给同步到表格里面去了。
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

适配器的另一个例子是QCompleter。Qt有QCompleter用于在Qt控件中提供自动补全功能,如QComboBox和QLineEdit,如下所示。QCompleter使用一个 model 作为它的数据源。
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++
就像下面的简单代码就可以做到这个效果

QStringList wordList;
wordList << "alpha" << "omega" << "omicron" << "zeta"<<"Emanuel"<<"Emerson"<<"Emilio"<<"Emma"<<"Emmily";
QLineEdit *lineEdit = new QLineEdit(this);

QCompleter *completer = new QCompleter(wordList, this);
completer->setCaseSensitivity(Qt::CaseInsensitive);
lineEdit->setCompleter(completer);

三、 简单的 model / view 应用程序示例

如果你想开发一个 model / view 应用程序,应该从哪里开始?Qt官方建议从一个简单的示例开始,并逐步扩展它。这使得理解架构变得容易得多。对许多开发人员来说,在调用IDE之前尝试详细理解 model/view 架构是困难的。但是从简单 model/view 应用程序实践来看要更容易。

下面是7个非常简单和独立的应用程序,展示了 model/view 编程的不同方面

1. 一个只读表

我们从一个使用QTableView显示数据的应用程序开始。稍后我们将添加编辑功能。

// main.cpp
#include < QApplication >
#include < QTableView >
#include“mymodel.h”

int main(Int argc, char *argv[])
{
	QApplication a(argc, argv);
	QTableView tableView;
	MyModel MyModel;
	tableView.setModel (&myModel);
	tableView.show ();
	return a.exec ();
}

我们有常用的main()函数:
我们创建一个MyModel的实例并使用tableView.setModel(&myModel);
传递它的指针给tableView。

tableView会调用它接收到的指针的方法来找出两件事:

  • 应该显示多少行和多少列。
  • 每个单元格应该打印什么内容。

model 需要一些代码来响应此请求。我们有一个表数据集,所以让我们从QAbstractTableModel开始,因为它比更通用的qabstractemmodel更容易使用。

// mymodel.h
#include <QAbstractTableModel>

class MyModel : public QAbstractTableModel
{
	Q_OBJECT
	public:
      MyModel(QObject *parent = nullptr);
      int rowCount(const QModelIndex &parent = QModelIndex()) const override;
      int columnCount(const QModelIndex &parent = QModelIndex()) const override;
      QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
};

qabstractablemodel需要实现三个抽象方法。

  // mymodel.cpp
  #include "mymodel.h"

  MyModel::MyModel(QObject *parent)
      : QAbstractTableModel(parent)
  {
  }

  int MyModel::rowCount(const QModelIndex & /*parent*/) const
  {
     return 2;
  }

  int MyModel::columnCount(const QModelIndex & /*parent*/) const
  {
      return 3;
  }

  QVariant MyModel::data(const QModelIndex &index, int role) const
  {
      if (role == Qt::DisplayRole)
         return QString("Row%1, Column%2")
                     .arg(index.row() + 1)
                     .arg(index.column() +1);

      return QVariant();
  }

行数和列数由 MyModel::rowCount() 和 MyModel::columnCount() 提供。当 view 需要知道单元格的文本是什么时,它会调用方法MyModel::data()。行和列信息通过index参数指定,role 设置为Qt::DisplayRole。下一节将介绍其他role。

在我们的例子中,应该显示的数据已经生成。在实际的应用程序中,MyModel会有一个名为MyData的成员,它充当所有读写操作的目标。

这个小示例演示了 model 的被动性。** model 不知道何时会使用它或需要哪些数据。它只是在每次 view 请求时提供数据。**

当 model 的数据需要更改时会发生什么? view 如何意识到数据已经更改,需要再次读取? model 必须发出一个信号,表明哪些范围的单元格发生了变化。这将在 3 节中进行演示。

2. 使用role扩展只读示例

除了控制 view 显示的文本, model 还控制文本的外观。对 model 稍作修改后,得到如下结果:
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

实际上,除了data()方法之外,我们不需要修改任何内容,以设置字体、背景颜色、对齐方式和复选框。下面是产生上面显示结果的data()方法。不同的是,这次我们使用形参int role根据其值返回不同的信息。

  // mymodel.cpp
  QVariant MyModel::data(const QModelIndex &index, int role) const
  {
      int row = index.row();
      int col = index.column();
      // generate a log message when this method gets called
      qDebug() << QString("row %1, col%2, role %3")
              .arg(row).arg(col).arg(role);

      switch (role) {
      case Qt::DisplayRole:
          if (row == 0 && col == 1) return QString("<--left");
          if (row == 1 && col == 1) return QString("right-->");

          return QString("Row%1, Column%2")
                  .arg(row + 1)
                  .arg(col +1);
      case Qt::FontRole:
          if (row == 0 && col == 0) { //change font only for cell(0,0)
              QFont boldFont;
              boldFont.setBold(true);
              return boldFont;
          }
          break;
      case Qt::BackgroundRole:
          if (row == 1 && col == 2)  //change background only for cell(1,2)
              return QBrush(Qt::red);
          break;
      case Qt::TextAlignmentRole:
          if (row == 1 && col == 1) //change text alignment only for cell(1,1)
              return Qt::AlignRight + Qt::AlignVCenter;
          break;
      case Qt::CheckStateRole:
          if (row == 1 && col == 0) //add a checkbox to cell(1,0)
              return Qt::Checked;
          break;
      }
      return QVariant();
  }

每个格式化属性都是通过单独调用data()方法从模型中请求的。role参数用来让模型知道请求的是哪个属性:

enum Qt::ItemDataRole Meaning Type
Qt::DisplayRole 文本 QString
Qt::FontRole 字体 QFont
BackgroundRole 单元格的背景刷 QBrush
Qt::TextAlignmentRole 文字对齐 enum Qt::AlignmentFlag
Qt::CheckStateRole 支持CheckBox with QVariant(), sets checkboxes with Qt::Checked or Qt::Unchecked enum Qt::ItemDataRole
Qt::DecorationRole 以图标形式呈现的装饰数据 QColor, QIcon or QPixmap

Qt::ForegroundRole |用于使用默认Delegates渲染的项目的前景画笔(通常为文本颜色 |QBrush

请参阅Qt命名空间文档,了解有关Qt::ItemDataRole枚举功能的更多信息。

现在我们需要确定使用分离的模型如何影响应用程序的性能,因此让我们跟踪视图调用data()方法的频率。为了跟踪视图调用模型的频率,我们在data()方法中添加了调试语句,它会记录到错误输出流中。

在上面的小示例中,data()将被调用42次。每次将光标悬停在字段上时,data()将再次被调用——每个单元格调用7次。

分别执行的是 就是上面的 7个 Role 对应的 case 下面的语句。

这就是为什么在调用 data() 并缓存昂贵的查找操作时,确保数据可用是很重要的

3. 表格单元中的时钟

Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

我们仍然有一个只读表,但这一次内容每秒都在变化,因为我们显示的是当前时间。

  QVariant MyModel::data(const QModelIndex &index, int role) const
  {
      int row = index.row();
      int col = index.column();

      if (role == Qt::DisplayRole && row == 0 && col == 0)
          return QTime::currentTime().toString();

      return QVariant();
  }

让时钟滴答作响的东西少了一些。我们需要每秒都告诉视图时间发生了变化,需要重新读取。我们用计时器来做到这一点。在构造函数中,我们将其间隔设置为1秒,并连接其超时信号。

  MyModel::MyModel(QObject *parent)
      : QAbstractTableModel(parent)
      , timer(new QTimer(this))
  {
      timer->setInterval(1000);
      connect(timer, &QTimer::timeout , this, &MyModel::timerHit);
      timer->start();
  }

下面是对应的槽:

  void MyModel::timerHit()
  {
      //we identify the top left cell
      QModelIndex topLeft = createIndex(0,0);
      //emit a signal to make the view reread identified data
      emit dataChanged(topLeft, topLeft, {Qt::DisplayRole});
  }

我们 调用dataChanged()函数,让视图再次读取左上角单元格中的数据。注意,我们没有显式地将dataChanged()信号连接到视图。这在我们调用setModel()时自动发生。

4. 为列和行设置标题

标题可以通过视图方法隐藏
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

tableView->verticalHeader()->hide();

然而,头部内容是通过模型设置的,因此我们重新实现了 headerData() 方法:

  QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role) const
  {
      if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
          switch (section) {
          case 0:
              return QString("first");
          case 1:
              return QString("second");
          case 2:
              return QString("third");
          }
      }
      return QVariant();
  }

注意,headerData()方法也有一个 role,与MyModel::data()中role一样的含义。

5. 最小编辑示例

在本例中,我们将构建一个应用程序,通过重复在表格单元格中输入的值,自动用内容填充窗口标题。为了能够轻松地访问窗口标题,我们将 QTableView 放在 QMainWindow 中。

该模型决定是否提供编辑功能。我们只需要修改模型,以便启用可用的编辑功能。这是通过重新实现下列虚拟方法来实现的:setData()和flags()。

  // mymodel.h
  #include <QAbstractTableModel>
  #include <QString>

  const int COLS= 3;
  const int ROWS= 2;

  class MyModel : public QAbstractTableModel
  {
      Q_OBJECT
  public:
      MyModel(QObject *parent = nullptr);
      int rowCount(const QModelIndex &parent = QModelIndex()) const override;
      int columnCount(const QModelIndex &parent = QModelIndex()) const override;
      QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
      bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
      Qt::ItemFlags flags(const QModelIndex &index) const override;
  private:
      QString m_gridData[ROWS][COLS];  //holds text entered into QTableView
  signals:
      void editCompleted(const QString &);
  };

我们使用二维数组QString m_gridData来存储数据。这使得m_gridData成为MyModel的核心。MyModel的其余部分就像一个包装器,并将m_gridData适应于QAbstractItemModel接口。我们还引入了editCompleted()信号,它可以将修改后的文本传输到窗口标题中。

  bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
  {
      if (role == Qt::EditRole) {
          if (!checkIndex(index))
              return false;
          //save value from editor to member m_gridData
          m_gridData[index.row()][index.column()] = value.toString();
          //for presentation purposes only: build and emit a joined string
          QString result;
          for (int row = 0; row < ROWS; row++) {
              for (int col= 0; col < COLS; col++)
                  result += m_gridData[row][col] + ' ';
          }
          emit editCompleted(result);
          return true;
      }
      return false;
  }

每当用户编辑一个单元格时,都会调用setData()。index参数告诉我们哪个字段被编辑了,value参数提供了编辑过程的结果。Role将始终设置为Qt::EditRole,因为单元格只包含文本。如果存在一个复选框,并且用户权限被设置为允许选中该复选框,那么调用也会将角色设置为Qt::CheckStateRole。

  Qt::ItemFlags MyModel::flags(const QModelIndex &index) const
  {
      return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
  }

可以使用flags()来调整单元格的各种属性。

返回Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled足以显示编辑器可以选择一个单元格。

如果编辑一个单元格修改的数据比该特定单元格中的数据更多,模型必须发出dataChanged()信号,以便读取已经更改的数据。就像 3 中的写法,自己去手动 emit dataChanged()信号

四、中间的话题

1. TreeView

您可以将上面的示例转换为具有树视图的应用程序。只需将QTableView替换为QTreeView,就可以得到一个读/写树。不需要对模型进行任何更改。树不会有任何层次结构,因为模型本身没有任何层次结构。
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++
QListView、QTableView和QTreeView都使用了一个模型抽象,它是一个合并的列表、表和树。这使得在同一个模型中使用多个不同类型的视图类成为可能。

Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

到目前为止,我们的示例模型看起来是这样的:
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++
我们想要呈现一棵真正的树。为了建立模型,我们将数据包装在上面的示例中。这次我们使用QStandardItemModel,它是一个层次化数据的容器,也实现了QAbstractItemModel。为了显示树,QStandardItemModel必须用QStandardItems填充,它能够保存项目的所有标准属性,如文本、字体、复选框或笔刷。
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

  // modelview.cpp
  #include "mainwindow.h"

  #include <QTreeView>
  #include <QStandardItemModel>
  #include <QStandardItem>

  MainWindow::MainWindow(QWidget *parent)
      : QMainWindow(parent)
      , treeView(new QTreeView(this))
      , standardModel(new QStandardItemModel(this))
  {
      setCentralWidget(treeView);

      QList<QStandardItem *> preparedRow = prepareRow("first", "second", "third");
      QStandardItem *item = standardModel->invisibleRootItem();
      // adding a row to the invisible root item produces a root element
      item->appendRow(preparedRow);

      QList<QStandardItem *> secondRow = prepareRow("111", "222", "333");
      // adding a row to an item starts a subtree
      preparedRow.first()->appendRow(secondRow);

      treeView->setModel(standardModel);
      treeView->expandAll();
  }

  QList<QStandardItem *> MainWindow::prepareRow(const QString &first,
                                                const QString &second,
                                                const QString &third) const
  {
      return {new QStandardItem(first),
              new QStandardItem(second),
              new QStandardItem(third)};
  }

我们只需实例化一个QStandardItemModel,并在构造函数中添加一些QStandardItems。然后,我们可以建立一个分层的数据结构,因为一个QStandardItem可以容纳其他QStandardItem。节点在视图中被折叠和展开。

2. 使用选择器

我们希望访问所选项目的内容,以便将其与层次结构一起输出到窗口标题中。
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

下面来创建几个条目:

  #include "mainwindow.h"

  #include <QTreeView>
  #include <QStandardItemModel>
  #include <QItemSelectionModel>

  MainWindow::MainWindow(QWidget *parent)
      : QMainWindow(parent)
      , treeView(new QTreeView(this))
      , standardModel(new QStandardItemModel(this))
  {
      setCentralWidget(treeView);
      QStandardItem *rootNode = standardModel->invisibleRootItem();

      //defining a couple of items
      QStandardItem *americaItem = new QStandardItem("America");
      QStandardItem *mexicoItem =  new QStandardItem("Canada");
      QStandardItem *usaItem =     new QStandardItem("USA");
      QStandardItem *bostonItem =  new QStandardItem("Boston");
      QStandardItem *europeItem =  new QStandardItem("Europe");
      QStandardItem *italyItem =   new QStandardItem("Italy");
      QStandardItem *romeItem =    new QStandardItem("Rome");
      QStandardItem *veronaItem =  new QStandardItem("Verona");

      //building up the hierarchy
      rootNode->    appendRow(americaItem);
      rootNode->    appendRow(europeItem);
      americaItem-> appendRow(mexicoItem);
      americaItem-> appendRow(usaItem);
      usaItem->     appendRow(bostonItem);
      europeItem->  appendRow(italyItem);
      italyItem->   appendRow(romeItem);
      italyItem->   appendRow(veronaItem);

      //register the model
      treeView->setModel(standardModel);
      treeView->expandAll();

      //selection changes shall trigger a slot
      QItemSelectionModel *selectionModel = treeView->selectionModel();
      connect(selectionModel, &QItemSelectionModel::selectionChanged,
              this, &MainWindow::selectionChangedSlot);
  }

视图在一个单独的选择模型中管理选择,这个模型可以用selectionModel()方法取得。我们获取选择模型,以便将槽连接到它的selectionChanged()信号。

void MainWindow::selectionChangedSlot(const QItemSelection & /*newSelection*/, const QItemSelection & /*oldSelection*/)
{
      //get the text of the selected item
      const QModelIndex index = treeView->selectionModel()->currentIndex();
      QString selectedText = index.data(Qt::DisplayRole).toString();
      //find out the hierarchy level of the selected item
      int hierarchyLevel = 1;
      QModelIndex seekRoot = index;
      while (seekRoot.parent() != QModelIndex()) {
          seekRoot = seekRoot.parent();
          hierarchyLevel++;
      }
      QString showString = QString("%1, Level %2").arg(selectedText)
                           .arg(hierarchyLevel);
      setWindowTitle(showString);
}

我们通过调用treeView->selectionModel()->currentIndex()来获取与选区对应的模型索引,并通过模型索引获取字段的字符串。然后我们只需要计算物品的层次结构。顶级元素没有父元素,parent()方法将返回一个默认构造的QModelIndex()。

这就是为什么我们使用parent()方法迭代到顶层,同时计算迭代过程中执行的步数。

选择模型(如上所示)可以被检索,但它也可以被QAbstractItemView::setSelectionModel设置。这就是为什么可以有3个视图类同步选择,因为只有一个选择模型的实例被使用。要在3个视图之间共享选择模型,请使用selectionModel(),并将结果分配给第二个和第三个视图类与setSelectionModel()。

3. 预定义模型

使用model/view的典型方法是包装特定的数据,使其可以在视图类中使用。然而,Qt也为常见的底层数据结构提供了预定义的模型。如果有一种可用的数据结构适合您的应用程序,那么预定义的模型可能是一个很好的选择。

模型名称 含义
QStringListModel 存储一个字符串列表
QStandardItemModel 存储任意的分层项
QFileSystemModel 封装的本地的文件系统
QSqlQueryModel 封装一个SQL结果集
QSqlTableModel 封装一个SQL表
QSqlRelationalTableModel 用外键封装一个SQL表
QSortFilterProxyModel 对另一个模型进行排序和/或过滤

4. Delegates

到目前为止,在所有的例子中,数据都是以文本或复选框的形式出现在单元格中,并以文本或复选框的形式进行编辑。提供这些表示和编辑服务的组件称为Delegates。我们才刚刚开始使用Delegates,因为视图使用了默认Delegates。但是,假设我们想要有一个不同的编辑器(例如,滑块或下拉列表),或者想要以图形的形式显示数据。让我们看一个名为Star Delegate的例子,其中使用星号表示评级:
Qt扫盲-Model/View入门,# ▶ Qt扫盲,model/view,model,view,qt5,模型视图编程,c++

这个视图有一个setItemDelegate()方法,用来替换默认的Delegates,并安装一个自定义的Delegates。新的Delegates可以通过创建一个继承自QStyledItemDelegate的类来编写。为了编写一个显示星号并且没有输入功能的Delegates,我们只需要覆盖两个方法。

  class StarDelegate : public QStyledItemDelegate
  {
      Q_OBJECT
  public:
      StarDelegate(QWidget *parent = 0);
      void paint(QPainter *painter, const QStyleOptionViewItem &option,
                 const QModelIndex &index) const;
      QSize sizeHint(const QStyleOptionViewItem &option,
                     const QModelIndex &index) const;
  };

Paint()根据底层数据的内容绘制星号。可以通过调用index.data()来查找数据。

Delegates的sizeHint()方法用于获取每个星号的尺寸,以便单元格提供足够的高度和宽度来容纳这些星号。

如果你想在视图类的网格中使用自定义图形表示来显示数据,编写自定义Delegates是正确的选择。如果你想离开网格,你不会使用自定义Delegates,而是使用自定义视图类。

Qt文档中对Delegates的其他引用:

Spin BoxDelegates示例
QAbstractItemDelegate类的引用
QSqlRelationalDelegate类的引用
QStyledItemDelegate类引用
QItemDelegate类引用文章来源地址https://www.toymoban.com/news/detail-640344.html

到了这里,关于Qt扫盲-Model/View入门的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt Quick系列(7)—Model-View

    🚀作者:CAccept 🎂专栏:Qt Quick 在QML中,model和view由delegate连接,他们的关系如下👇 1、delegate 属性:delegate知道model的内容以及如何可视化它- 怎么显示 。 2、view知道delegate的概念以及如何布置它们- 怎么摆放 。 3、model属性:model只知道它所表示的数据- 要显示的内容集合 。

    2024年02月12日
    浏览(31)
  • Qt关于Model/View大数据量刷新的处理经验

    前段时间有同学咨询关于大数据量的Model刷新时卡顿的优化方案,通过评论留言的方式回答了一部分,但感觉不够全面。因为这个是之前项目重点解决的问题,处理的过程中收获颇多,这里就基于之前的项目经验进行完整的总结,希望对大家在处理类似问题的过程中能有所启

    2024年02月08日
    浏览(31)
  • Qt 中model/View 架构 详解,以及案例实现相薄功能

    ​ 我们的系统需要显示大量数据,比如从数据库中读取数据,以自己的方式显示在自己的应用程序的界面中。早期的 Qt 要实现这个功能,需要定义一个组件,在这个组件中保存一个数据对象,比如一个列表。我们对这个列表进行查找、插入等的操作,或者把修改的地方写回

    2024年02月06日
    浏览(32)
  • 如何避免 QT 的 View/Model 模式产生消息激活的死循环?

    当收到QTableWidget的itemChanged信号时,关联的槽函数一般用于响应单元格数据的修改。它可以执行以下一些常见的工作: 更新数据:槽函数可以获取修改后的数据,并根据需要更新相关的数据结构或变量。 数据验证:槽函数可以对修改后的数据进行验证,检查其是否满足特定条

    2024年01月21日
    浏览(38)
  • 一文带你了解QT Model/View框架的设计思想和实现机制

    目录 1、QT Model/View框架简介 1.1、QT Model/View是什么? 1.2、QT Model/View框架核心思想 1.3、Model/View框架工作机制 1.4、Model/View框架的类 2、Model 2.1模型简介 2.2、模型索引 2.3、数据角色 2.4、QStringListModel 2.5、QFileSystemModel 2.6、QSortFilterProxyModel 3、View 4、Delegate 5、项选择模型 5.1、QIt

    2024年02月05日
    浏览(67)
  • 【Jetpack】ViewModel 架构组件 ( 视图 View 和 数据模型 Model | ViewModel 作用 | ViewModel 生命周期 | 代码示例 | 使用注意事项 )

    Activity 遇到的问题 : 瞬态数据丢失 : 操作 Activity 时 , 如果 屏幕 自动旋转 , 当前 Activity 组件会 执行销毁操作 , 并重新创建新的 Activity 组件 , 该操作会 导致 Activity 的 瞬态数据 丢失 ; 内存泄漏 : 在 系统组件 如 Activity 中 , 启动了一个线程 , 在线程中执行一系列操作 , 如果 A

    2024年01月25日
    浏览(35)
  • Pyqt Model View 的使用方法

    全是嵌套的callback 的实现方法,层级分离,通过类的继承,拓展基础类的功能,通用性不错,省了自己在,调用原始方法,构建view 和 控制数据库,再将数据同步到板卡,利用现成的基础类,自己在拓展一个功能就🆗了 C 没有继承和多态,一言难尽,Python 的继承和多态应该是最容易理解的 添

    2024年02月07日
    浏览(50)
  • 22、touchGFX学习Model-View-Presenter设计模式

    touchGFX采用MVP架构,如下所示: 本文界面如下所示: 本文将实现两个操作: 1、触摸屏点击开关按键实现打印开关显示信息,模拟开关灯效果 2、板载案按键控制触摸屏LED灯的显示和隐藏 实现的方向为view-present-model 1、添加led开关交互事件:button_clicked_led 2、screenView.hpp中声明

    2024年02月13日
    浏览(26)
  • JavaEE的MVC(Model-View-Controller)设计模式

    JavaEE的MVC(Model-View-Controller)设计模式是一种用于组织和管理Web应用程序的架构模式。MVC模式将应用程序分为三个主要组件:模型(Model)、视图(View)和控制器(Controller)。每个组件有着不同的责任,以促使代码的分离和模块化,提高应用程序的可维护性和可扩展性。 以

    2024年01月23日
    浏览(38)
  • 【扫盲】什么是模型推理(model inference)

    举几个对推理性能有强要求的场景例子: (1)在公共安全领域中,视频监控中实时的人脸识别需要有实时的展示能力方便执法人员快速定位跟踪人员。 (2)在互联网应用领域中,电商网站、内容应用实时的个性化推荐要求能够快速响应,推荐的卡顿感将直接影响购物或者内

    2024年02月13日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包