Last active
February 15, 2022 08:42
-
-
Save photonlili/90705564f3182b82bd9f to your computer and use it in GitHub Desktop.
QHeaderView with custom checkbox
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "checkedheader.h" | |
| #include <QDebug> | |
| CheckedHeader::CheckedHeader(Qt::Orientation orientation, QWidget *parent) | |
| : QHeaderView(orientation, parent) | |
| { | |
| connect(this, &CheckedHeader::sectionResized, [&](int logicalIndex, int oldSize, int newSize){ | |
| for( int i = visualIndex(logicalIndex); i < visibleCount(); ++i ){ | |
| int index = this->logicalIndex(i); | |
| menuRect[index].moveTo(menuRect[index].x()+ newSize-oldSize, menuRect[index].y()); | |
| } | |
| }); | |
| setSectionsMovable(true); | |
| connect(this, &CheckedHeader::sectionMoved, this, &CheckedHeader::onSectionMoved); | |
| } | |
| void CheckedHeader::onSectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex) | |
| { int offset = 0; | |
| if( oldVisualIndex < newVisualIndex ){ | |
| // move right; | |
| for( int i = oldVisualIndex; i <= newVisualIndex; ++i ){ | |
| int index = this->logicalIndex(i); | |
| QRect oldRect = menuRect[index]; | |
| if( i != newVisualIndex ){ | |
| menuRect[index].moveTo(oldRect.x()- sectionSize(logicalIndex), oldRect.y()); | |
| offset += sectionSize(index); | |
| } | |
| else | |
| menuRect[index].moveTo(oldRect.x()+offset,oldRect.y()); | |
| } | |
| } | |
| else { | |
| // move left | |
| for( int i = oldVisualIndex; i >= newVisualIndex; --i ){ | |
| int index = this->logicalIndex(i); | |
| QRect oldRect = menuRect[index]; | |
| if( i != newVisualIndex ){ | |
| menuRect[index].moveTo(oldRect.x() + sectionSize(logicalIndex), oldRect.y()); | |
| offset += sectionSize(index); | |
| } | |
| else | |
| menuRect[index].moveTo(oldRect.x() - offset,oldRect.y()); | |
| } | |
| } | |
| } | |
| void CheckedHeader::setChecked(bool checked, int index) | |
| { | |
| if (isEnabled() && menuOn.value(index) != checked) | |
| { | |
| menuOn[index] = checked; | |
| updateSection(index); | |
| emit toggled(checked, index); | |
| } | |
| } | |
| void CheckedHeader::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const | |
| { | |
| painter->save(); | |
| QHeaderView::paintSection(painter, rect, logicalIndex); | |
| painter->restore(); | |
| QStyleOptionButton option; | |
| if (isEnabled()) | |
| option.state |= QStyle::State_Enabled; | |
| option.rect = menuRect[logicalIndex]; | |
| if (menuOn.value(logicalIndex)) | |
| option.state |= QStyle::State_On; | |
| else | |
| option.state |= QStyle::State_Off; | |
| if (menuOn.value(logicalIndex)) | |
| style()->drawControl(QStyle::CE_CheckBox, &option, painter); | |
| } | |
| void CheckedHeader::mousePressEvent(QMouseEvent *event) | |
| { | |
| int index = logicalIndexAt(event->pos()); | |
| if (isEnabled() && menuRect[index].contains(event->pos())) | |
| { | |
| menuOn[index] = !menuOn.value(index); | |
| updateSection(index); | |
| emit toggled(menuOn.value(index), index); | |
| QHeaderView::mousePressEvent(event); | |
| } | |
| else | |
| { | |
| QHeaderView::mousePressEvent(event); | |
| } | |
| } | |
| void CheckedHeader::mouseMoveEvent(QMouseEvent *event) | |
| { | |
| int index = logicalIndexAt(event->pos()); | |
| if( isEnabled() && menuRect[index].contains(event->pos())) | |
| { | |
| menuOn[index] = true; | |
| updateSection(index); | |
| } | |
| else { | |
| menuOn[index] = false; | |
| updateSection(index); | |
| } | |
| QHeaderView::mouseMoveEvent(event); | |
| } | |
| QSize CheckedHeader::sizeHint() const | |
| { | |
| // Get the base implementation size. | |
| QSize baseSize = QHeaderView::sizeHint(); | |
| // Override the height with a custom value. | |
| //baseSize.setHeight( 55 ); | |
| return baseSize; | |
| } | |
| void CheckedHeader::changeSectionVisibility(int logicalIndex, bool visible) | |
| { | |
| if( isSectionHidden(logicalIndex) && visible ){ | |
| showSection(logicalIndex); | |
| emit sectionVisibleChanged(logicalIndex, visible); | |
| } | |
| else if(!isSectionHidden(logicalIndex) && !visible ){ | |
| hideSection(logicalIndex); | |
| emit sectionVisibleChanged(logicalIndex, visible); | |
| } | |
| } | |
| QRect CheckedHeader::checkBoxRect(const QRect &sourceRect) const | |
| { | |
| QStyleOptionButton checkBoxStyleOption; | |
| QRect checkBoxRect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, | |
| &checkBoxStyleOption); | |
| QPoint checkBoxPoint(sourceRect.x() + sourceRect.width() - checkBoxRect.width() - 5, | |
| sourceRect.y() + sourceRect.height() / 2 - checkBoxRect.height() / 2); | |
| return QRect(checkBoxPoint, checkBoxRect.size()); | |
| } | |
| void CheckedHeader::initMenuRect() | |
| { | |
| int offset = 0; | |
| for( int i = 0; i < visibleCount(); ++i ){ | |
| QRect sourceRect = QRect(offset,0,sectionSize(logicalIndex(i)),sizeHint().height()); | |
| menuRect[i] = checkBoxRect(sourceRect); | |
| offset += sectionSize(i); | |
| } | |
| } | |
| int CheckedHeader::visibleCount() const | |
| { | |
| int counter = 0; | |
| for( int i = 0; i < count(); ++i ){ | |
| if( !isSectionHidden(i) ) | |
| counter++; | |
| } | |
| return counter; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef CHECKEDHEADER_H | |
| #define CHECKEDHEADER_H | |
| #include <QMap> | |
| #include <QHeaderView> | |
| #include <QPainter> | |
| #include <QMouseEvent> | |
| class CheckedHeader : public QHeaderView | |
| { | |
| Q_OBJECT | |
| public: | |
| explicit CheckedHeader(Qt::Orientation orientation, QWidget *parent = 0); | |
| void setChecked( bool checked, int index ); | |
| void initMenuRect(); | |
| virtual QSize sizeHint() const; | |
| int visibleCount() const; | |
| void onSectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex); | |
| void changeSectionVisibility(int logicalIndex, bool visible); | |
| signals: | |
| void toggled(bool checked, int index); | |
| void sectionVisibleChanged( int logicalIndex, bool visible ); | |
| protected: | |
| void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const; | |
| void mousePressEvent(QMouseEvent *event); | |
| void mouseMoveEvent(QMouseEvent *event); | |
| private: | |
| QRect checkBoxRect(const QRect &sourceRect) const; | |
| QMap<int, bool> menuOn; | |
| QMap<int, QRect> menuRect; | |
| }; | |
| #endif // CHECKEDHEADER_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment