alexltr的个人主页

http://www.qtcn.org/bbs/u/107032  [收藏] [复制]

alexltr

我不是IT,只是喜欢Qt。 我不是程序员,只是与程序有缘。

  • 26

    关注

  • 60

    粉丝

  • 150

    访客

  • 等级:骑士
  • 身份:论坛版主
  • 总积分:537
  • 男,1976-01-01
  • 广州

最后登录:2024-04-20

更多资料

日志

Model/View Programming 模型与视图编程 -- <6>

2012-04-29 14:24
Creating new models
建立新的模型


The separation of functionality between themodel/view components allows models to be created that can take advantage ofexisting views. This approach lets us present data from a variety of sourcesusing standard graphical user interface components, such as QListView, QTableView, and QTreeView.
模型与视图的部件在功能上的分离,使得可以建立模型并能利用现有的视图。这种方法让我们可以使用标准的图形用户界面部件,如QListView, QTableView, 和QTreeView,来呈现多样化来源的数据。

The QAbstractItemModel class provides an interfacethat is flexible enough to support data sources that arrange information inhierarchical structures, allowing for the possibility that data will beinserted, removed, modified, or sorted in some way. It also provides supportfor drag and drop operations.
QAbstractItemModel类提供了一个足够灵活的接口,它支持以层次结构安排信息的数据源,为数据的插入,移动,修改或排序提供了可能性。它同时对拖放操作也提供支持。

The QAbstractListModel and QAbstractTableModel classes provide support for interfacesto simpler non-hierarchical data structures, and are easier to use as astarting point for simple list and table models.
QAbstractListModel 和 QAbstractTableModel 类为较简单的无层次数据结构的接口提供支持,同时用作简单列表和表格模型的起点(模型基类)会比较容易使用。

In this section,we create a simple read-only model to explore the basic principles of themodel/view architecture. Later in this section, we adapt this simple model sothat items can be modified by the user.
For an example ofa more complex model, see the Simple Tree Model example.
The requirementsof QAbstractItemModel subclasses is described in more detailin the Model Subclassing Reference document.
在这一节中,我们建立一个简单的唯读模型来了解模型/视图结构的基本原则。然后我们改写这个简单模型使得用户可以修改项。
对于更为复杂的模型,请看例子Simple Tree Model
关于子类化QAbstractItemModel 的要求在 Model Subclassing Reference子类化模型参考的文档中会有更加详细的描述。

Designing a model
模型设计

When creating a new model for an existing datastructure, it is important to consider which type of model should be used toprovide an interface onto the data. If the data structure can be represented asa list or table of items, you can subclass QAbstractListModel or QAbstractTableModel since these classes providesuitable default implementations for many functions.
当为一个现有的数据类型创建一个新的模型时,考虑哪一种类型的模型适合于为数据提供接口是很重要的。如果数据结构可以用一个列表或表格的项来表示,你可以子类化QAbstractListModel 或QAbstractTableModel,因为这两个类为很多函数提供了合适的默认实现。

However, if the underlying data structure can onlybe represented by a hierarchical tree structure, it is necessary to subclass QAbstractItemModel. This approach is taken in the Simple Tree Model example.
In this section, we implement a simple model basedon a list of strings, so the QAbstractListModel provides an ideal baseclass on which to build.
然而,如果底层的数据结构只能以层次树结构来表示,那就必须子类化 QAbstractItemModel类,在Simple Tree Model 例子中使用的就是这种方法。
在这一节中,我们实现一个基于字符串列表的简单模型,所以QAbstractListModel提供了一个理想的基类。

Whatever form the underlying data structure takes,it is usually a good idea to supplement the standard QAbstractItemModel API in specialized modelswith one that allows more natural access to the underlying data structure. Thismakes it easier to populate the model with data, yet still enables othergeneral model/view components to interact with it using the standard API. Themodel described below provides a custom constructor for just this purpose.
????????????????

A read-onlyexample model
一个唯读模型的例子
The model implemented here is a simple,non-hierarchical, read-only data model based on the standard QStringListModel class. It has a QStringList as its internal data source, and implements only what is needed tomake a functioning model. To make the implementation easier, we subclass QAbstractListModelbecause it defines sensible defaultbehavior for list models, and it exposes a simpler interface than the QAbstractItemModel class.
我们这里实现的模型是一个简单的,无层次的,唯读的,基于标准的QStringListModel 类的数据模型。它包含一个QStringList字符串列表作为他的内部数据源,它只实现一个功能性模型所需要的东西。为了使实现更加容易,我们子类化QAbstractListModel,因为它为列表模型定义了合理的默认行为,并且它有比QAbstractItemModel更简单的接口。

