Russian Qt Forum

Qt => Model-View (MV) => Тема начата: schmidt от Март 22, 2013, 18:32



Название: Перетаскивание элементов QTableView: подсветка/обрамление ячеек под курсором
Отправлено: schmidt от Март 22, 2013, 18:32
Добрый вечер,

Стандартно при перетаскивании элементов QTableView отображается значение этого элемента рядом с курсором, но ячейки, над которыми протаскивают элемент, никак не подают вида, что сброс осуществляется именно в данную конкретную ячейку. Хотелось бы сделать так, чтобы ячейки изменяли цвет фона, или обрамлялись жирной границей, говоря пользователю "Эй, ты можешь сбросить это в меня!" :)

Поиск по интернету дал информацию о том, как реализовать подсветку элемента QTableView в момент наведения на него курсора - с помощью делегата, и выглядит это так:

Код:
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                             const QModelIndex &index) const {
    if(index.isValid()) {
        if(option & QStyle::State_MouseOver) {
             // Курсор мыши наведен на элемент
        }
    }
}

Если я правильно понимаю, то решение моей проблемы состоит в том, чтобы отлавливать событие "начало перетаскивания" и подключать делегат с подсветкой?


Название: Re: Перетаскивание элементов QTableView: подсветка/обрамление ячеек под курсором
Отправлено: GreatSnake от Март 23, 2013, 11:02
Код
C++ (Qt)
void QAbstractItemView::setDropIndicatorShown( bool enable )


Название: Re: Перетаскивание элементов QTableView: подсветка/обрамление ячеек под курсором
Отправлено: schmidt от Март 23, 2013, 11:32
По какой-то неясной причине изменение showDropIndicator не дает никакого эффекта. Возможно я где-то в модели чего-то нагородил, перегружая методы, или с событиями QTableView. **Пошел впитывать Drag/Drop документацию полностью  :)


Название: Re: Перетаскивание элементов QTableView: подсветка/обрамление ячеек под курсором
Отправлено: GreatSnake от Март 23, 2013, 11:36
Наверняка при наследовании забываешь вызывать метод базового класса.


Название: Re: Перетаскивание элементов QTableView: подсветка/обрамление ячеек под курсором
Отправлено: schmidt от Март 23, 2013, 14:58
Создал тестовый проект, стал поочередно добавлять функционал до тех пор "пока не сломается" :) А сломалось всё после того как я переопределил  метод mimeData(). Видимо, и вправду что-то магическое добавляет вызов

Код:
QMimeData* data = QAbstractTableModel::mimeData(indexes);

к объекту QMimeData, но все вернулось на свои места после этого  :)


Название: Re: Перетаскивание элементов QTableView: подсветка/обрамление ячеек под курсором
Отправлено: schmidt от Март 23, 2013, 16:57
А если я хочу "прокачать" TableView, чтобы он обрамлял активную область сброса под курсором, если пользователь перетаскивает прямоугольный регион?

Код:
void MatrixDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                           const QModelIndex &index) const {
    /* Если в данный момент происходит перетаскивание выделенных ячеек,
     * Обрамлять активную область сброса границей */
    if(_isDraggedModeEnabled()) {
              // ...
    }
}

Есть ли способ из делегата добраться до выделения в QTableView? :)

Код:
QItemSelectionModel * QAbstractItemView::selectionModel() const


Название: Re: Перетаскивание элементов QTableView: подсветка/обрамление ячеек под курсором
Отправлено: schmidt от Март 24, 2013, 07:16
Решил проблему иным путем: реализовал собственный делегат с методом setRegionBorder(), в переопределеном методе dragMoveEvent() у TableView вызываю метод setRegionBorder() делегата. В методе paint() делегата проверяю, не лежит ли ячейка на границе заданной setRegionBorder() области, и рисую линию сверху/справа/снизу/слева от ячейки:

Код:
//---------------------------------------------------------------------------------------
void MatrixDelegate::setRegionBorder(int upper_row, int left_column, int bottom_row, int right_column) {
    _left_border_column_idx = left_column;
    _upper_border_row_idx = upper_row;
    _right_border_column_idx = right_column;
    _bottom_border_row_idx = bottom_row;
}

//---------------------------------------------------------------------------------------
void MatrixDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                           const QModelIndex &index) const {
    if(index.isValid()) {
        int cell_row = index.row();
        int cell_column = index.column();
        /* Проверить, не является ли ячейка границей региона, к которому применяется обрамление */
        if(_isCellHasLeftBorder(cell_row, cell_column)) {
            // Отрисовать границу слева
            _drawLeftCellBorder(painter, option);
        }
        if(_isCellHasUpperBorder(cell_row, cell_column)) {
            // Отрисовать границу сверху
            _drawUpperCellBorder(painter, option);
        }
        if(_isCellHasRightBorder(cell_row, cell_column)) {
            // Отрисовать границу справа
            _drawRightCellBorder(painter, option);
        }
        if(_isCellHasBottomBorder(cell_row, cell_column)) {
            // Отрисовать границу снизу
            _drawBottomCellBorder(painter, option);
        }

        QStyledItemDelegate::paint(painter, option, index);
    }
}

//---------------------------------------------------------------------------------------
bool MatrixDelegate::_isCellHasLeftBorder(int row, int column) const {
    bool is_cell_between_horizontal_borders =
            ( (_upper_border_row_idx <= row) && (row <= _bottom_border_row_idx) );

    bool is_cell_lays_onto_left_edge = ( column == _left_border_column_idx );

    return ( is_cell_between_horizontal_borders && is_cell_lays_onto_left_edge );
}

//---------------------------------------------------------------------------------------
/* и.т.д. по аналогии */

//---------------------------------------------------------------------------------------
void MatrixView::dragMoveEvent(QDragMoveEvent *evt) {
    QModelIndex index_under_cursor = indexAt(evt->pos());
    int current_row = index_under_cursor.row();
    int current_column = index_under_cursor.column();

    QItemSelectionRange selected_range = selectionModel()->selection().first();
    int upper_row = selected_range.top();
    int bottom_row = selected_range.bottom();
    int left_column = selected_range.left();
    int right_column = selected_range.right();
    int selection_width = right_column - left_column;
    int selection_height = bottom_row - upper_row;

    _matrix_delegate->clearRegionBorder();
    _matrix_delegate->setRegionBorder(current_row, current_column,
                                           current_row + selection_height,
                                           current_column + selection_width);

    QTableView::dragMoveEvent(evt);
}