博主QQ:1356438802
 
Qt 使用QItemSelectionModel類獲取視圖中項目的選擇情況。這個模型保持有項目的索引。而且獨立於不論什么視圖。這意味着,我們能夠讓不同的視圖共享同一個選擇模型,從來達到一種同步操作的目的。選擇由選擇區域組成。模型僅僅將選區的開始和結束的索引位置記錄下來,以保證對於非常大的選區也有非常好的性能。
非連續選區則由多個連續選擇組成。
選擇會直接應用於選擇模型所維護的那些被選中的索引上面。最新的選擇就是當前選擇。這意味着。即便界面上沒有顯示有不論什么項目被選擇。假設通過某些命令對選區進行操作,相同會有作用。
在視圖中,始終存在一個當前項和被選擇項(即便從界面上看不到有不論什么選擇)。與通常所想的不同,當前項和選擇項是相互獨立的兩個狀態。一個項目能夠即是當前項又是選擇項。下表是當前項和選擇項的差別:
| 當前項 | 選擇項 | 
|---|---|
| 僅僅能有一個當前項。 | 能夠有多個選擇項。 | 
| 使用鍵盤或者鼠標點擊能夠改變當前項。 | 選擇項使用兩種狀態:選擇和未選擇,這取決於項目之前的狀態和其他一些設置。比如,單選或多選。僅僅有在用戶進行交互的時候,這樣的狀態才會發生改變。 | 
| 當前項能夠使用 F2 或者鼠標雙擊進行編輯(前提是程序同意)。 | 當前項能夠結合另外一個錨點指定被選擇或者去除選擇的一塊選區(或二者的結合)。 | 
| 當前項一般會有一個焦點框進行標識。 | 選擇項使用選區顏色進行標識。 | 
在處理選擇的時候,我們能夠將QItemSelectionModel當成數據模型中全部數據項的選擇狀態的一個記錄。
一旦選擇模型創建好,這些數據項就能夠在不知道哪些項被選擇的情況下進行選擇、取消選擇或者改變選擇狀態的操作。全部被選擇項的索引都在可隨時更改,其他組件也能夠通過信號槽機制改動這些選擇的信息。
 
標准視圖類(QListView、QTreeView以及QTableView)已經提供了默認的選擇模型,足以滿足大多數應用程序的需求。
某一個視圖的選擇模型能夠通過selectionModel()函數獲取,然后使用setSelectionModel()提供給其他視圖共享,因此,一般沒有必要新建選擇模型。
假設須要創建一個選區。我們須要指定一個模型以及一對索引,使用這些數據創建一個QItemSelection對象。這兩個索引應該指向給定的模型中的數據,而且作為一個塊狀選區的左上角和右下角的索引。為了將選區應用到模型上。須要將選區提交到選擇模型。
這樣的操作有多種實現,對於現有選擇模型有着不同的影響。
以下我們來看一些代碼片段。首選構建一個總數 32 個數據項的表格模型,然后將其設置為一個表格視圖的數據:
|  
                
                  1 
                  
                
                  2 
                  
                
                  3 
                  
                |  
               
                 
                 QTableWidget tableWidget(8, 4); 
                  
                 
                 QItemSelectionModel *selectionModel = tableWidget.selectionModel(); 
                  
                |  
             
在代碼的最后,我們獲得QTableView的選擇模型,以備以后使用。
如今,我們沒有改動模型中的數據。而是選擇表格左上角的一些單元格。以下我們來看看代碼怎樣實現:
|  
                
                  1 
                  
                
                  2 
                  
                |  
               
                 
                 QModelIndex topLeft = tableWidget.model()->index(0, 0, QModelIndex()); 
                  
                 
                 QModelIndex bottomRight = tableWidget.model()->index(5, 2, QModelIndex()); 
                  
                |  
             
接下來,我們將獲得的兩個索引定義為選區。
為達這一目的,我們首先構造一個QItemSelection對象,然后將其賦值給我們獲取的選擇模型:
|  
                
                  1 
                  
                
                  2 
                  
                |  
               
                 
                 QItemSelection selection(topLeft, bottomRight); 
                  
                 
                 selectionModel->select(selection, QItemSelectionModel::Select); 
                  
                |  
             
