前段时间项目上的要求,要实现一个列表(见下图1)。类似网页上的列表,可以通过选中标题栏的复选框,实现全选或者全不选的功能。但是看了很久,都没看到Qt哪个方法可以实现在标题栏添加控件。
图1
要实现这样的效果,也许我们首先想到的,就是直接生成一个CheckBox,用setGeometry()设置它的位置就可以了。当然这样是可以的,也是最简单的。但是有个问题:这样做,CheckBox就固定死了,而且没有跟标题栏连城一体,不会随着标题栏一起移动。结果如下图2
显然,这样的效果有点不爽。
后面想到了一种比较好的办法,就是自定义一个heander。通过setHeader()设置给列表。下面是我的部分实现代码
class MyCheckBox:public QCheckBox { Q_OBJECT public: MyCheckBox(QWidget *parent /*= NULL*/):QCheckBox(parent) { } ~MyCheckBox(){} protected: void mouseMoveEvent(QMouseEvent *e) {
//HeaderView::mouseMoveEvent(e); QRect boxRect = this->rect(); QPoint pos = e->pos(); if (boxRect.contains(pos)) { setCursor(Qt::ArrowCursor); } } private: }; class HanderView :public QHeaderView { Q_OBJECT public: HanderView( Qt::Orientation orientation,QWidget *parent /*= NULL*/):QHeaderView(orientation,parent) { m_pCheckBox = new MyCheckBox(this); hasPaint = false; } ~HanderView() { } private slots: protected: void resizeEvent(QResizeEvent *event) { int leftPos = this->sectionViewportPosition(0); m_pCheckBox->setGeometry(leftPos + 5,0,50,this->height()); int sectionMinSize = 50; this->setMinimumSectionSize(sectionMinSize + sectionSizeFromContents(0).width()); this->setDefaultSectionSize(sectionMinSize + sectionSizeFromContents(0).width()); } void paintEvent(QPaintEvent *e) { QHeaderView::paintEvent(e); int leftPos = this->sectionViewportPosition(0); m_pCheckBox->setGeometry(leftPos + 5,0,50,this->height()); } private: MyCheckBox *m_pCheckBox; bool hasPaint; };
class MyTreeWidget:public QTreeWidget { Q_OBJECT public: MyTreeWidget(QWidget *parent = NULL); ~MyTreeWidget(); protected: private: HanderView *m_pHeader; };
MyTreeWidget::MyTreeWidget(QWidget *parent /* = NULL */):QTreeWidget(parent) { m_pHeader = new HanderView(Qt::Horizontal,parent); this->setHeader(m_pHeader); QStringList list ; list<<"文件名"<<"文件大小"<<"文件类型"<<"创建日期"; this->setHeaderLabels(list); header()->setDefaultAlignment(Qt::AlignCenter); }
void mouseMoveEvent(QMouseEvent *e) {
//HeaderView::mouseMoveEvent(e); QRect boxRect = this->rect(); QPoint pos = e->pos(); if (boxRect.contains(pos)) { setCursor(Qt::ArrowCursor); } }2、
int leftPos = this->sectionViewportPosition(0); m_pCheckBox->setGeometry(leftPos + 5,0,50,this->height()); int sectionMinSize = 50; this->setMinimumSectionSize(sectionMinSize + sectionSizeFromContents(0).width()); this->setDefaultSectionSize(sectionMinSize + sectionSizeFromContents(0).width());设置列的最小宽度。
sectionSizeFromContents(0).width()这个可以根据标题栏的字符的长度调整列的宽度。
3、
int leftPos = this->sectionViewportPosition(0); m_pCheckBox->setGeometry(leftPos + 5,0,50,this->height());这里保证移动滚动条的时候,Box会跟着标题栏动。
效果如图3,图4
图3 图4
4、我们也可以把Box放在其他列,改一下index就可以了
int leftPos = this->sectionViewportPosition(1); m_pCheckBox->setGeometry(leftPos + 5,0,50,this->height()); int sectionMinSize = 50; this->setMinimumSectionSize(sectionMinSize + sectionSizeFromContents(1).width()); this->setDefaultSectionSize(sectionMinSize + sectionSizeFromContents(1).width());
int leftPos = this->sectionViewportPosition(1); m_pCheckBox->setGeometry(leftPos + 5,0,50,this->height());结果如图5,图6
图5 图6