alexltr的个人主页

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

alexltr

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

  • 26

    关注

  • 60

    粉丝

  • 150

    访客

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

最后登录:2024-04-20

更多资料

日志

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

2011-11-27 21:20

Delegate classes
委托类


Concepts
概念


Unlike the Model-View-Controller pattern, the model/view design does not include a completely separate component for managing interaction with the user. Generally, the view is responsible for the presentation of model data to the user, and for processing user input. To allow some flexibility in the way this input is obtained, the interaction is performed by delegates. These components provide input capabilities and are also responsible for rendering individual items in some views. The standard interface for controlling delegates is defined in the QAbstractItemDelegate class.
不同于模型-视图-控制器模式,模型/视图设计不包含用于处理与用户交互的完全独立的部件。通常,视图负责把模型数据显示给用户,以及处理用户的输入。为了让这种输入有灵活性,这种交互由委托来完成。这些部件在视图中提供输入功能,同时负责传递视图中的单个项。控制委托的标准接口在 QAbstractItemDelegate类中定义。

Delegates are expected to be able to render their contents themselves by implementing the paint() and sizeHint() functions. However, simple widget-based delegates can subclass QItemDelegate instead of QAbstractItemDelegate, and take advantage of the default implementations of these functions.
委托通过实现 paint() 和 sizeHint()函数来传递他们本身的内容。但是,简单的基于部件的委托可以子类化QItemDelegate 类而不是 QAbstractItemDelegate类,这样就可以利用这些函数的默认实现。

Editors for delegates can be implemented either by using widgets to manage the editing process or by handling events directly. The first approach is covered later in this section, and it is also shown in the Spin Box Delegate example.
The Pixelator example shows how to create a custom delegate that performs specialized rendering for a table view.
委托的编辑器可以通过使用部件来管理编辑的过程来实现,也可以通过直接处理事件来实现。第一种方法在这一节的后面会讲到,在Spin Box Delegate这个例子中也是使用的这种方法。
Pixelator这个例子演示了如何建立一个专门用于表格视图的自定义委托。???

Using an existing delegate
使用现有的委托


The standard views provided with Qt use instances of QItemDelegate to provide editing facilities. This default implementation of the delegate interface renders items in the usual style for each of the standard views: QListView, QTableView, and QTreeView.
All the standard roles are handled by the default delegate used by the standard views. The way these are interpreted is described in the QItemDelegate documentation.
The delegate used by a view is returned by the itemDelegate() function. The setItemDelegate() function allows you to install a custom delegate for a standard view, and it is necessary to use this function when setting the delegate for a custom view.
Qt提供的标准视图使用QItemDelegate的实例提供编辑功能。委托接口的预设实现以通常的样式将项传递给每一个标准视图:QListView, QTableView, 和 QTreeView。
所有的标准角色都由标准视图的预设委托处理。角色解释的方法在 QItemDelegate文档中有描述。
视图所使用的委托可以用itemDelegate() 函数返回。setItemDelegate()函数允许你为一个标准视图安装一个自定义的委托,当为自定义的视图设定一个委托时必须要用到这个函数。

A simple delegate
一个简单委托


The delegate implemented here uses a QSpinBox to provide editing facilities, and is mainly intended for use with models that display integers. Although we set up a custom integer-based table model for this purpose, we could easily have used QStandardItemModel instead, since the custom delegate controls data entry. We construct a table view to display the contents of the model, and this will use the custom delegate for editing.
下面要实现的委托用一个QSpinBox 来提供编辑功能,主要是想用于显示整数的模型。虽然我们基于这个目的建立了一个基于整数的自定义模型,但是我们可以很容易地以QStandardItemModel代替,因为自定义委托控制数据的输入。我们构造一个表格模型以显示模型里的内容,同时它会使用自定义的委托来进行编辑。


We subclass the delegate from QItemDelegate because we do not want to write custom display functions. However, we must still provide functions to manage the editor widget:
我们用QItemDelegate 类来子类化这个委托,因为我们不想去写那些自定义的显示函数。然而,我们必须提供下面的函数以管理编辑器部件:

  1. class SpinBoxDelegate : public QItemDelegate
    {    
          Q_OBJECT  
          public:     SpinBoxDelegate(QObject *parent = 0);
          QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                               const QModelIndex &index) const;
          void setEditorData(QWidget *editor, const QModelIndex &index) const;
         void setModelData(QWidget *editor, QAbstractItemModel *model,
                           const QModelIndex &index) const;
          void updateEditorGeometry(QWidget *editor,
             const QStyleOptionViewItem &option, const QModelIndex &index) const;
    };

