QStringListModel

2018-10-07 15:20 更新

QStringListModel

今天開(kāi)始我們要看看 Qt 的 model-view 類(lèi)了。正如前面說(shuō)的那樣,之前三節(jié)的 item class 類(lèi)只是Qt 為了方便我們使用而封裝了的一些操作。比起真正的 model-view 類(lèi)來(lái),那些類(lèi)更易于使用,但是功能也會(huì)更簡(jiǎn)單,并且缺少實(shí)時(shí)性的支持,比如我們并不方便實(shí)現(xiàn)插入、刪除等一些常見(jiàn)操作。而現(xiàn)在我們要說(shuō)的 model-view 類(lèi)使用起來(lái)可能會(huì)復(fù)雜一些,但是功能強(qiáng)大,并且在 model 更新時(shí)會(huì)自動(dòng)更新view,而 model 多是一些數(shù)據(jù)集合,因此比較便于操作。

model-view 類(lèi)中,view 大致有三種:list、tree 和 table,但是 model 千奇百怪,不同的業(yè)務(wù),甚至同樣的業(yè)務(wù)不同的建模都會(huì)有不同的 model。為了方便使用,Qt 提供了一些預(yù)定義好的 model 供我們使用。QStringListModel 是其中最簡(jiǎn)單的一種。

顧名思義,QStringListModel 就是封裝了 QStringList 的 model。QStringList 是一種很常用的數(shù)據(jù)類(lèi)型,它實(shí)際上是一個(gè)字符串列表。我們可以想象,對(duì)于一個(gè) list 來(lái)說(shuō),如果提供一個(gè)字符串列表形式的數(shù)據(jù),就應(yīng)該能夠把這個(gè)數(shù)據(jù)展示出來(lái)。因?yàn)槎呤且恢碌模篞StringList 是線(xiàn)性的,而list 也是線(xiàn)性的。所以,QStringListModel 很多時(shí)候都會(huì)作為 QListView 的 model。

下面我們來(lái)看怎么使用它們。比起前面的 QListWidget,這里要使用兩個(gè)類(lèi):QStringListModel 和QListView,并且還有一些輔助類(lèi)。不過(guò)你可以看到,即便這樣復(fù)雜的工作,我們的代碼也不會(huì)很多的:

mylistview.h


#ifndef MYLISTVIEW_H 
#define MYLISTVIEW_H 

#include <QtGui> 

class MyListView : public QWidget 
{ 
        Q_OBJECT 
public: 
        MyListView(); 

private: 
        QStringListModel *model; 
        QListView *listView; 

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

#endif // MYLISTVIEW_H

mylistview.cpp


#include "mylistview.h" 

MyListView::MyListView() 
{ 
        model = new QStringListModel(this); 
        QStringList data; 
        data << "Letter A" << "Letter B" << "Letter C"; 
        model->setStringList(data); 
        listView = new QListView(this); 
        listView->setModel(model); 
        QHBoxLayout *btnLayout = new QHBoxLayout; 
        QPushButton *insertBtn = new QPushButton(tr("insert"), this); 
        QPushButton *delBtn = new QPushButton(tr("Delete"), this); 
        QPushButton *showBtn = new QPushButton(tr("Show"), this); 
        btnLayout->addWidget(insertBtn); 
        btnLayout->addWidget(delBtn); 
        btnLayout->addWidget(showBtn); 
        QVBoxLayout *mainLayout = new QVBoxLayout(this); 
        mainLayout->addWidget(listView); 
        mainLayout->addLayout(btnLayout); 
        this->setLayout(mainLayout); 

        connect(insertBtn, SIGNAL(clicked()), this, SLOT(insertData())); 
        connect(delBtn, SIGNAL(clicked()), this, SLOT(deleteData())); 
        connect(showBtn, SIGNAL(clicked()), this, SLOT(showData())); 
} 

void MyListView::insertData() 
{ 
        bool isOK; 
        QString text = QInputDialog::getText(NULL, "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); 
        } 
} 

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

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

        QMessageBox::information(this, "Data", str); 
} 

來(lái)看看我們的代碼吧。

首先我們創(chuàng)建一個(gè) QStringListModel 的對(duì)象。然后創(chuàng)建一個(gè) QStringList 對(duì)象,并且把這個(gè)對(duì)象設(shè)置為 model 的數(shù)據(jù)。此時(shí),這個(gè) model 已經(jīng)擁有數(shù)據(jù)了。然后,我們創(chuàng)建一個(gè) QListView 的對(duì)象,并把 model 設(shè)置為它的 model。后面是三個(gè)按鈕的創(chuàng)建以及信號(hào)槽的連接,這里就不再贅述。

