在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C/ 自定義 model 之二
Qt 容器和算法拾遺
自定義 model 之一
反走樣
Hello, world!
Qt 容器類之關(guān)聯(lián)存儲(chǔ)容器
QStringListModel
拖放技術(shù)之一
狀態(tài)欄
QTreeWidget
拖放技術(shù)之二
通用算法
event()
Qt 學(xué)習(xí)之路(18): Qt 標(biāo)準(zhǔn)對(duì)話框之 QInputDialog
Qt 容器類之遍歷器和隱式數(shù)據(jù)共享
QListWidget
Meta-Object 系統(tǒng)
事件接收與忽略
Qt 學(xué)習(xí)之路(tip): parent 參數(shù)
Qt 標(biāo)準(zhǔn)對(duì)話框之 QColorDialog
QPainter(續(xù))
國(guó)際化(下)
漸變填充
自定義委托
創(chuàng)建 shared library
model-view 架構(gòu)
Graphics View Framework
自定義拖放數(shù)據(jù)對(duì)象
QSortFilterProxyModel
國(guó)際化(上)
組件布局
自定義 Model 之三
事件過濾器
QDirModel
Hello, world!(續(xù))
Qt 標(biāo)準(zhǔn)對(duì)話框之 QFileDialog
自定義 model 之二
深入了解信號(hào)槽
坐標(biāo)變換
剪貼板操作
QTableWidget
QByteArray 和 QVariant
創(chuàng)建一個(gè)對(duì)話框(下)
Qt 學(xué)習(xí)之路(32): 一個(gè)簡(jiǎn)易畫板的實(shí)現(xiàn)(Graphics View)
文本文件讀寫
自定義事件
編寫跨平臺(tái)的程序
MainWindow
初探信號(hào)槽
Qt 學(xué)習(xí)之路(17): Qt 標(biāo)準(zhǔn)對(duì)話框之 QMessageBox
繪圖設(shè)備
菜單和工具條(續(xù))
二進(jìn)制文件讀寫
QString
事件(event)
菜單和工具條
QPainter
Qt 容器類之順序存儲(chǔ)容器
進(jìn)程間交互
API 文檔的使用
創(chuàng)建一個(gè)對(duì)話框(上)
一個(gè)簡(jiǎn)易畫板的實(shí)現(xiàn)(QWidget)

自定義 model 之二

前面的例子已經(jīng)比較清楚的給出了自定義 model 的方法,就是要覆蓋我們所需要的那幾個(gè)函數(shù)就可以了。但是,前面的例子僅僅是簡(jiǎn)單的展示數(shù)據(jù),也就是說數(shù)據(jù)時(shí)只讀的。那么,如何能做到讀寫數(shù)據(jù)呢?那就要來看進(jìn)來的例子了。這個(gè)例子也是來自 C++GUI Programming with Qt 4, 2nd Edition這本書的。

還是先來看代碼吧:

citymodel.h


class CityModel : public QAbstractTableModel 
{ 
        Q_OBJECT 

public: 
        CityModel(QObject *parent = 0); 

        void setCities(const QStringList &cityNames); 
        int rowCount(const QModelIndex &parent) const; 
        int columnCount(const QModelIndex &parent) const; 
        QVariant data(const QModelIndex &index, int role) const; 
        bool setData(const QModelIndex &index, const QVariant &value, int role); 
        QVariant headerData(int section, Qt::Orientation orientation, int role) const; 
        Qt::ItemFlags flags(const QModelIndex &index) const; 

private: 
        int offsetOf(int row, int column) const; 

        QStringList cities; 
        QVector<int> distances; 
};

citymodel.cpp
CityModel::CityModel(QObject *parent) 
        : QAbstractTableModel(parent) 
{ 
} 

int CityModel::rowCount(const QModelIndex & parent) const 
{ 
        return cities.count(); 
} 

int CityModel::columnCount(const QModelIndex & parent) const 
{ 
        return cities.count(); 
} 

QVariant CityModel::data(const QModelIndex &index, int role) const 
{ 
        if (!index.isValid()) { 
                return QVariant(); 
        } 

        if (role == Qt::TextAlignmentRole) { 
                return int(Qt::AlignRight | Qt::AlignVCenter); 
        } else if (role == Qt::DisplayRole) { 
                if (index.row() == index.column()) { 
                        return 0; 
                } 
                int offset = offsetOf(index.row(), index.column()); 
                return distances[offset]; 
        } 
        return QVariant(); 
} 

QVariant CityModel::headerData(int section, Qt::Orientation orientation, int role) const 
{ 
        if (role == Qt::DisplayRole) { 
                return cities[section]; 
        } 
        return QVariant(); 
} 

bool CityModel::setData(const QModelIndex &index, const QVariant &value, int role) 
{ 
        if (index.isValid() && index.row() != index.column() && role == Qt::EditRole) { 
                int offset = offsetOf(index.row(), index.column()); 
                distances[offset] = value.toInt(); 

                QModelIndex transposedIndex = createIndex(index.column(), index.row()); 
                emit dataChanged(index, index); 
                emit dataChanged(transposedIndex, transposedIndex); 
                return true; 
        } 
        return false; 
} 

Qt::ItemFlags CityModel::flags(const QModelIndex &index) const 
{ 
        Qt::ItemFlags flags = QAbstractItemModel::flags(index); 
        if (index.row() != index.column()) { 
                flags |= Qt::ItemIsEditable; 
        } 
        return flags; 
} 

