У меня есть обычай QTableView
модель с кастомом QHeaderView
чтобы отобразить флажок, используемый для выполнения функции «выбрать все» для содержимого таблицы.
В моем заголовке перегружен paintSection()
функция, я успешно отображаю флажок, используемый для выбора всех с:
QStyleOptionButton option;
option.rect = QRect(3,10,16,16);
option.state = QStyle::State_Enabled | QStyle::State_Active;
if (isChecked_)
option.state |= QStyle::State_On;
else
option.state |= QStyle::State_Off;
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
К сожалению, флажок не отображается по центру, а вместо этого выравнивается по левому краю Это полностью противоречит правильно центрированному QStyledItemDelegate
флажки в столбце для каждой записи таблицы.
Я знаю, что могу изменить первые два аргумента QRect
изменить происхождение нарисованного примитива, но это не реагирует на изменения ширины столбца. Хотя фиксированная ширина столбца не является худшим решением.
Как правильно расположить флажок в заголовке столбца?
Вспомогательный вопрос: флажок в заголовке можно переключать, нажимая в любом месте в ячейке, а не только на самой коробке (в отличие от тех, которые представлены в таблице через делегатов). Есть ли способ это исправить?
Решение @scopchanov у меня не работает, так как флажок охватывает весь элемент заголовка
Возможное решение — нарисовать CheckBox со стилями, но помимо этого вы должны хранить память о том, проверен ли элемент или нет, для этого мы используем QMap<>
первым элементом является logicalIndex
поскольку он не изменяется даже при перемещении столбцов, а вторым элементом является состояние.
#include <QApplication>
#include <QHeaderView>
#include <QMouseEvent>
#include <QPainter>
#include <QStandardItemModel>
#include <QTableView>
class CheckedHeaderView : public QHeaderView
{
Q_OBJECT
public:
using QHeaderView::QHeaderView;
protected:
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override
{
painter->save();
QHeaderView::paintSection(painter, rect, logicalIndex);
painter->restore();
QStyleOptionButton opt;
QRect checkbox_rect = style()->subElementRect(QStyle::SE_CheckBoxIndicator, &opt);
checkbox_rect.moveCenter(rect.center());
opt.rect = checkbox_rect;
opt.state = QStyle::State_Enabled | QStyle::State_Active;
if(logicalIndex == columnDown)
opt.state |= QStyle::State_Sunken;
if (states[logicalIndex])
opt.state |= QStyle::State_On;
else
opt.state |= QStyle::State_Off;
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &opt, painter);
}
void mousePressEvent(QMouseEvent *event) override
{
QHeaderView::mousePressEvent(event);
int li = logicalIndexAt(event->pos());
if(li == -1) return;
columnDown = li;
updateSection(li);
}
void mouseReleaseEvent(QMouseEvent *event) override
{
QHeaderView::mouseReleaseEvent(event);
int li = logicalIndexAt(event->pos());
if(li == -1) return;
states[li] = !states[li];
Q_EMIT checked(li, states[li]);
columnDown = -1;
updateSection(li);
}
Q_SIGNALS:
void checked(int logicalIndex, bool state);
private:
QMap<int, bool> states;
int columnDown = -1;
};
class TableView : public QTableView
{
Q_OBJECT
public:
TableView(QWidget *parent = nullptr):
QTableView(parent)
{
CheckedHeaderView *header = new CheckedHeaderView(Qt::Horizontal, this);
setHorizontalHeader(header);
connect(header, &CheckedHeaderView::checked, this, &TableView::on_checked);
}
private Q_SLOTS:
void on_checked(int logicalIndex, bool state){
QItemSelectionModel::SelectionFlags command = state? QItemSelectionModel::Select : QItemSelectionModel::Deselect;
for(int r=0; r < model()->rowCount(); r++){
QModelIndex ix = model()->index(r, logicalIndex);
selectionModel()->select(ix, command);
}
}
};int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TableView w;
QStandardItemModel *model = new QStandardItemModel(8, 6, &w);
w.setModel(model);
w.show();
return a.exec();
}
QHeaderView::paintSection
занимает QRect &rect
в качестве аргумента. Задавать QStyleOption::rect
быть равным rect
то есть заменить
option.rect = QRect(3,10,16,16);
с
option.rect = rect;
Замечания: Это решение реагирует на изменения ширины столбца.
Используя вашу реализацию paintSection
Я создал минимальный пример, чтобы продемонстрировать, как предлагаемое решение может быть реализовано. Код доступен на GitHub.
Приведенный пример дает следующий результат в Windows 7:
Результат на Windows 10:
Замечания: Это решение не работает в Linux, так как дает следующий результат (Ubuntu 17):