Qt模型 - 视图 - 控制器 [英] Qt Model-View-Controller

查看:189
本文介绍了Qt模型 - 视图 - 控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先我想说我已经阅读所有其他关于Qt和MVC的问题,但我找不到我要找的。所以,除非你在老问题中找到真正回答我的问题的东西,不要将它们链接到我。我也在qt.digia.com和qt.project.com搜索,但再次没有运气。

First of all I would like to say that I' ve already read all the other questions about Qt and MVC, but I couldn't find what I'm looking for. So please, unless you find something in the old questions that actually answer my question, don't link them to me. I also searched in qt.digia.com and qt.project.com but again, no luck.

现在我的问题。我必须实现一个简单的图像比较器,并排显示图像,以便可以进行比较。我必须使用MVC来做到这一点。我的问题是,我从来没有使用Qt,我有点困惑,如何使用它与MVC。

So now to my problem. I have to implement a simple image comparator that shows to image side by side so that they can be compared. I have to use MVC to do this. My problem is that I've never used Qt and I'm a bit confused on how to use it with MVC.

特别是,我想知道MainWindow应该是什么子类。它是视图还是模型,还是两者?这是我想的。 MainWindow是一个视图在我的类图,但我不确定,因为它也具有模型的元素,因为它实际上存储数据信息。你建议什么?
那么如何设计其他类呢?谢谢。

In particular, I am wondering what MainWindow should be subclassed from. It is the View or the Model, or both? This is what I thought. MainWindow is a View in my class diagram, but I'm not sure of that, because it also has elements of a model, since it actually stores data information. What do you suggest? Then how would design the other classes? Thank you.

推荐答案

Qt没有实现标准MVC模式作为一个整体 - 你需要重新实现这样的框架从头开始。 Qt提供了一个模型视图框架,为MVVM提供了足够的功能,但这不是MVC的书。

Qt does not implement the "standard" MVC pattern as a whole - you would need to reimplement such a framework from scratch. Qt offers a model-view framework that offers enough functionality for MVVM, but that's not MVC-by-the-book.

在Qt的实现中,视图和控制器混合在一起。视图是向用户显示模型 在代表的帮助下,用户使用什么来与模型交互。

In Qt's implementation, the view and the controller are mingled together. The view is what shows the model to the user and what the user uses to interact with the model, with help of delegates.

一个单独的控制器的问题基本上是模糊的,因为没有一个。在Qt,一个具体的视图是一个独立的小部件,你通常不从中得到。

Thus, the question of a separate controller is essentially moot, as there isn't one. In Qt, a concrete view is a stand-alone widget that you normally don't derive from. Instead, you integrate (has-a) the view into a larger widget that holds other controls.

Qt提供了一些标准视图(列表视图,表视图和一个视图)树视图)。还有 QDataWidgetMapper ,可让您将模型中的一个索引映射到任何窗口小部件的用户属性。还有几种型号可供选择。抽象模型是您自己实现的基础。然后是 QStandardItemModel ,它提供了灵活的树/表存储数据。最后, QSqlQueryModel QSqlRelationalTableModel 公开SQL数据库作为模型。

Qt provides some standard views (a list view, a table view and a tree view). There's also the QDataWidgetMapper that lets you map one index from a model onto the user property of any widget. There are also several models to choose from. The abstract models are bases for your own implementations. Then there's the QStandardItemModel that provides a flexible tree/table storage of data. Finally, QSqlQueryModel and QSqlRelationalTableModel expose SQL databases as models.

在下面的示例中,比较器实现为viewmodel - 一个代理,用于使用比较结果修正底层图像提供模型。对于要显示的图像,它们需要在 Qt :: DecorationRole 下提供。主窗口只是视图(is-a),不需要子类化。

In the example below, the comparator is implemented as a viewmodel - a proxy that amends the underlying image-providing model with results of the comparison. For the images to be displayed, they need to be provided under the Qt::DecorationRole. The main window is simply the view (is-a), and no subclassing is necessary.

#include <QApplication>
#include <QTableView>
#include <QIdentityProxyModel>
#include <QStandardItemModel>
#include <QPainter>

/** Adds image comparison results to a table/tree with pairs of images in each row.
 *
 * This is a viewmodel that expects a table or tree with row containing pairs of images in the
 * first two columns. Comparison results are visualized as the added last column.
 * A null result is provided for rows that don't have two images as their first two columns.
 */
class Comparator : public QIdentityProxyModel {
   Q_OBJECT
   bool isLastColumn(const QModelIndex & proxyIndex) const {
      return proxyIndex.column() == columnCount(proxyIndex.parent()) - 1;
   }
   QModelIndex indexInColumn(int column, const QModelIndex & proxyIndex) const {
      return index(proxyIndex.row(), column, proxyIndex.parent());
   }
   /** Compares the two images, returning their difference..
    * Both images are expanded to the larger of their sizes. Missing data is filled with
    * transparent pixels. The images can be in any format. The difference is in ARGB32. */
   QImage compare(const QImage & left, const QImage & right) const {
      QImage delta(left.size().expandedTo(right.size()), QImage::Format_ARGB32);
      delta.fill(Qt::transparent);
      QPainter p(&delta);
      p.setRenderHint(QPainter::Antialiasing);
      p.drawImage(0, 0, left);
      p.setCompositionMode(QPainter::CompositionMode_Difference);
      p.drawImage(0, 0, right);
      return delta;
   }
public:
   Comparator(QObject * parent = 0) : QIdentityProxyModel(parent) {}
   QModelIndex index(int row, int column, const QModelIndex &parent) const Q_DECL_OVERRIDE {
      if (column != columnCount(parent) - 1)
         return QIdentityProxyModel::index(row, column, parent);
      return createIndex(row, column, parent.internalPointer());
   }
   int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE {
      return sourceModel()->columnCount(mapToSource(parent)) + 1;
   }
   QVariant data(const QModelIndex &proxyIndex, int role) const Q_DECL_OVERRIDE {
      if (isLastColumn(proxyIndex)) {
         QVariant left = data(indexInColumn(0, proxyIndex), role);
         QVariant right = data(indexInColumn(1, proxyIndex), role);
         if (!left.canConvert<QImage>() || !right.canConvert<QImage>()) return QVariant();
         return QVariant::fromValue(compare(left.value<QImage>(), right.value<QImage>()));
      }
      return QAbstractProxyModel::data(proxyIndex, role);
   }
};

QImage sector(qreal diameter, qreal size, qreal start, qreal end, const QColor & color)
{
   QImage image(size, size, QImage::Format_ARGB32_Premultiplied);
   image.fill(Qt::transparent);
   QPainter p(&image);
   p.setRenderHint(QPainter::Antialiasing);
   p.setPen(Qt::NoPen);
   p.setBrush(color);
   p.drawPie(QRectF(size-diameter, size-diameter, diameter, diameter),
             qRound(start*16), qRound((end-start)*16));
   return image;
}

QStandardItem * imageItem(const QImage & image) {
   QScopedPointer<QStandardItem> item(new QStandardItem);
   item->setEditable(false);
   item->setSelectable(false);
   item->setData(QVariant::fromValue(image), Qt::DecorationRole);
   item->setSizeHint(image.size());
   return item.take();
}

typedef QList<QStandardItem*> QStandardItemList;

int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   QStandardItemModel images;
   Comparator comparator;
   QTableView view;
   comparator.setSourceModel(&images);
   view.setModel(&comparator);

   images.appendRow(QStandardItemList()
                    << imageItem(sector(150, 160, 30, 100, Qt::red))
                    << imageItem(sector(150, 160, 60, 120, Qt::blue)));
   images.appendRow(QStandardItemList()
                    << imageItem(sector(40, 45, 0, 180, Qt::darkCyan))
                    << imageItem(sector(40, 45, 180, 360, Qt::cyan)));

   view.resizeColumnsToContents();
   view.resizeRowsToContents();
   view.adjustSize();
   view.show();

   return a.exec();
}

#include "main.moc"

这篇关于Qt模型 - 视图 - 控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