void CityModel::setCities(const QStringList &cityNames) 
{ 
        cities = cityNames; 
        distances.resize(cities.count() * (cities.count() - 1) / 2); 
        distances.fill(0); 
        reset(); 
} 

int CityModel::offsetOf(int row, int column) const 
{ 
        if (row < column) { 
                qSwap(row, column); 
        } 
        return (row * (row - 1) / 2) + column; 
} 

代碼很長(zhǎng),但實(shí)際上和前面我們的那個(gè)例子非常相似。這個(gè) model 也是用于 table 的,因此還是繼承了QAbstractTableModel。CityModel 內(nèi)部有兩個(gè)數(shù)據(jù)源:一個(gè) QStringList 類型的對(duì)象,一個(gè)QVector<int>類型的對(duì)象。前者用于保存城市的名字,需要用戶顯示的給出;后者是 model 內(nèi)部維護(hù)的一個(gè)存放 int 的向量。這個(gè) CityModel 就是要在 table 中顯示兩個(gè)城市之間的距離。同前面的例子一樣,如果我們要把所有的數(shù)據(jù)都保存下來,顯然會(huì)造成數(shù)據(jù)的冗余:城市 A 到城市 B 的距離同城市 B 到城市 A 的距離是一樣的!因此我們還是自定義一個(gè) model。同樣這個(gè) CityModel 有個(gè)簡(jiǎn)單的空構(gòu)造函數(shù),rowCount()和 columnCount()函數(shù)也是返回 list 的長(zhǎng)度。data()函數(shù)根據(jù) role 的不同返回不同的值。由于在 table 中坐標(biāo)是由 row 和 column 給出的,因此需要有一個(gè)二維坐標(biāo)到一維坐標(biāo)的轉(zhuǎn)換,這就是 offsetOf()函數(shù)的作用。我們把主要精力放在 setData()函數(shù)上面。


bool CityModel::setData(const QModelIndex &index, const QVariant &value, int role) 
{ 
        if (index.isValid() && index.row() != index.column() && role == Qt::EditRole) { 
                int offset = offsetOf(index.row(), index.column()); 
                distances[offset] = value.toInt(); 

                QModelIndex transposedIndex = createIndex(index.column(), index.row()); 
                emit dataChanged(index, index); 
                emit dataChanged(transposedIndex, transposedIndex); 
                return true; 
        } 
        return false; 
}

這個(gè)函數(shù)在用戶編輯數(shù)據(jù)時(shí)會(huì)自動(dòng)調(diào)用。也就是說,這時(shí)我們的數(shù)據(jù)已經(jīng)不是只讀的了。函數(shù)開始是一個(gè)長(zhǎng)長(zhǎng)的判斷:index 要是合法的;index 的 row 和 column 不相等,也就是說兩個(gè)城市是不同的;數(shù)據(jù)想的 role是 Qt::EditRole。如果滿足了這三個(gè)條件,才會(huì)執(zhí)行下面的操作。首先,由 row 和 column 坐標(biāo)定位到表中的數(shù)據(jù)項(xiàng)在 vector 中的位置。然后用戶新修改的數(shù)據(jù)被作為參數(shù) value 傳入,所以我們要把這個(gè)參數(shù)賦值給 distances。createIndex()函數(shù)根據(jù) column 和 row 值生成一個(gè) QModelIndex 對(duì)象。請(qǐng)注意這里的順序:row 和 column 是顛倒的!這就把坐標(biāo)為(row, column)的點(diǎn)關(guān)于主對(duì)角線對(duì)稱的那個(gè)點(diǎn)(column, row)的 index 找到了。還記得我們的需求嗎?當(dāng)我們修改了一個(gè)數(shù)據(jù)時(shí),對(duì)應(yīng)的數(shù)據(jù)也要被修改,這就是這個(gè)功能的實(shí)現(xiàn)。我們需要 emit dataChanged()信號(hào),這個(gè)信號(hào)接收兩個(gè)參數(shù):一個(gè)是被修改的數(shù)據(jù)的左上角的坐標(biāo),一個(gè)是被修改的數(shù)據(jù)的右下角的坐標(biāo)。為什么會(huì)有兩個(gè)坐標(biāo)呢?因此我們修改的數(shù)據(jù)不一定只是一個(gè)。像這里,我們只修改了一個(gè)數(shù)據(jù),因此這兩個(gè)值是相同的。數(shù)據(jù)更新了,我們用這個(gè)信號(hào)通知 view 刷新,這樣就可以顯示新的數(shù)據(jù)了。最后,如果函數(shù)數(shù)據(jù)修改成功就返回 true,否則返回 false。

最后,我們?cè)?main()函數(shù)中顯示出來這個(gè) model:


int main(int argc, char *argv[]) 
{ 
        QApplication a(argc, argv); 
        QStringList cities; 
        cities << "Arvika" << "Boden" << "Eskilstuna" << "Falun"; 

        CityModel cityModel; 
        cityModel.setCities(cities); 

        QTableView tableView; 
        tableView.setModel(&cityModel); 
        tableView.setAlternatingRowColors(true); 
        tableView.setWindowTitle(QObject::tr("Cities")); 
        tableView.show(); 
        return a.exec(); 
}

這樣,我們就把這個(gè) model 做完了。最后來看看效果吧!

http://wiki.jikexueyuan.com/project/learn-road-qt/images/78.png" alt="" />

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