Итак жил был фреймворк Qt и последние 10 лет ничего почти в нем не менялось. И захотел один чел написать свой QTableView с нужным ему функционалом, а именно захотелось ему выводить ячейки в несколько рядов в одной строке. Ещё ему хотелось растягивать одну из ячеек по ширине двух других и т.д. (ну как в 1С например). Искал, искал чел готовый пример в интернете и не находил. И вот однажды подумал он посмотреть как сделан внутри сам QTableView и стало плохо ему от количества строк кода, не одна тысяча там. И взял с собой терпения чел и пошел по коду, долго он шел, и примерно на 5 день понял он, что здесь уже проходил. И обернулся и посмотрел чел на свой путь и открылось ему, что ходит он по кругу. И предстал ему весь его путь и вспомнил он все дороги и открылось ему царство знаний и понял он чего он хочет. Сразу небольшое ознакомительное видео по новым возможностям: QpTableView. Теперь к делу: надо создать шаблон расположения секций. Это по сути как шахматная доска, только теперь у строки может быть 2,3 и т.д. ряда. И теперь одну ячейку можно располагать на 2,3 и т.д. клетках шахматной доски как по горизонтале так и по вертикале. Приходится теперь как-то обозвать что есть что. У строки есть теперь горизонтальные и вертикальные ряды. Ряды вертикальные не будем путать с колонками. Понятие колонки оставим со смыслом как в модели данных, то есть колонка это номер поля (в select запросе). Теперь номер поля может быть в шаблоне указан в нескольких ячейках с одним только ограничением - в строго в прямоугольной области. То есть не где попало, а компактно в пределах визуального поямоугольника и без пропусков. А далее оказалось для нужной отрисовки мы переопределяем метод paintEvent класса QTableView и paintEvent  класса QHeaderView и получается, что совсем не сложно нарисовать так: Итак смысл прост в отрисовке QTableView. А именно: через drawCell рисуем каждую ячейку отдельно, передавая координаты ее прямоугольника, данные  и стиль отрисовки. Потом рисуем линии сетки между ячейками. Чтобы знать координаты, ширину и высоту каждой ячейки используются четыре новых контейнера. Они логично хранятся в горизонтальном хэдере. QTableView работает вместе с классами заголовками QHeaderView. Хедеров две штуки: горизонтальный и вертикальный.  Хэдеры имеют важное значение, именно по их геометрии (расположение секций) мы определяем расположение (геометнию) ячеек самой таблицы (плюс смещение к конкретной строке по Y). Также в хэдерах мы изменяем ширину колонок или высоту строк. По сути это удобный каркас (шаблон) геометрии ячеек. Нам придется сделать свои хэдеры. И приходится теперь отдельно делать горизонтальный и вертикальный хэдер, потому-что вся эта универсальность Qt нам не подходит. Горизонтальный хэдер (QpHorHeaderView) это будет каркас расположения ячеек. Также как и раньше QTableView для получения информации (куда рисовать ячейку) будет обращаться к горизонтальному  QHeaderView для получения QRect ячейки плюс будет добавлять смещение по y для отрисовки в конкретной строке. Для большей совместимости мы сохраним вертикальный хедер как таковой, но по сути он будет брать все данные о геометрии ячеек из горизонтального хэдера. Надо немного сказать, что создание своего QpTableView идёт по принципу попытки сохранения совместимости с оригинальным функционалом QTableView,  то есть методы класса остаются практически те же,. Но логично удалить часть функционала, связанная с объединением ячеек (span), а также можно удалить функционал реверса секций, то есть отображения в обратном порядке, так как для нас это на самом деле не актуально. Ещё не актуально скрывать секции и этот функционал тоже удалим. Зачем скрывать секцию, если можно просто инициализировать новый шаблон секций. Надо понимать, что отрисовка хэдеров и самой таблицы это отдельные независимые операции. В каждом классе для этого переопределен виртуальный метод paintEvent. Примечание: очень своеобразная ширина и высота прямоугольника QRect в Qt. Оказывается если мы видим через qDebug() такое: QRect(0,0 101x101) и вроде бы ширина (и высота) равны 101. Но самом деле это означает реально ширину (или высоту) 100px. А 101 это количество пикселей, то есть количество от 0 до 100 , и это равно 101 штуке. По времени создание своей QTableView и двух QHeaderView заняло примерно 4 рабочих недели. Поскольку мы удалили span функционал, а он был сильно интегрирован, нам пришлось восстановить работу практически всего сломанного функционала, в частности интерактивного изменения ширины колонок и высоты строк (рядов) мышкой, также поломалось выделение (ячеек, колонок, строк).  Пришлось разобраться довольно подробно в коде Qt. Например рамка ячейки в таблице рисуется явно через drawLine, а вот рамка в хэдере не рисуется явно, это просветы фона между секциями. Отрисовка при выделении ячейки(ячеек) не приводит к отрисовки всей таблицы, а отрисовываются только те ячейки, изображение которых хоть немного визуально изменилось (изменение фона - это тоже визуальное изменение).  По поводу делегатов, то тут все просто: делегату передается прямоугольник ячейки и далее делегат сам все отрисовывает в ячейке как ему надо. Это про комбобоксы, всякие чекбоксы и т.д. Интересно где срабатывает отрисовка делегата - это ("как ни странно") событие выделения ячейки и метод setSelection. Еще наверное надо отметить, что классы QTableView и QHeaderView оба наследуются от QAbstractItemView (каждый естественно самостоятельно). Класс QAbstractItemView наследуется от QAbstractScrollArea. Тут надо отметить, что выше указанные классы не полностью абстрактные, в них реализована и часть функционала. И что ещё важнее часть функционала реализована в их приватных спутниках типа QAbstractItemViewPrivate. А это значит, что нам придется собирать свои классы в составе исходников Qt (ветка gui), ибо методы приватных классов наружу в библиотеки не торчат, в чем и смысл заложенный Qt-никами. По факту мы переписываем полностью классы  QTableView и QHeaderView полностью заново. Поэтому мы решили обозвать наши классы с префиксом Qp, чтобы было понятно и наглядно. То есть у нас будут классы типа QpTableView, QpHorHeaderView, QpVertHeaderView. Сами файлы будут называться qp_tableview.h/.cpp, то есть ещё добавим знак подчеркивания. Знак подчеркивания хорошо выделяет наши файлы в куче исходников Qt. Да теперь о сборке нашего функционала в составе исходников Qt. А по другому не получается, то есть сделать чисто открытое наследование от QAbstractItemView можно, оно скомпилируется, но при сборке линковщик не найдет методы QAbstratItemViewPrivate , потому-что они не помечены как экспортируемые в библиотеках Qt. В результате надо как минимум править заголовок Qt файла qabstractitemview_p.h и как следствие придется пересобрать опять же ветку исходников gui. То есть пересобрать исходники придется по любому как минимум один раз. Это очень неприятная проблема для начинающих Qt-ников. Если кто знает как можно сделать свой класс , унаследованный от QAbstractItemView, чтобы можно было свободно его распространять без необходимости лезть в исходники Qt - буду безмерно признателен... С другой стороны один раз сделав сборку из исходников понимаешь, что процесс добавления своего функционала внутрь, отладка, сборка совсем не трудные операции. Примечание: на самом деле разобрались с этим вопросом позднее. Оказалось что, чтобы  наши классы QpTableView и т.д. предоставить открыто для добавления к любому проекту (без пересборки исходников Qt) надо еще свой вариант класса QAbstractItemView/QAbstractItemViewPrivate тащить с собой. А вот QAbstractScrollArea уже не надо, потому что QAbstractItemViewPrivate не экспортируемый, а  QAbstractScrollAreaPrivate экспортируемый.   Вот есть видео на эту тему: После того как мы первый раз отрисовали свою таблицу с новым шаблоном расположения ячеек, начинается самое интересное, а именно:  Создание делегатов Прокрутка (скроллинг) Изменение ширины ряда при перетаскивании мышкой границы ряда вправо или влево (вверх, вниз). Выделение ячейки, выделение колонок, строк, выделение произвольного сектора и т.д. И все это убивает огромное количество времени, так как заставляет досконально разобраться в работе отрисовки. Но оно того стоит, так как впоследствие лишних вопросов почему что-то не так отрисовываются уже не возникает. Самые интересные этапы отрисовки таблицы и хэдеров возникают при интерактивном изменении ширины колонки или высоты ряда (в горизонтальном хэдере) при перетаскивании мышкой края колонки (или ряда). При перетаскивании края колонки (ряда) мы видим как изменяется таблица и выбираем приятный для себя визуальный вариант, но это значит, что отрисовка происходит постоянно при движении мышки. Тут используется таймер потому, что в событии moveMouseEvent нельзя сразу отрисовывать таблицу или хэдер. Правильнее взвести таймер и когда moveMouseEvent благополучно завершится (и возможно несколько раз) отрисовать таблицу по событию таймера, то есть спустя некоторое разумное время. Итак поезд тронулся и вышла первая бета версия нашего набора классов QpTableView/QpHorHeaderView/QpVertHeaderView. Завтра выложим на гитхабе и китайским товарищам на gitee и oschina. проект на github Если долго, нудно , как шел процесс, то здесь на kkmspb.ru (записки сумасшедшего)  девелопер cpp