«Ручной» множественный выбор в QTableView и частично скрытая сетка

Я знаю, что тема про множественный выбор поднималась хотя бы раз, но, честно говоря, уже не могу ее найти и не помню, чтобы у нее было достойное решение.

Предлагаю обсудить два вопроса:

1) Создание поведения, аналогичного выбору ячейки MS Excel. Таким образом, пользователь щелкает одну ячейку в QTableView и получает выделенную выделенную ячейку, а также несколько «зависимых» ячеек меняют внешний вид (выбираются или просто выделяются каким-либо образом). В Excel он широко используется для отображения зависимостей формулы ячейки.

Я знаю, что есть несколько подходов к ее решению. Самый простой — изменить выбор представления с зависимой ячейкой в ​​любом из соответствующих обработчиков сигналов (например, QAbastractModelView clicked()). Такой способ выполняет свою работу, но имеет неприятный побочный эффект: из-за того, что сигналы, доставляемые после перерисовки выбранной ячейки, происходят, поэтому зависимый выбор рисуется после первой ячейки, что приводит к мерцанию.

Второй подход - это путь делегата. Это также имеет некоторые проблемы, потому что вы получаете paintEvent только для выбранной ячейки, поэтому вы не так уж много можете сделать с «зависимыми» ячейками. На самом деле я смог решить это таким образом, перехватив щелчок, изменив выделение и используя полностью настраиваемый делегат, который рисует все, как только сформирован полный выбор, поэтому на самом деле он пропускает первую перерисовку, но опять же я не был полностью удовлетворен с результатами, хотя визуально это выглядело совершенно правильно ... в основном потому, что общее время отклика TableView значительно уменьшилось. Причина этого в том, что Qt рисует собственный выбор сразу после получения щелчка мыши перед отправкой каких-либо сигналов пользовательским классам, и в случае этого подхода paintEvent в делегате поступает после нескольких основных циклов. Таким образом, существует заметная задержка в случае использования «отрисовки выбора в делегате» по сравнению с «отрисовкой собственного выбора».

Я уже начинаю думать, что лучшим вариантом может быть полная перезапись большей части QTableView, чтобы добавить поддержку таких схем выбора, но, может быть, есть более прямой подход?

2) Второй вопрос (сложил их вместе, потому что есть что-то общее). Допустим, у вас есть сетка, представляющая финансовую информацию по месяцам, и в течение месяца есть несколько столбцов информации, поэтому блок из N столбцов повторяется M раз. Очевидный способ сделать такую ​​сетку более читабельной — использовать другой стиль для вертикальных линий в сетке для первого столбца данных в каждом месяце. Скажем, сделать их на 1-2 пикселя шире.

Поскольку вы не можете указать стиль сетки для каждой ячейки, я установил setGrid(false), а затем нарисовал свои собственные линии сетки в качестве содержимого ячейки в делегате.

Но затем я столкнулся с проблемами из пункта 1. Затем вы указываете Qt использовать делегата в определенной ячейке, прежде чем делегат получит paintEvent Qt очищает фон ячейки. А в случае скрытой сетки фоновый прямоугольник, который очищает Qt, на один пиксель больше, чем требуется. Вероятно, это можно считать ошибкой Qt, потому что они не учитывают видимость сетки, но это приводит к удалению линий сетки в соседней ячейке, поэтому вам нужно рисовать в делегате не только собственную сетку ячейки, но и пересчитывать правильный прямоугольник ячейки, проверьте, если Qt допустил ошибку (проанализировав прямоугольник QPainter), решите, нужно ли восстановить то, что удаляется из соседней ячейки, и также перерисовать его. Это приводит к очень сложной логике делегирования, и я не могу считать это достойным решением.

Итак, вопрос 2 можно перефразировать так: знаем ли мы достойный способ стилизации сетки для каждой ячейки в QTableView?


person evilruff    schedule 19.04.2013    source источник


Ответы (2)


ОМГ, так много слов, не могли бы вы выбрать самую важную информацию?

person Aliceljm    schedule 19.04.2013
comment
Ну, если бы это был простой вопрос, я, вероятно, мог бы решить его сам =) это больше тема для обсуждения, я думаю, что есть профессиональные разработчики Qt, которые сталкивались с подобными проблемами. Поэтому я просто предлагаю обсудить возможные решения. - person evilruff; 19.04.2013