Note that no editor widgets are set up when the delegate is constructed. We only construct an editor widget when it is needed.
注意,构造委托时编辑器部件是没有建立的。只有需要时我们才构造一个编辑器部件。

Providing an editor
提供编辑器


In this example, when the table view needs to provide an editor, it asks the delegate to provide an editor widget that is appropriate for the item being modified. The createEditor() function is supplied with everything that the delegate needs to be able to set up a suitable widget:
在这个例子中,当表格视图需要提供编辑器时,它就向委托请求提供一个适合当前被修改项的编辑器部件。createEditor()函数提供了委托用于建立一个合适部件需要的所有东西:

  1. [color=#000000]    QWidget *SpinBoxDelegate::createEditor(QWidget *parent, [/color]
         const QStyleOptionViewItem &/* option */,
         const QModelIndex &/* index */) const
    {
         QSpinBox *editor = new QSpinBox(parent);
         editor->setMinimum(0);
         editor->setMaximum(100);
          return editor;
    }


Note that we do not need to keep a pointer to the editor widget because the view takes responsibility for destroying it when it is no longer needed.
We install the delegate's default event filter on the editor to ensure that it provides the standard editing shortcuts that users expect. Additional shortcuts can be added to the editor to allow more sophisticated behavior; these are discussed in the section on Editing Hints.
注意,我们不需要保留一个指向编辑器部件的指针,因为当不再需要编辑器的时候,视图会负责销毁它。
我们把委托默认的事件过滤器安装在编辑器上,以确保它提供用户所期望的标准编辑快捷键。额外的快捷键也可以增加到编辑器上以允许更复杂的行为。这些会在“编辑提示”章节中讨论。

The view ensures that the editor's data and geometry are set correctly by calling functions that we define later for these purposes. We can create different editors depending on the model index supplied by the view. For example, if we have a column of integers and a column of strings we could return either aQSpinBox or a QLineEdit, depending on which column is being edited.
The delegate must provide a function to copy model data into the editor. In this example, we read the data stored in the display role, and set the value in the spin box accordingly.
通过调用我们稍后定义的函数,视图确保能正确地设定编辑器的数据和几何尺寸大小。根据视图提供的模型索引,我们可以建立不同的编辑器。比如,我们有一列数据是整数,一列数据是字符,那根据当前被编辑的列,我们可以返回一个SpinBox 或 QLineEdit。
委托必须提供一个函数以便将模型数据复制到编辑器里。在这个例子中,我们读取储存在显示角色 displayrole里的数据,并相应的把这个值设定在编辑器spin box中。


  1. [color=#000000] void SpinBoxDelegate::setEditorData(QWidget *editor, [/color]
                                         const QModelIndex &index) const
    {
         int value = index.model()->data(index, Qt::EditRole).toInt();
          QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
         spinBox->setValue(value);
    }



In this example, we know that the editor widget is a spin box, but we could have provided different editors for different types of data in the model, in which case we would need to cast the widget to the appropriate type before accessing its member functions.
在这个例子中,我们知道编辑器部件是一个spin box,但是在模型中,我们可能会因应不同的数据类型提供不同的编辑器,在存取它的成员函数前,我们需要将这个部件转换成适合的类型。

Submitting data to the model
向模型提交数据


When the user has finished editing the value in the spin box, the view asks the delegate to store the edited value in the model by calling the setModelData()function.
当用户在spin box中完成编辑数值时,通过调用 setModelData()函数,视图要求委托将被编辑后的值储存到模型中。


  1. [color=#000000]void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, [/color]
                                        const QModelIndex &index) const
    {
         QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
         spinBox->interpretText();
         int value = spinBox->value();
          model->setData(index, value, Qt::EditRole);
    }



Since the view manages the editor widgets for the delegate, we only need to update the model with the contents of the editor supplied. In this case, we ensure that the spin box is up-to-date, and update the model with the value it contains using the index specified.
因为视图为委托管理编辑器部件,所以我们只要以编辑器提供的内容更新模型就可以了。在这个例子中,我们确保spinbox的内容是最新的,同时通过指定的索引把spinbox包含的值更新到模型中。


