【Qt筆記】QStringListModel

上一章咱們已經瞭解到有關 list、table 和 tree 三個最經常使用的視圖類的便捷類的使用。前面也提到過,因爲這些類僅僅是提供方便,功能、實現天然不如真正的 model/view 強大。從本章起,咱們將瞭解最基本的 model/view 模型的使用。數據結構

既然是 model/view,咱們也會分爲兩部分:model 和 view。本章咱們將介紹 Qt 內置的最簡單的一個模型:QStringListModel。接下來,咱們再介紹另外的一些內置模型,在此基礎上,咱們將瞭解到 Qt 模型的基本架構,以便爲最高級的應用——自定義模型——打下堅實的基礎。架構

 

QStringListModel是最簡單的模型類,具有向視圖提供字符串數據的能力。QStringListModel是一個可編輯的模型,能夠爲組件提供一系列字符串做爲數據。咱們能夠將其看做是封裝了QStringList的模型。QStringList是一種很經常使用的數據類型,其實是一個字符串列表(也就是QList<QString>)。既然是列表,它也就是線性的數據結構,所以,QStringListModel不少時候都會做爲QListView或者QComboBox這種只有一列的視圖組件的數據模型。函數

下面咱們經過一個例子來看看QStringListModel的使用。首先是咱們的構造函數:this

//MyListView.h
#ifndef MYLISTVIEW_H
#define MYLISTVIEW_H

#include <QWidget>

#include <QStringListModel>
#include <QListView>

class MyListView : public QWidget
{
    Q_OBJECT

public:
    MyListView(QWidget *parent = 0);
    ~MyListView();

private:
    QStringListModel *model;
    QListView *listView;

private slots:
    void insertData();
    void deleteData();
    void showData();
};

#endif // MYLISTVIEW_H



//MyListView.cpp
#include "MyListView.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QInputDialog>
#include <QLineEdit>
#include <QMessageBox>

MyListView::MyListView(QWidget *parent)
    : QWidget(parent)
{
    QStringList data;
    data << "Letter A" << "Letter B" << "Letter C";
    model = new QStringListModel(this);
    model->setStringList(data);

    listView = new QListView(this);
    listView->setModel(model);

    QHBoxLayout *btnLayout = new QHBoxLayout;
    QPushButton *insertBtn = new QPushButton(tr("insert"), this);
    connect(insertBtn, SIGNAL(clicked()), this, SLOT(insertData()));
    QPushButton *delBtn = new QPushButton(tr("Delete"), this);
    connect(delBtn, SIGNAL(clicked()), this, SLOT(deleteData()));
    QPushButton *showBtn = new QPushButton(tr("Show"), this);
    connect(showBtn, SIGNAL(clicked()), this, SLOT(showData()));
    btnLayout->addWidget(insertBtn);
    btnLayout->addWidget(delBtn);
    btnLayout->addWidget(showBtn);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(listView);
    mainLayout->addLayout(btnLayout);
    setLayout(mainLayout);
}

首先,咱們建立了一個QStringList對象,向其中插入了幾個數據;而後將其做爲QStringListModel的底層數據。這樣,咱們能夠理解爲,QStringListModelQStringList包裝了起來。剩下來的只是簡單的界面代碼,這裏再也不贅述。試運行一下,程序應該是這樣的:code

接下來咱們來看幾個按鈕的響應槽函數。orm

void MyListView::insertData()
{
    bool isOK;
    QString text = QInputDialog::getText(this, "Insert",
                                         "Please input new data:",
                                         QLineEdit::Normal,
                                         "You are inserting new data.",
                                         &isOK);
    if (isOK) {
        int row = listView->currentIndex().row();
        model->insertRows(row, 1);
        QModelIndex index = model->index(row);
        model->setData(index, text);
        listView->setCurrentIndex(index);
        listView->edit(index);
    }
}

首先是insertData()函數。咱們使用QInputDialog::getText()函數要求用戶輸入數據。這是 Qt 的標準對話框,用於獲取用戶輸入的字符串。這部分在前面的章節中已經講解過。當用戶點擊了 OK 按鈕,咱們使用listView->currentIndex()函數,獲取QListView當前行。這個函數的返回值是一個QModelIndex類型。咱們會在後面的章節詳細講解這個類,如今只要知道這個類保存了三個重要的數據:行索引、列索引以及該數據屬於哪個模型。咱們調用其row()函數得到行索引,該返回值是一個 int,也就是當前是第幾行。而後咱們向模型插入新的一行。insertRows()函數簽名以下:對象

bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());

該函數會將 count 行插入到模型給定的 row 的位置,新行的數據將會做爲 parent 的子元素。若是 row 爲 0,新行將被插入到 parent 的全部數據以前,不然將在指定位置的數據以前。若是 parent 沒有子元素,則會新插入一個單列數據。函數插入成功返回 true,不然返回 false。咱們在這段代碼中調用的是insertRows(row, 1)。這是QStringListModel的一個重載。參數 1 說明要插入 1 條數據。記得以前咱們已經把 row 設置爲當前行,所以,這行語句其實是在當前的 row 位置插入 count 行,這裏的 count 爲 1。因爲咱們沒有添加任何數據,實際效果是,咱們在 row 位置插入了 1 個空行。而後咱們使用 model 的index()函數獲取當前行的QModelIndex對象,利用setData()函數把咱們用QInputDialog接受的數據設置爲當前行數據。接下來,咱們使用setCurrentIndex()函數,把當前行設爲新插入的一行,並調用edit()函數,使這一行能夠被編輯。索引

以上是咱們提供的一種插入數據的方法:首先插入空行,而後選中新插入的空行,設置新的數據。這實際上是一種冗餘操做,由於currentIndex()已經獲取到當前行。在此,咱們僅僅是爲了介紹這些函數的使用。所以,除去這些冗餘,咱們可使用一種更簡潔的寫法:rem

void MyListView::insertData()
{
    bool isOK;
    QString text = QInputDialog::getText(this, "Insert",
                                         "Please input new data:",
                                         QLineEdit::Normal,
                                         "You are inserting new data.",
                                         &isOK);
    if (isOK) {
        QModelIndex currIndex = listView->currentIndex();
        model->insertRows(currIndex.row(), 1);
        model->setData(currIndex, text);
        listView->edit(currIndex);
    }
}

接下來是刪除數據:字符串

void MyListView::deleteData()
{
    if (model->rowCount() > 1) {
        model->removeRows(listView->currentIndex().row(), 1);
    }
}

使用模型的removeRows()函數能夠輕鬆完成這個操做。這個函數同前面所說的insertRows()很相似,這裏再也不贅述。須要注意的是,咱們用rowCount()函數判斷了一下,要求最終始終保留 1 行。這是由於咱們寫的簡單地插入操做所限制,若是把數據所有刪除,就不能再插入數據了。因此,前面所說的插入操做實際上還須要再詳細考慮才能夠解決這一問題。

最後是簡單地將全部數據都顯示出來:

void MyListView::showData()
{
    QStringList data = model->stringList();
    QString str;
    foreach(QString s, data) {
        str += s + "\n";
    }
    QMessageBox::information(this, "Data", str);
}

這段代碼沒什麼好說的。

關於QStringListModel咱們簡單介紹這些。從這些示例中能夠看到,幾乎全部操做都是針對模型的,也就是說,咱們直接對數據進行操做,當模型檢測到數據發生了變化,會馬上通知視圖進行刷新。這樣,咱們就能夠把精力集中到對數據的操做上,而不用擔憂視圖的同步顯示問題。這正是 model/view 模型所帶來的一個便捷之處。

相關文章
相關標籤/搜索