玉兔远程控制 0.1.0-bate6
载入中...
搜索中...
未找到
CheckBoxHeader.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QStandardItemModel>
4#include <QPainter>
5#include <QMouseEvent>
6#include <QStyleOptionButton>
7#include <QStyle>
8#include <QApplication>
9#include <QLoggingCategory>
10#include "CheckBoxHeader.h"
11
12static Q_LOGGING_CATEGORY(log, "CCheckBoxHeader")
13CCheckBoxHeader::CCheckBoxHeader(Qt::Orientation orientation, QWidget *parent)
14 : QHeaderView(orientation, parent)
15{
16 // 可根据需要启用鼠标追踪等
17 setSectionsClickable(true);
18}
19
20void CCheckBoxHeader::SetCheckState(int index, Qt::CheckState state)
21{
22 QStandardItemModel* pModel = qobject_cast<QStandardItemModel*>(this->model());
23 if(pModel) {
24 QStandardItem* item = nullptr;
25 if(orientation() == Qt::Horizontal)
26 item = pModel->horizontalHeaderItem(index);
27 else
28 item = pModel->verticalHeaderItem(index);
29 if(item && item->isCheckable()) {
30 item->setCheckState(state);
31 viewport()->update();
32 return;
33 }
34 }
35
36 if(!m_CheckableSections.contains(index)) {
37 qCritical(log) << "Please call SetCheckable first to enable the checkbox";
38 return;
39 }
40 if (m_CheckableSections[index] == state) return;
41 m_CheckableSections[index] = state;
42 viewport()->update();
43}
44
45Qt::CheckState CCheckBoxHeader::GetCheckState(int index) const
46{
47 QStandardItemModel* pModel = qobject_cast<QStandardItemModel*>(this->model());
48 if(pModel) {
49 QStandardItem* item = nullptr;
50 if(orientation() == Qt::Horizontal)
51 item = pModel->horizontalHeaderItem(index);
52 else
53 item = pModel->verticalHeaderItem(index);
54 if(item && item->isCheckable()) {
55 return item->checkState();
56 }
57 }
58
59 auto it = m_CheckableSections.find(index);
60 if(m_CheckableSections.end() == it)
61 return Qt::Unchecked;
62 return *it;
63}
64
65void CCheckBoxHeader::SetCheckable(int index, bool checkable, Qt::CheckState state)
66{
67 QStandardItemModel* pModel = qobject_cast<QStandardItemModel*>(this->model());
68 if(pModel) {
69 QStandardItem* item = nullptr;
70 if(orientation() == Qt::Horizontal)
71 item = pModel->horizontalHeaderItem(index);
72 else
73 item = pModel->verticalHeaderItem(index);
74 if(item) {
75 item->setCheckable(checkable);
76 item->setCheckState(state);
77 return;
78 }
79 }
80
81 if (checkable)
82 m_CheckableSections.insert(index, state);
83 else
84 m_CheckableSections.remove(index);
85 viewport()->update();
86}
87
88bool CCheckBoxHeader::isCheckable(int index) const
89{
90 QStandardItemModel* pModel = qobject_cast<QStandardItemModel*>(this->model());
91 if(pModel) {
92 QStandardItem* item = nullptr;
93 if(orientation() == Qt::Horizontal)
94 item = pModel->horizontalHeaderItem(index);
95 else
96 item = pModel->verticalHeaderItem(index);
97 return item && item->isCheckable();
98 }
99
100 return m_CheckableSections.contains(index);
101}
102
103QRect CCheckBoxHeader::CheckboxRect(const QRect &sectionRect) const
104{
105 int size = style()->pixelMetric(QStyle::PM_IndicatorWidth, nullptr, this);
106 if (size <= 0) size = 16;
107 //qDebug(log) << "Size:" << size;
108 int x = 0;
109 int y = 0;
110 x = sectionRect.left() + 4;
111 y = sectionRect.center().y() - size / 2;
112 return QRect(x, y, size, size);
113}
114
115void CCheckBoxHeader::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
116{
117 if (!isCheckable(logicalIndex) || isSectionHidden(logicalIndex)) {
118 QHeaderView::paintSection(painter, rect, logicalIndex);
119 return;
120 }
121
122 // 1) 绘制默认背景
123 painter->save();
124 QStyleOptionHeader option;
125 option.initFrom(this);
126 option.rect = rect;
127 option.section = logicalIndex;
128 option.orientation = this->orientation();
129 style()->drawControl(QStyle::CE_Header, &option, painter, this);
130 painter->restore();
131
132 // 2) 如果该列可显示复选框,绘制复选框
133 QRect cbRect = CheckboxRect(rect);
134 DrawCheckBox(painter, cbRect, GetCheckState(logicalIndex), true);
135
136 // 3) 绘制文本(在复选框右侧留出间距)
137 QString text;
138 if (model()) {
139 QVariant v = model()->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole);
140 text = v.isValid() ? v.toString() : QString();
141 }
142 if (!text.isEmpty()) {
143 // 调整文本区域(避开复选框)
144 int textLeft = cbRect.right() + 4; // 复选框右边留4像素间距
145 QRect textRect(textLeft, rect.top(), rect.width() - (textLeft - rect.left()), rect.height());
146 // 绘制文本
147 QVariant vAlign = model() ? model()->headerData(
148 logicalIndex, orientation(),
149 Qt::TextAlignmentRole)
150 : Qt::AlignLeft;
151 Qt::Alignment alignment = Qt::AlignCenter;
152 if(vAlign.isValid())
153 alignment = (Qt::Alignment)vAlign.toInt();
154 this->DrawText(painter, textRect, text, alignment);
155 }
156
157 return;
158}
159
160void CCheckBoxHeader::DrawCheckBox(QPainter* painter, const QRect& rect,
161 Qt::CheckState state, bool enabled) const
162{
163 QStyleOptionButton option;
164 option.rect = rect;
165 option.state = QStyle::State_Enabled | QStyle::State_Active;
166
167 if (enabled) {
168 option.state |= QStyle::State_Enabled;
169 }
170
171 switch (state) {
172 case Qt::Checked:
173 option.state |= QStyle::State_On;
174 break;
175 case Qt::PartiallyChecked:
176 option.state |= QStyle::State_NoChange;
177 break;
178 case Qt::Unchecked:
179 option.state |= QStyle::State_Off;
180 break;
181 }
182
183 // 绘制复选框
184 style()->drawControl(QStyle::CE_CheckBox, &option, painter, this);
185}
186
187void CCheckBoxHeader::DrawText(QPainter* painter, const QRect& rect,
188 const QString& text, Qt::Alignment alignment) const
189{
190 if (text.isEmpty()) return;
191
192 painter->save();
193
194 // 文本省略处理
195 QFontMetrics fm = painter->fontMetrics();
196 QString elided = fm.elidedText(text, Qt::ElideRight, rect.width());
197
198 QPalette palette = this->palette();
199 painter->setPen(palette.color(QPalette::Text));
200
201 // 绘制文本
202 painter->drawText(rect, alignment, elided);
203
204 painter->restore();
205}
206
207void CCheckBoxHeader::mousePressEvent(QMouseEvent *event)
208{
209 int logical = logicalIndexAt(event->pos());
210 if (logical >= 0 && isCheckable(logical)) {
211 // 使用 sectionViewportPosition + sectionSize 构造节矩形,避免兼容性问题
212 int x = sectionViewportPosition(logical);
213 int w = sectionSize(logical);
214 QRect sectionRect;
215 sectionRect = QRect(x, 0, w, height());
216 if (CheckboxRect(sectionRect).contains(event->pos())) {
217 Qt::CheckState state = GetCheckState(logical);
218 switch (state) {
219 case Qt::Unchecked:
220 state = Qt::PartiallyChecked;
221 break;
222 case Qt::PartiallyChecked:
223 state = Qt::Checked;
224 break;
225 case Qt::Checked:
226 state = Qt::Unchecked;
227 break;
228 }
229 SetCheckState(logical, state);
230 emit sigCheckStateChanged(logical, state);
231 // 结束事件以避免触发排序(如不需要可调整)
232 //event->accept();
233 //return;
234 }
235 }
236
237 QHeaderView::mousePressEvent(event);
238}
包含复选框的表头
void SetCheckable(int index, bool checkable, Qt::CheckState state=Qt::Unchecked)
设置是否显示复选框
void SetCheckState(int index, Qt::CheckState state)
设置表头复选框状态