When implementing a model it is important toremember that QAbstractItemModel does not store any data itself, it merely presents an interface thatthe views use to access the data. For a minimal read-only model it is onlynecessary to implement a few functions as there are default implementations formost of the interface. The class declaration is as follows:
QAbstractItemModel本身并不存储任何数据,它只是提供一个视图用于存取数据的接口,当实现一个模型时,记住这一点很重要。对于一个微型的唯读模型,它只需要实现几个函数,因为大多数接口都有默认的实现。类的声明如下:
  1. class StringListModel :public QAbstractListModel
    {
         Q_OBJECT

    public:
         StringListModel(constQStringList &strings, QObject *parent = 0)
             : QAbstractListModel(parent),stringList(strings) {}

         int rowCount(constQModelIndex &parent = QModelIndex()) const;
         QVariant data(constQModelIndex &index, int role) const;
         QVariant headerData(intsection, Qt::Orientation orientation,
                             int role = Qt::DisplayRole)const;

    private:
         QStringList stringList;
    };

Apart from the model's constructor, we only needto implement two functions: rowCount() returns the number of rows in the model and data() returns an item of data corresponding to a specified model index.
Well behaved models also implement headerData() to give tree and table views something to display in their headers.
除了模型的构造函数,我们只需要实现两个函数:rowCount()返回模型里的行数,data()返回指定模型索引对应项的数据。好的模型同时还要实现headerData(),以便让树型或表格视图在它们的表头显示信息。

Note that this is a non-hierarchical model, so wedon't have to worry about the parent-child relationships. If our model washierarchical, we would also have to implement the index() and parent() functions.
The list of strings is stored internally in the stringList private member variable.
因为这是一个非层次结构的模型,所以我们不必担心父-子项关系。如果我们的模型是层次结构的,那我们还必须实现index() and parent()函数。字符串列表储存在内部的私有成员变量stringList中。

Dimensions ofthe model
模型大小

We want the number of rows in the model to be thesame as the number of strings in the string list. We implement the rowCount() function with this in mind:
我们想要模型的行数跟字符串列表中字符串的个数一样,在实现rowCount()函数时要记住这一点。
  1. int StringListModel::rowCount(const QModelIndex &parent) const
    {
         returnstringList.count();
    }

Since the model is non-hierarchical, we can safelyignore the model index corresponding to the parent item. By default, modelsderived fromQAbstractListModel only contain one column, sowe do not need to reimplement the columnCount() function.
因为模型是非层次结构的,因此我们可以忽略父项对应的模型索引。从QAbstractListModel派生出来的模型默认只保留一栏,所以我们不必重新实现 columnCount()函数。


Model headers & data
模型表头和数据

For items in the view, we want to return thestrings in the string list. The data() function is responsible for returning the item of data thatcorresponds to the index argument:
对于视图中的项,我们要返回字符串列表中的字符串。data()函数就是负责返回对应索引参数项的数据的:
  1. QVariantStringListModel::data(const QModelIndex &index, int role) const
    {
         if (!index.isValid())
             return QVariant();

         if (index.row() >=stringList.size())
             return QVariant();

         if (role ==Qt::DisplayRole)
             return stringList.at(index.row());
         else
             return QVariant();
    }


We only return a valid QVariant if the model index supplied is valid, the row number is within therange of items in the string list, and the requested role is one that wesupport.
Some views, such as QTreeView and QTableView,are able to display headers along with the item data. If our model is displayedin a view with headers, we want the headers to show the row and column numbers.We can provide information about the headers by subclassing the headerData() function:
如果提供的模型索引合法,行数在字符串项的范围内,且要求的角色是我们支持的,那我们只返回一个合法的QVariant。
一些视图,如QTreeView 和 QTableView,表头可以跟项数据一起显示。如果我们的模型用表头显示在视图中,我们想让表头显示行号和列号。我们可以通过子类化headerData() 函数来提供表头的相关信息。

  1. QVariantStringListModel::headerData(int section, Qt::Orientation orientation,
                                         int role) const
    {
         if (role !=Qt::DisplayRole)
             return QVariant();

         if (orientation ==Qt::Horizontal)
             returnQString("Column %1").arg(section);
         else
             returnQString("Row %1").arg(section);
    }


Again, we return a valid QVariant only if the role is one that we support. The orientation of theheader is also taken into account when deciding the exact data to return.Notall views display headers with the item data, and those that do may beconfigured to hide them. Nonetheless, it is recommended that you implement theheaderData() function to provide relevant information about the data provided bythe model.
记住,只有是支持的角色我们才返回一个合法的QVariant。当要确定返回的确切数据时,表头的方向也是要考虑的。不是所有的视图在显示项数据时都显示表头,那些不显示表头的视图可能已设定了隐藏表头。但是,我们还是建议你实现headerData()函数以便提供模型数据的相关信息。

