Qt之模型/視圖(委託)


概念
不一樣於模型 - 視圖 - 控制器模式,模型/視圖設計不包括用於管理與用戶交互的一個徹底獨立的組件。通常狀況,視圖負責將模型數據呈現給用戶以及處理用戶輸入。爲了輸入更加具備靈活性,則由委託來執行交互。這些組件提供輸入功能,且在一些視圖中還負責渲染個別項目。控制委託的標準接口在QAbstractItemDelegate類中定義。
委託可以經過實現的paint()和sizeHint()函數來展現它們的內容。然而,簡單基礎部件的委託能夠繼承QItemDelegate而不是QAbstractItemDelegate,並使用這些函數的默認實現。
委託編輯器能夠經過使用小工具來管理編輯過程或直接處理事件來實現。

使用現有委託
Qt提供的標準視圖中使用QItemDelegate提供編輯功能。委託接口的默認實現以一向風格來呈現項目爲每一個標準視圖:QListView、QTableView、QTreeView。
全部標準角色由所使用的標準視圖中的默認委託處理。
視圖使用委託是由itemDelegate()函數返回。setItemDelegate()函數容許你爲標準視圖設定一個自定義委託,爲自定義視圖設定委託時,有必要使用此功能。

一個簡單的委託
這裏實現的委託使用QSpinBox來提供編輯功能,主要用於模型處理整數。雖然爲了這個目的咱們設置了一個自定義的基於整數的表模型,咱們能夠很容易地使用QStandardItemModel來代替,由於自定義委託控制數據輸入。咱們構造了一個表視圖來顯示模型的內容,可使用自定義的委託來進行編輯。

咱們的委託繼承於QItemDelegate,由於咱們不想編寫自定義顯示功能。然而,仍然必須提供管理編輯器窗口小部件的功能:
class SpinBoxDelegate : public QStyledItemDelegate
{
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;
};
提供了一個編輯器
在這個例子中,當表視圖須要提供一個編輯器時,它將要求委託提供一個編輯器部件適用於修改該項目。createEditor()函數提供一切,委託須要可以創建一個合適的窗口小部件:
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &,
const QModelIndex &) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setMaximum(100);

return editor; }
注意,咱們不須要一個指向編輯器的部件,由於當再也不須要時,視圖負責銷燬它。
在編輯器上安裝代理的默認事件過濾器,以確保它提供了用戶所指望的標準編輯快捷方式。編輯器中能夠添加額外的快捷鍵,以容許更復雜的行爲。
能夠根據視圖提供的模型索引建立不一樣的編輯器。例如,若是有一個整數列和字符串列,咱們能夠返回一個QSpinBox或QLineEdit,這取決於哪一列正在被編輯。
委託必須提供一個函數將模型中的數據複製到編輯器中。在這個例子中,咱們讀出存儲在顯示角色中的數據,並在QSpinBox中設置的值相應。
void SpinBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<<span style=" color:#800080;">QSpinBox*>(editor);
spinBox->setValue(value);
}
在這個例子中,咱們知道編輯器部件是一個QSpinBox,但能夠爲模型中不一樣類型的數據提供不一樣的編輯器,在這種狀況下,則須要在訪問它的成員函數以前設置部件爲適當的類型。
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<<span style=" color:#800080;">QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
因爲視圖爲委託管理編輯器部件,因此只須要以編輯器提供的內容來更新模型。在這種狀況下,咱們確QSpinBox是最新更新,並使用指定的索引包含的值來更新模型。
標準的QItemDelegate類經過發射closeEditor()信號來完成編輯視圖。視圖可確保編輯器部件被關閉和銷燬。在這個例子中,咱們只提供簡單的編輯功能,因此咱們須要永遠不會發出這個信號。
全部的數據操做經過QAbstractItemModel提供的接口執行。這使得委託大多獨立於它操縱的數據的類型,但爲了使用某些類型的編輯器部件,則必須作出一些假設。在這個例子中,咱們假設模型老是包含整數值,但咱們仍然在不一樣類型的模型中使用此委託,由於的QVariant爲意想不到的數據提供了合理的默認值。

更新編輯器的幾何形狀
管理編輯器的幾何形狀是委託的責任。當編輯器被建立,或者當項目視圖的的位置、大小在視圖中改變時,幾何形狀必須被設置。幸運的是,視圖提供了視圖選項物體內部全部必要的幾何信息。
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &) const
{
editor->setGeometry(option.rect);
}
這種狀況下,咱們僅在項目區域中使用視圖選項提供的位置信息。使用一些元素展示項目的委託不會直接使用該項目矩形。根據這個項目中的其餘元素來設定編輯器的位置。
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QStandardItemModel model(4, 2);
QTableView tableView;
tableView.setModel(&model);
SpinBoxDelegate delegate;
tableView.setItemDelegate(&delegate);
tableView.horizontalHeader()->setStretchLastSection(true);
for (int row = 0; row <<span style=" color:#c0c0c0;"> 4; ++row) {
for (int column = 0; column <<span style=" color:#c0c0c0;"> 2; ++column) {
QModelIndex index = model.index(row, column, QModelIndex());
model.setData(index, QVariant((row + 1) * (column + 1)));
}
}
tableView.setWindowTitle(QObject::tr("Spin Box Delegate"));
tableView.show();
return app.exec();
}app

相關文章
相關標籤/搜索