先來(lái)運(yùn)行一下看看結(jié)果吧!

我們只是把 QStringListModel 設(shè)置為 QListView 的 model,QListView 就已經(jīng)可以把 model 里面的數(shù)據(jù)展示出來(lái)了。下面我們看看增、刪、改的操作。

先來(lái)看增加數(shù)據(jù)的操作。這部分是在代碼中的 insertData()函數(shù)實(shí)現(xiàn)的。先把那個(gè)函數(shù)拿出來(lái)看看:


void MyListView::insertData() 
{ 
        bool isOK; 
        QString text = QInputDialog::getText(NULL, "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); 
        } 
}

我們使用 QInputDialog::getText()函數(shù)要求用戶(hù)輸入數(shù)據(jù)。這部分在前面講過(guò),這里也不再贅述。如果用戶(hù)點(diǎn)擊了 OK 按鈕,首先,我們使用 listView()->currentIndex()函數(shù),獲取 QListView當(dāng)前行。注意,這個(gè)函數(shù)的返回值是一個(gè) QModelIndex 類(lèi)型。這個(gè)類(lèi)我們以后再說(shuō),只要知道這個(gè)類(lèi)保存了三個(gè)重要的數(shù)據(jù):行、列以及屬于哪一個(gè) model。我們調(diào)用其 row()函數(shù)獲得行,這個(gè)返回值是一個(gè) int,也就是第幾行。然后 model 插入一行。insertRows()函數(shù)簽名如下:


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

這個(gè)函數(shù)原本是 QAbstractListModel 類(lèi)的函數(shù),而 QStringListModel 把它覆蓋了。所以我們會(huì)發(fā)現(xiàn)它還需要另外的一個(gè)參數(shù)。我們調(diào)用 insertRows(row, 1); ,所謂1就是指插入1條數(shù)據(jù),而前面又把 row 保存成當(dāng)前行,因此,這行語(yǔ)句實(shí)際上是在當(dāng)前的 row 行插入 count 行,這里的 count = 1。然后我們使用 model 的 index()函數(shù)獲取當(dāng)前行的 QModelIndex 對(duì)象,使用 setData()函數(shù)把我們用 QInputDialog 接受的數(shù)據(jù)插入。這里其實(shí)是一個(gè)冗余的操作,因?yàn)橛?currentIndex()函數(shù)已經(jīng)獲取當(dāng)前行了。這么寫(xiě)僅僅是為了展示如何使用這個(gè)函數(shù)。不過(guò),你知道了 insertRow()函數(shù),就可以很容易的做出插入空白行的效果了。然后我們把當(dāng)前行設(shè)為新插入的一行,并調(diào)用 edit()函數(shù),這個(gè)函數(shù)使得這一行可以被編輯。就這樣,我們向 model 插入了數(shù)據(jù)。

然后來(lái)看刪除數(shù)據(jù)的操作:


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

使用 model 的 removeRows()函數(shù)可以輕松的完成這個(gè)功能。這個(gè)函數(shù)同前面所說(shuō)的 insertRows()很類(lèi)似,就不再多說(shuō)了。需要注意的是,我們用 rowCount()函數(shù)判斷了一下,要求最終始終保留1行。這是因?yàn)槿绻惆褦?shù)據(jù)全部刪除,你就不能再插入數(shù)據(jù)了,因?yàn)槟菚r(shí)侯按照我們所寫(xiě)的插入邏輯就不對(duì)了。所以,前面所說(shuō)的插入操作實(shí)際上還需要再詳細(xì)考慮。

最后那個(gè) showData()僅僅為了查看 model 的數(shù)據(jù),沒(méi)有什么要說(shuō)的東西。你可以在 insert 或者remove 完成后查看一下 model 里面的數(shù)據(jù)是不是真的被修改了。

關(guān)于 QStringListModel 就說(shuō)這么多。你可以看到,我們的幾乎所有操作都是針對(duì) model 的,也就是說(shuō),我們直接針對(duì)的是數(shù)據(jù),而 model 偵測(cè)到數(shù)據(jù)發(fā)生了變化,會(huì)立刻通知 view 刷新。這樣,我們就可以把精力集中到對(duì)數(shù)據(jù)的操作上,而不用擔(dān)心 view 的同步等操作。這也是 model-view 模型的一個(gè)便捷之處。

本文出自 “豆子空間” 博客,請(qǐng)務(wù)必保留此出處 http://devbean.blog.51cto.com/448512/193918

以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)