An item can have several roles,giving out different data depending on the role specified. The items in ourmodel only have one role, DisplayRole,so we return the data for items irrespective of the role specified. However, wecould reuse the data we provide for the DisplayRole in other roles, such as the ToolTipRolethat views can use to displayinformation about items in a tooltip.
一个项可以有几个角色,依据指定的角色可以给出不同的数据。在我们现在创建的模型中,项只有一个角色DisplayRole,所以不管指定什么角色,我们都返回项的数据。然而,我们可以重新利用DisplayRole角色提供的数据用在其它角色上,如ToolTipRole角色,视图可以以工具提示的形式显示项的信息。

An editable model
可编辑模型

The read-only model shows how simple choices couldbe presented to the user but, for many applications, an editable list model ismuch more useful. We can modify the read-only model to make the items editableby changing the data() function we implemented for read-only, and byimplementing two extra functions: flags() and setData(). The following function declarations areadded to the class definition:
唯读模型显示了如何向用户呈现简单的选项,但是对于大多数的应用程序,一个可编辑的列表模型会更有用。我们可以通过改变前面那个为唯读模型而实现的data()函数,以及实现另外两个函数flags() 和 setData(),来把唯读模型改为可以编辑项的模型。下面的函数声明要加到类定义中:
  
  1.    Qt::ItemFlags flags(constQModelIndex &index) const;
         bool setData(constQModelIndex &index, const QVariant &value,
                      int role =Qt::EditRole);

Making the model editable
使模型可编辑

A delegate checks whether an item is editablebefore creating an editor. The model must let the delegate know that its itemsare editable. We do this by returning the correct flags for each item in themodel; in this case, we enable all items and make them both selectable andeditable:
在建立编辑器之前,委托会检查项是否可以编辑。模型必须让委托知道它的项是可以编辑的。我们可以通过为模型里的每一个项返回正确的标识来实现这个要求。在这个例子中,我们把所有的项激活并把它们设定为可选择及可编辑的:
  1. Qt::ItemFlagsStringListModel::flags(const QModelIndex &index) const
    {
         if (!index.isValid())
             returnQt::ItemIsEnabled;

         returnQAbstractItemModel::flags(index) | Qt::ItemIsEditable;
    }


Note that we do not have to know howthe delegate performs the actual editing process. We only have to provide a wayfor the delegate to set the data in the model. This is achieved through the setData() function:
我们不需要知道委托怎样执行实际的编辑过程。我们只需要为委托提供一个在模型中设定数据的方法。这个方法可以通过setData()函数来实现:

  1. bool StringListModel::setData(const QModelIndex &index,
                                  const QVariant &value, int role)
    {
         if (index.isValid()&& role == Qt::EditRole) {

             stringList.replace(index.row(),value.toString());
             emitdataChanged(index, index);
             return true;
         }
       return false;
    }
In this model, the item in the string list thatcorresponds to the model index is replaced by the value provided. However,before we can modify the string list, we must make sure that the index isvalid, the item is of the correct type, and that the role is supported. Byconvention, we insist that the role is theEditRole since this is the role usedby the standard item delegate. For boolean values, however, you can use Qt::CheckStateRole and set theQt::ItemIsUserCheckable flag; a checkbox is thenused for editing the value. The underlying data in this model is the same forall roles, so this detail just makes it easier to integrate the model withstandard components.
在这个模型中,对应模型索引的字符串项被提供的值所代替。然而,在我们修改字符串列表之前,我们必须保证索引是有效的,项是正确的类型,并且角色也是是支持的角色。按照常规,角色我们要用EditRole,因为它是标准项委托所使用的角色。然而,对于逻辑值,你可以使用角色Qt::CheckStateRole,并设定标识为Qt::ItemIsUserCheckable;这样就可以用一个复选框来编辑这个值了。对于所有的角色,这个模型中的底层数据都是一样的,所以这个细节只是为了让模型与标准部件结合使用时更加容易。

When the data has been set, the model must let theviews know that some data has changed. This is done by emitting the dataChanged() signal. Since only one itemof data has changed, the range of items specified in the signal is limited tojust one model index.
Also the data() function needs to bechanged to add the Qt::EditRole test:
当设定了数据以后,模型必须要让视图知道某些数据已经被改动。这个可以通过发射 dataChanged()信号来完成。。因为只有一个项的数据有更改,所以信号中所指定的项范围仅限于一个模型索引。
同时,data()函数也要更改以增加对 Qt::EditRole角色的检测
  1. QVariant StringListModel::data(constQModelIndex &index, int role) const
    {
         if (!index.isValid())
             return QVariant();

         if (index.row() >=stringList.size())
             return QVariant();

         if (role ==Qt::DisplayRole || role == Qt::EditRole)
             returnstringList.at(index.row());
         else
             return QVariant();
    }


