240601 在Item View里画一个checkbox并能改变勾选状态 - subclassing QStyledItemDelegate
最近在用Qt做一个hobby project,类似Microsoft Todo的任务清单。
最初就是用QListView,QStandardItemModel,QStandardItem,和默认使用的QStyledItemDelegate。如果每个只是显示任务名字和一个checkbox的话,这些确实足够了。
但是还想在item view里显示截止日期和提醒时间,上面的就不够了。想自定义item view的话,就得自建一个QStyledItemDelegate的子类,重新实现paint方法了。
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
感觉官方也没有给这个方法详细的解释和例子,搜到的很多也只是画了单纯的图片和文字,没有像checkbox这样的控件。
这个方法里最让我搞不懂的就是option
。好像都是基于option.rect
来画出自定义的界面。后来通过debug打印出来rect的size和position,才搞懂一些。
paint
方法有还有个index
参数,而option
也对应了这个index
的item,每个option.rect
的位置是对应了index
的item在QListView里显示的位置。
然后就是不同类型的option
,比如paint
方法参数的option是QStyleOptionViewItem
类型,对应的是item view。而如果我要在item view上画一个checkbox,那这个checkbox需要另建一个类型为QStyleOptionButton
的实例,比如把这个实例命名为checkBoxOpt
。那么checkBoxOpt.rect
的位置应该根据option.rect
的位置来设定。
下面就是我在paint方法里用来画checkbox的代码,这里还包括了通过index获得该item的TaskCompleteRole
数据,表示这个task是否已经完成,并由此设定该item的checkbox是否被勾选。
1 | // Draw checkbox |
createCheckBoxRect
是用来确定checkbox的rect的位置,这个方法在之后改变checkbox状态的时候也用到。
1 | QRect TaskViewDelegate::createCheckBoxRect(const QStyleOptionViewItem& option, const QStyleOptionButton& checkBoxOpt) const |
现在可以在item view里画出来一个checkbox了,但是怎么让checkbox被点击之后能被勾选或者取消勾选呢。参考StackOverflow的一个问答,需要重新实现QStyledItemDelegate
的editorEvent
方法
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
通过检测鼠标点击事件并且点击区域限定在checkbox的rect位置内,来更新该item的TaskCompleteRole
的数据
1 | bool TaskViewDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) |
下面这两个个例子给了我很大启发。
自定义的item view里checkbox改变状态
https://stackoverflow.com/questions/36778577/qstyleditemdelegate-how-to-make-checkbox-button-to-change-its-state-on-click
在QListView里展示自定义wedget
https://stackoverflow.com/questions/53105343/is-it-possible-to-add-a-custom-widget-into-a-qlistview