正如前面我們說的。首先利用左上角和右下角的坐標構建一個QItemSelection對象,然后將這個對象設置為選擇模型的選擇區。
select()函數的第一個參數就是須要選擇的選區,第二個參數是選區的標志位。
Qt 提供了非常多不同的操作,能夠參考下QItemSelectionModel::SelectionFlags的文檔。在本例中,我們使用了QItemSelectionModel::Select,這意味着選區中所包括的全部單元格都會被選擇。
以下就是我們的執行結果:
如今我們知道怎樣設置選區。以下來看看怎樣獲取選區。
獲取選區須要使用selectedIndexes()函數。該函數返回一個無序列表。我們能夠通過遍歷這個列表獲得哪些被選擇:
|  
                
                  1 
                  
                
                  2 
                  
                
                  3 
                  
                
                  4 
                  
                
                  5 
                  
                
                  6 
                  
                
                  7 
                  
                |  
               
                 
                 QModelIndexList indexes = selectionModel->selectedIndexes(); 
                  
                 
                 QModelIndex index; 
                  
                 
                 foreach(index, indexes) { 
                  
                 
                     QString text = QString("(%1,%2)").arg(index.row()).arg(index.column()); 
                  
                 
                     model->setData(index, text); 
                  
                 
                 } 
                  
                |  
             
在選擇發生更改時。選擇模型會發出信號。我們能夠連接selectionChanged()信號,在選區改變時檢查哪個項目發生了變化。這個信號有兩個參數:第一個是新選擇的項目。第二個是剛剛被取消選擇的項目。
在以下的演示樣例中。我們通過selectionChanged()信號,將全部新選擇的項目填充字符串,將全部被取消選擇的部分清空:
|  
                
                  1 
                  
                
                  2 
                  
                
                  3 
                  
                
                  4 
                  
                
                  5 
                  
                
                  6 
                  
                
                  7 
                  
                
                  8 
                  
                
                  9 
                  
                
                  10 
                  
                
                  11 
                  
                
                  12 
                  
                
                  13 
                  
                
                  14 
                  
                
                  15 
                  
                
                  16 
                  
                
                  17 
                  
                |  
               
                 
                 void MainWindow::updateSelection(const QItemSelection &selected, 
                  
                 
                                                  const QItemSelection &deselected) 
                  
                 
                 { 
                  
                 
                     QModelIndex index; 
                  
                 
                     QModelIndexList items = selected.indexes(); 
                  
                 
                     foreach (index, items) { 
                  
                 
                         QString text = QString("(%1,%2)").arg(index.row()).arg(index.column()); 
                  
                 
                         model->setData(index, text); 
                  
                 
                     } 
                  
                 
                     items = deselected.indexes(); 
                  
                 
                     foreach (index, items) { 
                  
                 
                         model->setData(index, ""); 
                  
                 
                     } 
                  
                 
                 } 
                  
                |  
             
通過currentChanged()。我們能夠追蹤當前有焦點的項。同selectionChanged()信號類似,這個信號也有兩個參數:第一個是新的當前項,第二個是上一個當前項。
以下的代碼則是該信號的使用:
|  
                
                  1 
                  
                
                  2 
                  
                
                  3 
                  
                
                  4 
                  
                
                  5 
                  
                
                  6 
                  
                
                  7 
                  
                
                  8 
                  
                |  
               
                 
                 void MainWindow::changeCurrent(const QModelIndex ¤t, 
                  
                 
                                                const QModelIndex &previous) 
                  
                 
                 { 
                  
                 
                     statusBar()->showMessage( 
                  
                 
                         tr("Moved from (%1,%2) to (%3,%4)") 
                  
                 
                             .arg(previous.row()).arg(previous.column()) 
                  
                 
                             .arg(current.row()).arg(current.column())); 
                  
                 
                 } 
                  
                |  
             