Я бы сделал что-то вроде этого:

Создайте делегата. Подкласс QAbstractTableModel и повторная реализация метода data. Ваша реализация должна возвращать текст ячейки для Qt::DisplayRole, но также может возвращать все, что вы хотите, если role является одной из ваших пользовательских ролей (например, шрифт, цвет или любой другой текст ячейки. Вы можете использовать любой номер роли выше Qt::UserRole). Ваша модель должна излучать сигнал dataChanged, чтобы уведомить QTableView, что содержимое изменено и должно быть перерисовано.

Затем в делегате вы просто запрашиваете эти данные, используя свой перегруженный QAbstractTableModel::data, и рисуете их так, как хотите.

person user2155932    schedule 19.04.2013
comment
Правильно ли я понял вашу идею, что, как только определенная ячейка щелкнула, вы «настроили», скажем, некоторые роли украшения для «зависимых» ячеек, чтобы они на самом деле не выбирались, а перерисовывались из-за испускаемого dataChanged? Интересный подход, но разве у вас нет видимой задержки между выделением и изменением внешнего вида других ячеек? - person evilruff; 19.04.2013
comment
Я так не думаю, потому что весь GUI в qt обрабатывается в одном потоке, и я не вижу причин, по которым перерисовка в этом потоке может быть отложена. Однако, если вы хотите быть действительно уверены, вы можете отключить и включить обновления с помощью QWidget::setUpdatesEnabled. - person user2155932; 19.04.2013
comment
Спасибо за предложение, я попробую таким образом и сообщу о результатах.. насчет перерисовки, вы правы, но Qt также выполняет оптимизацию вокруг последовательных вызовов update()/redraw(), чтобы минимизировать отрисовку.. поэтому не очевидно, что будут два обновления разделенные краски. Но в вашем решении я считаю, что это так. Любые хорошие идеи о стиле сетки для каждой ячейки? знак равно - person evilruff; 19.04.2013
comment
Что мне не нравится в этом подходе, так это то, что он немного нарушает концепцию MVC. Допустим, у вас есть одна модель с большим количеством чисел, и вам нужно иметь два представления с разными правилами зависимости. Например, один с «выделенными одинаковыми значениями» при выборе, а другой с «выделенным меньше, чем выбрано». Вероятно, это можно решить более элегантным способом с помощью прокси-модели. - person evilruff; 19.04.2013
comment
Ну, если вы посмотрите на QTableView::paintEvent, вы увидите, что он использует один стиль сетки для всех ячеек, поэтому в этом случае я не могу думать ни о чем, кроме создания подклассов/повторной реализации QTableView - person user2155932; 19.04.2013
comment
Это, очевидно, путь к новой разработке, но многие существующие формы загружаются на лету с помощью uitools, поэтому повторная реализация QTableView также означает реализацию полного плагина с настройкой форм. Я надеялся найти более легкое решение, которое может работать "извне" на существующем QTableView, но может быть переопределение - это более быстрый способ - person evilruff; 19.04.2013
comment
Я не думаю, что это ломает MVC. В вашем примере я использовал параметризованный делегат, который сам решает, рисовать ли выделенную ячейку или нет. Причина этого заключается в том, что выделение «такое же, как выбрано» и «меньше, чем выбрано» не является неотъемлемым свойством модели, по сравнению с чем-то вроде «значение выбранного зависит от» - person user2155932; 19.04.2013
comment
это правильно, но это означает, что dataChanged должен быть выпущен для всей модели. Я думаю, что если используется прокси, прокси-модель может принять решение о схеме выделения (так что у нас может быть что-то вроде SameValueProxy, LessThenProxy и т. д.) и настроить роли оформления, в то время как родитель сохранит данные. Таким образом, класс делегата возьмет роли декорации от прокси, а также это означает, что, как только модель прокси получает измененный выбор основной ячейки, она может решить, какие другие ячейки необходимо выделить, и подавать сигналы только измененным ячейкам, а не всей сетке. - person evilruff; 19.04.2013