Как выровнять примитивный флажок с центром заголовка столбца QHeaderView? - PullRequest
0 голосов
/ 03 октября 2018

У меня есть пользовательская 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, чтобы изменить происхождение нарисованного примитива, но этоне реагирует на изменения ширины столбца.Хотя фиксированная ширина столбца не является худшим решением.

Как правильно расположить флажок в заголовке столбца?

Вспомогательный вопрос: флажок в заголовке может бытьпереключается нажатием в любом месте в ячейке, а не только на самом поле (в отличие от тех, которые отображаются в таблице через делегатов).Есть ли способ это исправить?

Ответы [ 2 ]

0 голосов
/ 04 октября 2018

Решение @ scopchanov не работает для меня, поскольку флажок охватывает весь элемент заголовка

enter image description here enter image description here

Возможное решение - нарисовать 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();
}

enter image description here

0 голосов
/ 03 октября 2018

Решение

QHeaderView::paintSection принимает QRect &rect в качестве аргумента.Установите QStyleOption::rect равным rect, т.е. замените

option.rect = QRect(3,10,16,16);

на

option.rect = rect;

Примечание: Это решениев ответ на изменения ширины столбца.

Пример

Использование вашей реализации paintSection Я создал минимальный пример, чтобы продемонстрировать, как может быть реализовано предлагаемое решение.Код доступен на GitHub .

Результат

Приведенный пример дает следующий результат для Windows 7:

Windows 7 - Window with a checkbox in the header of a table with three rows

Результат в Windows 10:

Windows 10 - Window with a checkbox in the header of a table with three rows

Примечание: Это решение не работает в Linux, так как он дает следующий результат (Ubuntu 17):

Ubuntu 17 - Window with a checkbox in the header of a table with three rows

...