Qt官方文档阅读笔记-对官方Star Delegate Example实例的解析
對應的博文為:
?
目錄
Star Delegate Example
StarDelegate Class Definition
StarDelegate Class Implementation
StarEditor Class Definition
StarEditor Class Implementation
StarRating Class Definition
StarRating Class Implementation
The main() Function
Possible Extensions and Suggestions
?
Star Delegate Example
在QListView、QTableView、QTreeView這些控件里面如果要有個性化的item就得使用委托,委托在編輯item的時候讓這些個性化的東西放置于最頂部。
這里告訴了一個道理當要自定義數據類型(比如int和QString混合,或者XX:xx這種數據)或者想定制渲染或者編輯存在的數據,就要子類化QAbstractItemDelegate或QItemDelegate(這兩個的優劣我就不說了,看名字大家都知道了)。
Star Delegate Example 這個栗子就是來教我們怎么去渲染(我覺得這個應該叫渲染)和編輯一個打分的數據類型(就是用星星表示的)
這個栗子包含了3個類(官方文檔就是清楚):
1.StarRating:自定義數據類型類,就是存那幾個星星;
2.StarDelegate:繼承于QItemDelegate,提供打分的功能,并且就是這個StarDelegate通過繼承QItemDelegate實現數據類型(那幾個星星)的處理;
3.StarEditor:繼承于QWidget,也是被StarDelegate使用的,這吊玩意提供了讓用戶使用鼠標去編輯“星星”;
?
StarDelegate Class Definition
class StarDelegate : public QStyledItemDelegate{Q_OBJECTpublic:StarDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {}void paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;QSize sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const Q_DECL_OVERRIDE;private slots:void commitAndCloseEditor();};關鍵:重寫了公有虛函數,實現了自定義渲染和編輯;
?
StarDelegate Class Implementation
首先是paint()函數,這個是父類的,目的是讓視圖重畫item:
每一個item都會調用這個函數,通過使用model中的QModelIndex對象來表示(估計是可以表示到哪一行調用了這個函數),如果存儲的數據類型就是那一坨星星,那就讓他進行繪制(源碼中可以看到一個if else,說的就是這個),否則使用QItemDelegate進行繪制。這樣就確保了StarDelegate更加的靈活。
當item顯示的是一坨星星時,選中item時會搞一個背景,然后通過使用StarRating::paint()來畫item。
?
那一坨星星可以存到QVariant里面,這歸功于Q_DECLARE_METATYPE()這個宏。
用戶開始編輯一個Item的時候就會調用createEditor()
如果item里面放了那一坨星星,重寫StartEditor這函數并且讓editingFinished()信號與commitAndCloseEidtor()型號連接起來,目的是當關閉編輯功能后能更新模型。
關于commitAndCloseEdit()的代碼!
void StarDelegate::commitAndCloseEditor(){StarEditor *editor = qobject_cast<StarEditor *>(sender());emit commitData(editor);emit closeEditor(editor);}當用戶做完編輯時,就emit commitData()和closeEditor()(這兩個信號都來源于QAbstractItemDelegate),這個是為了通知模型正在編輯數據并且通知視圖不要讓他編輯。
setEditorData()函數當要實現編輯功能的時候創建的,從模型中獲取數據并且初始化他!
void StarDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const{if (index.data().canConvert<StarRating>()) {StarRating starRating = qvariant_cast<StarRating>(index.data());StarEditor *starEditor = qobject_cast<StarEditor *>(editor);starEditor->setStarRating(starRating);} else {QStyledItemDelegate::setEditorData(editor, index);}}此處源碼里面編輯的時候調用了setStarRating()這函數!
當完成編輯的時候,就會調用setModelData()這個函數,作用是把editor中的數據給模型:
sizeHint()這個函數返回item的最合適的大小!
QSize StarDelegate::sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const{if (index.data().canConvert<StarRating>()) {StarRating starRating = qvariant_cast<StarRating>(index.data());return starRating.sizeHint();} else {return QStyledItemDelegate::sizeHint(option, index);}}StarEditor Class Definition
StarDelegate類在實例化的時候要使用StarEditor,關于StartEditor代碼如下:
class StarEditor : public QWidget{Q_OBJECTpublic:StarEditor(QWidget *parent = 0);QSize sizeHint() const Q_DECL_OVERRIDE;void setStarRating(const StarRating &starRating) {myStarRating = starRating;}StarRating starRating() { return myStarRating; }signals:void editingFinished();protected:void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;private:int starAtPosition(int x);StarRating myStarRating;};這個類通過移動鼠標讓用戶編輯那一坨星星數據,當鼠標單擊一個item后會emiteditingFinished()的信號。
這個類從繼承與QWidget,通過重寫這些函數來重新實現mouse和paint的事件。startAtPosition()這個函數是一個輔助函數返回鼠標指向的星星的指針(就是指向那個坨星星的哪一個位置)
?
StarEditor Class Implementation
start的構造函數:
StarEditor::StarEditor(QWidget *parent): QWidget(parent){setMouseTracking(true);setAutoFillBackground(true);}通過setMouseTracking這個函數去啟動鼠標追蹤,即使用戶沒有點擊鼠標,也能監聽到鼠標。一般都開打QWidget自動填充的特性用于獲取不透明的背景(如果不調用,視圖的Editor就會干擾這個編輯器)
下面是關于paintEvent()函數
void StarEditor::paintEvent(QPaintEvent *){QPainter painter(this);myStarRating.paint(&painter, rect(), this->palette(),StarRating::Editable);}通過這個函數去畫星星,這個函數就和StarDelegate差不多一毛一樣。
void StarEditor::mouseMoveEvent(QMouseEvent *event){int star = starAtPosition(event->x());if (star != myStarRating.starCount() && star != -1) {myStarRating.setStarCount(star);update();}}在鼠標事件里面調用setStartCount(),通過使用成員myStarRating得到當前光標的位置,并且調用QWidget::update()去讓他強制重繪。
void StarEditor::mouseReleaseEvent(QMouseEvent * /* event */){emit editingFinished();}當用戶釋放鼠標,就emit editingFinished()信號
int StarEditor::starAtPosition(int x){int star = (x / (myStarRating.sizeHint().width()/ myStarRating.maxStarCount())) + 1;if (star <= 0 || star > myStarRating.maxStarCount())return -1;return star;}startAtPosition這個函數使用了基礎的線性代數去尋找當前光標對應那一坨星星中哪個星星的位置。
?
StarRating Class Definition
class StarRating{public:enum EditMode { Editable, ReadOnly };explicit StarRating(int starCount = 1, int maxStarCount = 5);void paint(QPainter *painter, const QRect &rect,const QPalette &palette, EditMode mode) const;QSize sizeHint() const;int starCount() const { return myStarCount; }int maxStarCount() const { return myMaxStarCount; }void setStarCount(int starCount) { myStarCount = starCount; }void setMaxStarCount(int maxStarCount) { myMaxStarCount = maxStarCount; }private:QPolygonF starPolygon;QPolygonF diamondPolygon;int myStarCount;int myMaxStarCount;};Q_DECLARE_METATYPE(StarRating)StarRating類代表了星星的等級(就是那一坨星星有幾個組成),不僅如此他還提供了畫那一坨星星的能力,這個是通過QPaintDevice實現的,這個一坨星星可以在view上畫,或者在編輯器上畫。myStarCount這個成員存儲了當前有幾個星星,myMaxStarCount存儲了最多有多少個星星(存在QVariant這個神器里面)
?
通過Q_DECLARE_METATYPE()這個宏人QVariant知曉StarPating這個類,讓QVariant能存儲StarPating這個類。
?
StarRating Class Implementation
構造函數初始化了myStarCount和myMaxStarCount并且構造了一個多邊形(就是星星)和鉆石(非星星用這個代替)
StarRating::StarRating(int starCount, int maxStarCount){myStarCount = starCount;myMaxStarCount = maxStarCount;starPolygon << QPointF(1.0, 0.5);for (int i = 1; i < 5; ++i)starPolygon << QPointF(0.5 + 0.5 * std::cos(0.8 * i * 3.14),0.5 + 0.5 * std::sin(0.8 * i * 3.14));diamondPolygon << QPointF(0.4, 0.5) << QPointF(0.5, 0.4)<< QPointF(0.6, 0.5) << QPointF(0.5, 0.6)<< QPointF(0.4, 0.5);}paint()函數在StarRating這個對象的paint device上畫了星星。
void StarRating::paint(QPainter *painter, const QRect &rect,const QPalette &palette, EditMode mode) const{painter->save();painter->setRenderHint(QPainter::Antialiasing, true);painter->setPen(Qt::NoPen);if (mode == Editable) {painter->setBrush(palette.highlight());} else {painter->setBrush(palette.foreground());}int yOffset = (rect.height() - PaintingScaleFactor) / 2;painter->translate(rect.x(), rect.y() + yOffset);painter->scale(PaintingScaleFactor, PaintingScaleFactor);for (int i = 0; i < myMaxStarCount; ++i) {if (i < myStarCount) {painter->drawPolygon(starPolygon, Qt::WindingFill);} else if (mode == Editable) {painter->drawPolygon(diamondPolygon, Qt::WindingFill);}painter->translate(1.0, 0.0);}painter->restore();}首先設置了一個畫筆(pen)和畫刷(brush這兩個以后都用英文表示把,用中文太難過了)去畫圖。mode這個參數可以被設置成可編輯的或者可讀的,如果是可編輯的就要用Highligh color去代替Foreground color,從而才能更好的畫那一坨星星。
在編輯的時候,通過光標控制星星,沒有星星的地方用小方塊代替。
sizeHint()函數返回畫出來的這坨星星最適合的大小:
QSize StarRating::sizeHint() const{return PaintingScaleFactor * QSize(myMaxStarCount, 1);}最大也只能畫出myMaxStarCount這么多的星星。這個函數會被StarDelegate::sizeHint()與StartEditor::sizeHint()調用。
?
The main() Function
代碼如下:
int main(int argc, char *argv[]){QApplication app(argc, argv);QTableWidget tableWidget(4, 4);tableWidget.setItemDelegate(new StarDelegate);tableWidget.setEditTriggers(QAbstractItemView::DoubleClicked| QAbstractItemView::SelectedClicked);tableWidget.setSelectionBehavior(QAbstractItemView::SelectRows);QStringList headerLabels;headerLabels << "Title" << "Genre" << "Artist" << "Rating";tableWidget.setHorizontalHeaderLabels(headerLabels);populateTableWidget(&tableWidget);tableWidget.resizeColumnsToContents();tableWidget.resize(500, 300);tableWidget.show();return app.exec();}主函數創建了一個QTableWidget和設置了StartDelegate,DoubleClicked和SelectedClicked已經設置好了編輯觸發的功能,當星星等級的item被單擊選中后,就會打開編輯功能。
?
populateTableWidget()這個函數填充了QTableWidget的數據
?
注意:使用qVariantFromValue把StarRating轉化為QVariant
?
Possible Extensions and Suggestions
在Qt的視圖模型框架里面有很多自定義方法,這個例子適合大多數自定義委托和編輯(我估計在國內18k內的Qt開發足夠用了,18k外的可能要用別的),這個例子的星星委托和編輯沒有盡可能做到以下幾點:
1.使用編輯的方式,這種方式要調用QAbstractItemView::edit(),用這個代替編輯觸發。這可以支持其他編譯器的觸發,比如QAbstractItemView::EditTrigger。舉個例子,通過鼠標懸移動來改變數據這種效果比點擊更好。
2.通過重寫QAbstractItemDelegate::editorEvent(),這可以直接實現委托的編輯,而不是創建一個QWidget的子類來實現!
?
總結
以上是生活随笔為你收集整理的Qt官方文档阅读笔记-对官方Star Delegate Example实例的解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux学习笔记-标准库中的管道操作
- 下一篇: Qt工作笔记-时QLabel具有点击事件