The standard QItemDelegate class informs the view when it has finished editing by emitting the closeEditor() signal. The view ensures that the editor widget is closed and destroyed. In this example, we only provide simple editing facilities, so we need never emit this signal.
当委托完成编辑时,标准的QItemDelegate类会发出closeEditor()信号通知视图。视图确保关闭和销毁编辑器部件。在这个例子中,我们只提供简单的编辑功能,所以我们不需要发出这个信号。


All the operations on data are performed through the interface provided by QAbstractItemModel. This makes the delegate mostly independent from the type of data it manipulates, but some assumptions must be made in order to use certain types of editor widgets. In this example, we have assumed that the model always contains integer values, but we can still use this delegate with different kinds of models because QVariant provides sensible default values for unexpected data.
所有的数据操作都是通过QAbstractItemModel提供的接口进行的。这使得委托最大程度地独立于它所操控的数据类型。但是为了使用某些类型的编辑器部件,一些假设是必须要做的。在这个例子中,我们假设模型包含的数据全部是整数值,但是我们仍然可以将这个委托用于不同种类的模型,因为QVariant可以为没有考虑到的数据提供合理的默认值。

Updating the editor's geometry
更新编辑器外形


It is the responsibility of the delegate to manage the editor's geometry. The geometry must be set when the editor is created, and when the item's size or position in the view is changed. Fortunately, the view provides all the necessary geometry information inside a view option object.
编辑器的几何外形由委托负责管理。当创建编辑器时,以及视图中项的大小及位置改变时,都必须设定编辑器的几何外形。幸好,在视图中,view option对象中提供了所有必需的几何尺寸信息。
  1. [color=#000000] void SpinBoxDelegate::updateEditorGeometry(QWidget *editor, [/color]
         const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
    {    
          editor->setGeometry(option.rect);
    }



In this case, we just use the geometry information provided by the view option in the item rectangle. A delegate that renders items with several elements would not use the item rectangle directly. It would position the editor in relation to the other elements in the item.
在这个例子中,我们只是使用了view option提供的项矩形几何尺寸信息。传递多个要素项的委托不会直接使用项矩形。它会因应项中的其它要素定位编辑器的位置。

Editing hints
编辑提示


After editing, delegates should provide hints to the other components about the result of the editing process, and provide hints that will assist any subsequent editing operations. This is achieved by emitting the closeEditor() signal with a suitable hint. This is taken care of by the default QItemDelegateevent filter which we installed on the spin box when it was constructed.
编辑后,委托应该为其他部件提供关于编辑结果的提示,同时提供协助后续编辑操作的提示。这个可以通过发射closeEditor()信号以及一个合适的提示来实现。这个过程由默认的QItemDelegate事件过滤器负责。 在构造spinbox时,这个事件过滤器就已安装了。


The behavior of the spin box could be adjusted to make it more user friendly. In the default event filter supplied by QItemDelegate, if the user hits Return to confirm their choice in the spin box, the delegate commits the value to the model and closes the spin box. We can change this behavior by installing our own event filter on the spin box, and provide editing hints that suit our needs; for example, we might emit closeEditor() with the EditNextItem hint to automatically start editing the next item in the view.
Spinbox的行为可以稍作调整以使它更易用。在QItemDelegate提供的默认事件过滤器中,如果用户按回车来确认他们在spinbox中的选择,那委托就把值提交给模型并关闭spinbox。通过在spinbox中安装我们自己的事件过滤器,我们可以改变这种行为,并提供适合我们需要的编辑提示;比如,我们可以用EditNextItem提示来发射closeEditor()信号,来自动地开始视图中下一个项的编辑。

Another approach that does not require the use of an event filter is to provide our own editor widget, perhaps subclassing QSpinBox for convenience. This alternative approach would give us more control over how the editor widget behaves at the cost of writing additional code. It is usually easier to install an event filter in the delegate if you need to customize the behavior of a standard Qt editor widget.
Delegates do not have to emit these hints, but those that do not will be less integrated into applications, and will be less usable than those that emit hints to support common editing actions.
另一种不需要使用事件过滤器的方法就是提供我们自己的编辑器部件,或者是为了方便那就是子类化QSpinbox。这种方法让我们对编辑器的行为有更多的控制,而这需要以写额外的代码作为代价。如果你要自定义一个标准Qt编辑器部件的行为,那么在委托中安装事件过滤器通常来说是较容易的。
委托不必一定要发射这些提示,但相对于那些发射提示以支持通用编辑动作的委托,他们跟程序的整合性就会降低,所起的作用也很小。

分类:默认分类|回复:0|浏览:2313|全站可见|转载
 

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