Qt模型/檢視原理(4):自定義檢視
阿新 • • 發佈:2018-11-11
Qt模型/檢視原理(4):自定義檢視
若對C++語法不熟悉,建議參閱《C++語法詳解》一書,電子工業出版社出版,該書語法示例短小精悍,對查閱C++知識點相當方便,並對語法原理作了詳細講解。
自定義檢視的基本原則如下
1)、檢視需要自行繪製,通常在paintEvent()函式內完成,所以除了必須實現的純虛擬函式外,paintEvent()也應重新實現。另外若需要對單元格進行重新繪製、更新滾動條等,還需要重新實現resizeEvent()函式。
2)、自定義檢視需要完成顯示的單元格的大小和位置的計算、單元格輪廓線的繪製、滾動的計算、對單元格的選擇作出處理、若有必要還需要繪製標頭。
3)、另外需要記住的是檢視就是一個QFrame,也就是說直接使用show()顯示檢視,那麼檢視只是一個什麼也沒有的視窗而已,視窗中的內容需要由程式設計師設計,也就是說你也可以完全不繼承QAbstractItemView類,而子類化QFrame類來實現檢視中內容的繪製,當然這樣會失去對QAbstractItemView類中由Qt已實現的內部函式的使用。
示例8.11為最小的自定義檢視實現,也就是說以下程式碼實現的檢視功能並不完善。完整的實現需要比較複雜的計算量,以下程式碼主要是要讓讀者明白,檢視究竟用來做什麼,做了什麼。從而加深對模型/檢視結構的理解。作為最小實現,本示例只處理單元格輪廓線的繪製、單元格中資料項的繪製,以及簡單的選擇操作
示例8.11的基本規則:使用paintEvent()函式完成由visualRect()函式返回的矩形的輪廓線及其資料項的繪製,其中資料項呼叫委託繪製。
示例8.11:簡單的自定義檢視 //m.h檔案的內容 #ifndef M_H #define M_H #include<QtWidgets> class V:public QAbstractItemView{ public: //1、以下函式用於計算專案所佔據的矩形(即位置和大小) QRect visualRect(const QModelIndex &index) const{ //該函式在初次執行時便會由Qt呼叫,呼叫次數依模型而定,本例3*3的表格模型, //該函式會被呼叫18次。引數index包含模型的索引,index會在呼叫時迴圈傳遞。 //比如對於本例,第一次呼叫時的索引為(0,0),第二次為(0,1),第3次為(0,2)... //計算專案的矩形:專案大小始終為(110,33),位置隨索引而不同。 return QRect(index.column()*110,index.row()*33+20,110,33); } //2、以下函式返回滑鼠游標所在位置的專案的索引 QModelIndex indexAt(const QPoint &point) const{ //該函式在點選滑鼠時Qt會呼叫。 //引數point包含了滑鼠游標的座標位置(檢視座標) int r=(point.y()-20)/33; //計算游標位於哪一行。 int c=point.x()/110; //計算游標位於哪一列。 return model()->index(r,c); } //返回該專案的索引。 //3、以下兩個函式主要用於處理對專案的選擇,當選擇檢視中的專案時,Qt才會呼叫他們。 //當不需要選擇專案時,以下兩個函式可以不用實現。 void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags) { //引數rect包含了所選專案的矩形(位置和大小,使用檢視座標) //引數flags包含了選擇專案時的選擇標誌。 int r=(rect.y()-20)/33; //計算選中的是哪一行。 int c=rect.x()/110; //計算選中的是哪一列。 selectionModel()->select(model()->index(r,c),flags); } //選擇所選中的索引。 QRegion visualRegionForSelection(const QItemSelection &s) const { //此函式用於計算所有被選擇的專案佔據的區域(即位置和大小)。 //引數s包含了所選擇的專案的範圍。 return QRegion(); } //4、以下函式用於計算檢視的滾動,本例是最小實現,不需要滾動,所以不需要實現以下3個函式。 int horizontalOffset() const{ return 0; } int verticalOffset() const { return 0; } void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible){} //5、本示例不需要隱藏專案,所以以下函式直接返回0即可。 bool isIndexHidden(const QModelIndex &index) const{ return 0; } //6、以下函式用於處理鍵盤按鍵(比如按下左鍵應返回左側的專案索引等),本示例不處理鍵盤按鍵, //所以不需要實現。 QModelIndex moveCursor(CursorAction cursorAction ,Qt::KeyboardModifiers modifiers){ return QModelIndex(); } //7、以下函式是核心,用於繪製檢視的外觀,也就是說若沒有以下函式,則檢視什麼也不會顯示。 void paintEvent(QPaintEvent *e){ QPainter pt(viewport()); //在視口上繪製圖形 //使用QAbstractItemView::viewOptions()獲取需要繪製的圖形的資訊(此步驟比較重要) QStyleOptionViewItem po=viewOptions(); //迴圈遍歷模型的大小。 for(int r=0;r<model()->rowCount();r++) for(int c=0;c<model()->columnCount();c++){ QModelIndex i=model()->index(r,c); QRect rect=visualRect(i); //獲取索引i所指專案的矩形(位置和大小) po.rect=visualRect(i); //處理專案被選擇的情形 if(selectionModel()->isSelected(i)){ po.state |= QStyle::State_Selected;} //使用代理繪製資料項(即專案),這裡也可使用自定義的代理(若已新增) itemDelegate()->paint(&pt,po,i); //以下程式碼用於繪製檢視單元格的輪廓線。 pt.save(); pt.setPen(QPen(QColor(111,1,1))); //建立畫筆。 pt.drawLine(rect.bottomLeft(),rect.bottomRight()); pt.drawLine(rect.bottomRight(),rect.topRight()); pt.restore(); } //for結束 } //paintEvent結束 }; class B:public QWidget{ Q_OBJECT public: QStandardItemModel *d; V *pv; B(QWidget *p=0):QWidget(p){ d=new QStandardItemModel(3,3); V* pv=new V; //使用自定義的檢視 //向模型中新增資料 d->setData(d->index(0,0),"AAA"); d->setData(d->index(0,1),"BBB"); d->setData(d->index(1,0),"CCC"); d->setData(d->index(1,2),"DDD"); d->setData(d->index(1,1),"EEE"); d->setData(d->index(2,0),"FFF"); d->setData(d->index(1,1),QIcon("F:/1i.png"),Qt::DecorationRole); //向檢視中新增標籤,以用於檢視的標頭,以下程式碼主要演示檢視還可以像使用一個QFrame那樣使用。 QLabel *pp=new QLabel("111",pv); pp->setAutoFillBackground(1); //使標籤不透明。 pp->setAlignment(Qt::AlignCenter); pp->resize(111,20); QLabel *pp1=new QLabel("222",pv); pp1->setAutoFillBackground(1); pp1->setAlignment(Qt::AlignCenter); pp1->resize(111,20); pp1->move(111,0); QLabel *pp2=new QLabel("333",pv); pp2->setAutoFillBackground(1); pp2->setAlignment(Qt::AlignCenter); pp2->resize(111,20); pp2->move(222,0); //pv->setItemDelegate(pt); //也可以新增自定義代理,以使用自定義代理繪製資料項。 pv->setModel(d); pv->resize(333,222); pv->show(); } }; #endif // M_H //m.cpp檔案內容 #include "m.h" int main(int argc, char *argv[]){ QApplication app(argc,argv); B w; return app.exec(); }
執行結果及說明見圖8-37
本文作者:黃邦勇帥(原名:黃勇)