#include "stickytableview.h" #include #include #include #include #include StickyTableView::StickyTableView(QWidget *parent) : QTableView(parent) , m_stickyColumns(1) , m_stickyColumnWidth(0) , m_isScrolling(false) { // Настройка горизонтального скроллбара setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); // Подключаем сигнал изменения скролла connect(horizontalScrollBar(), &QScrollBar::valueChanged, [this](int) { if (!m_isScrolling) { updateStickyColumnGeometry(); viewport()->update(); } }); } void StickyTableView::setStickyColumns(int count) { if (m_stickyColumns != count) { m_stickyColumns = count; updateStickyColumnGeometry(); viewport()->update(); } } void StickyTableView::paintEvent(QPaintEvent *event) { // Сначала рисуем обычную таблицу QTableView::paintEvent(event); // Затем рисуем липкие столбцы поверх if (m_stickyColumns > 0 && model()) { QPainter painter(viewport()); paintStickyColumns(&painter); } } void StickyTableView::scrollContentsBy(int dx, int dy) { m_isScrolling = true; QTableView::scrollContentsBy(dx, dy); m_isScrolling = false; // Обновляем геометрию липких столбцов после скролла updateStickyColumnGeometry(); } void StickyTableView::resizeEvent(QResizeEvent *event) { QTableView::resizeEvent(event); updateStickyColumnGeometry(); } void StickyTableView::updateStickyColumnGeometry() { if (!model() || m_stickyColumns <= 0) return; // Вычисляем ширину липких столбцов m_stickyColumnWidth = 0; for (int i = 0; i < m_stickyColumns && i < model()->columnCount(); ++i) { m_stickyColumnWidth += columnWidth(i); } // Устанавливаем отступ для основного контента setViewportMargins(m_stickyColumnWidth, 0, 0, 0); } void StickyTableView::paintStickyColumns(QPainter *painter) { if (!model() || m_stickyColumns <= 0) return; // Сохраняем состояние painter painter->save(); // Настраиваем clipping для липких столбцов QRect stickyRect = QRect(0, 0, m_stickyColumnWidth, viewport()->height()); painter->setClipRect(stickyRect); // Получаем видимые строки QRect visibleRect = viewport()->rect(); int topRow = rowAt(0); int bottomRow = rowAt(visibleRect.height()); if (topRow < 0) topRow = 0; if (bottomRow < 0) bottomRow = model()->rowCount() - 1; // Рисуем липкие столбцы for (int row = topRow; row <= bottomRow && row < model()->rowCount(); ++row) { int y = rowViewportPosition(row); int currentRowHeight = rowHeight(row); for (int col = 0; col < m_stickyColumns && col < model()->columnCount(); ++col) { int x = 0; for (int i = 0; i < col; ++i) { x += columnWidth(i); } QRect cellRect(x, y, columnWidth(col), currentRowHeight); // Рисуем фон ячейки QModelIndex index = model()->index(row, col); QStyleOptionViewItem option; option.initFrom(this); option.rect = cellRect; option.state = QStyle::State_Enabled; if (selectionModel()->isSelected(index)) { option.state |= QStyle::State_Selected; } if (index == currentIndex()) { option.state |= QStyle::State_HasFocus; } style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter); // Рисуем текст ячейки QVariant data = model()->data(index, Qt::DisplayRole); if (data.isValid()) { painter->drawText(cellRect.adjusted(4, 0, -4, 0), Qt::AlignVCenter | Qt::AlignLeft, data.toString()); } } } // Рисуем границы липких столбцов painter->setPen(QPen(Qt::black, 1)); painter->drawLine(m_stickyColumnWidth - 1, 0, m_stickyColumnWidth - 1, viewport()->height()); // Восстанавливаем состояние painter painter->restore(); }