Inserting & removing rows
插入和删除行

It is possible to change the numberof rows and columns in a model. In the string list model it only makes sense tochange the number of rows, so we only reimplement the functions for insertingand removing rows. These are declared in the class definition:
在一个模型中,行数和列数是可以改变的。在字符串列表模型中,则只需要改变行数就可以了。所以我们只实现插入和删除行的函数。这些函数在类定义中的声明如下:
  
  1.     bool insertRows(intposition, int rows, const QModelIndex &index = QModelIndex());
         bool removeRows(intposition, int rows, const QModelIndex &index = QModelIndex());

Since rows in this model correspondto strings in a list, the insertRows() function inserts a number of emptystrings into the string list before the specified position. The number ofstrings inserted is equivalent to the number of rows specified.
The parent index is normally used todetermine where in the model the rows should be added. In this case, we onlyhave a single top-level list of strings, so we just insert empty strings intothat list.
因为行在这个模型中对应的是一个列表中的字符串,所以insertRows()函数在字符串列表中指定的位置之前插入几个空的字符串。插入的字符串的个数跟所指定的行数是相等的。函数中的父索引通常是用来决定这些行应加在模型的什么位置。在这个例子中,我们只有一个顶层的字符串列表,所以我们把空字符串加到这个列表就可以了。
  1. bool StringListModel::insertRows(int position, int rows, const QModelIndex&parent)
    {
         beginInsertRows(QModelIndex(),position, position+rows-1);

         for (int row = 0; row< rows; ++row) {
            stringList.insert(position, "");
         }

         endInsertRows();
         return true;
    }

The model first calls the beginInsertRows() function to inform other componentsthat the number of rows is about to change. The function specifies the rownumbers of the first and last new rows to be inserted, and the model index fortheir parent item. After changing the string list, it calls endInsertRows() to complete the operation and informother components that the dimensions of the model have changed, returning trueto indicate success.
模型首先调用beginInsertRows()函数以通知其它部件行数将要改变。这个函数指定了所插入行的首行和末尾行的行号,以及父项的模型索引。当改变了字符串列表后,再调用endInsertRows()函数以完成操作并通知其它部件模型的大小已经改变,同时返回true值表明插入行的操作成功。


The function to remove rows from themodel is also simple to write. The rows to be removed from the model arespecified by the position and the number of rows given. We ignore the parentindex to simplify our implementation, and just remove the corresponding itemsfrom the string list.

从模型中删除行的函数写起来也很简单。通过给出位置和行数就可以从模型中删除指定的行。为了简化我们的实现,我们忽略父索引,只要从字符串列表中删除对应的项就可以了。
  1. bool StringListModel::removeRows(int position, int rows, const QModelIndex&parent)
    {
        beginRemoveRows(QModelIndex(), position, position+rows-1);

         for (int row = 0; row< rows; ++row) {
            stringList.removeAt(position);
         }

         endRemoveRows();
         return true;
    }



The beginRemoveRows() function is always called before anyunderlying data is removed, and specifies the first and last rows to beremoved. This allows other components to access the data before it becomesunavailable. After the rows have been removed, the model emits endRemoveRows() to finish the operation and let othercomponents know that the dimensions of the model have changed.
beginRemoveRows()函数必须要在删除任何底层数据之前调用,并且要指定删除行的首行和末尾行。这样就可以让其它部件在数据失效前存取数据。行被删除后,模型发射endRemoveRows() 信号以完成操作,并通知通知其它部件模型的大小已经改变。

Next steps
后续步骤

We can display the data provided bythis model, or any other model, using the QListView class to present the model's items inthe form of a vertical list. For the string list model, this view also providesa default editor so that the items can be manipulated. We examine thepossibilities made available by the standard view classes in View Classes.
通过使用QListView 类将模型的项展现在一个垂直列表表格中,我们就可以显示这个模型或其它模型提供的数据。对于字符串列表模型,视图同时也提供了一个默认的编辑器,以便对项进行操作。????

The ModelSubclassing Reference documentdiscusses the requirements of QAbstractItemModel subclasses in more detail, andprovides a guide to the virtual functions that must be implemented to enablevarious features in different types of models.
在模型子类化参考这节文档中详细地讨论了子类化QAbstractItemModel的要求,同时为那些必须实现的虚函数提供指引,以便在不同类型的模型中赋予各种特性。
分类:默认分类|回复:0|浏览:2156|全站可见|转载
 

Powered by phpwind v8.7 Certificate Copyright Time now is:04-28 13:58
©2005-2016 QTCN开发网 版权所有 Gzip disabled