這些信號能夠用來監控選區的改變。假設你還要直接更新選區,我們還有另外的方法。
相同是利用前面所說的QItemSelectionModel::SelectionFlag,我們能夠對選區進行組合操作。
還記得我們在前面的select()函數中使用過的第二個參數嗎?當我們替換這個參數,就能夠獲得不同的組合方式。
最經常使用的就是QItemSelectionModel::Select,它的作用是將全部指定的選區都選擇上。
QItemSelectionModel::Toggle則是一種取反的操作:假設指定的部分原來已經被選擇,則取消選擇,否則則選擇上。
QItemSelectionModel::Deselect則是取消指定的已選擇的部分。在以下的樣例中。我們使用QItemSelectionModel::Toggle對前面的演示樣例作進一步的操作:
|  
                
                  1 
                  
                
                  2 
                  
                
                  3 
                  
                
                  4 
                  
                
                  5 
                  
                
                  6 
                  
                
                  7 
                  
                |  
               
                 
                 QItemSelection toggleSelection; 
                  
                 
                 topLeft = tableWidget.model()->index(2, 1, QModelIndex()); 
                  
                 
                 bottomRight = tableWidget.model()->index(7, 3, QModelIndex()); 
                  
                 
                 toggleSelection.select(topLeft, bottomRight); 
                  
                 
                 selectionModel->select(toggleSelection, QItemSelectionModel::Toggle); 
                  
                |  
             
執行結果將例如以下所看到的:
默認情況下,選擇操作會僅僅會影響到指定的模型索引。可是。我們也能夠改變這一設置。比如,僅僅選擇整行或者整列:
|  
                
                  1 
                  
                
                  2 
                  
                
                  3 
                  
                
                  4 
                  
                
                  5 
                  
                
                  6 
                  
                
                  7 
                  
                
                  8 
                  
                
                  9 
                  
                
                  10 
                  
                
                  11 
                  
                
                  12 
                  
                
                  13 
                  
                
                  14 
                  
                
                  15 
                  
                
                  16 
                  
                
                  17 
                  
                
                  18 
                  
                
                  19 
                  
                |  
               
                 
                 QItemSelection columnSelection; 
                  
                 
                 topLeft = model->index(0, 1, QModelIndex()); 
                  
                 
                 bottomRight = model->index(0, 2, QModelIndex()); 
                  
                 
                 columnSelection.select(topLeft, bottomRight); 
                  
                 
                 selectionModel->select(columnSelection, 
                  
                 
                                        QItemSelectionModel::Select | QItemSelectionModel::Columns); 
                  
                 
                 QItemSelection rowSelection; 
                  
                 
                 topLeft = model->index(0, 0, QModelIndex()); 
                  
                 
                 bottomRight = model->index(1, 0, QModelIndex()); 
                  
                 
                 rowSelection.select(topLeft, bottomRight); 
                  
                 
                 selectionModel->select(rowSelection, 
                  
                 
                                        QItemSelectionModel::Select | QItemSelectionModel::Rows); 
                  
                |  
             
上面的代碼,我們依舊使用兩個索引設置了一個區域。可是,在選擇的使用我們使用了QItemSelectionModel::Rows和QItemSelectionModel::Columns這兩個參數。因此僅僅會選擇這兩個區域中指定的行或者列:
使用QItemSelectionModel::Current參數能夠將當前選區替換為新的選區。使用QItemSelectionModel::Clear則會將原來已有的選區所有取消。為了進行全選。我們能夠設置選區為左上角和右下角兩個索引:
|  
                
                  1 
                  
                
                  2 
                  
                
                  3 
                  
                
                  4 
                  
                
                  5 
                  
                
                  6 
                  
                |  
               
                 
                 QModelIndex topLeft = model->index(0, 0, parent); 
                  
                 
                 QModelIndex bottomRight = model->index(model->rowCount(parent)-1, 
                  
                 
                 model->columnCount(parent)-1, parent); 
                  
                 
                 QItemSelection selection(topLeft, bottomRight); 
                  
                 
                 selectionModel->select(selection, QItemSelectionModel::Select); 
                  
                |  
             



