#include "stickytableview_fixed.h" #include #include #include #include #include StickyTableViewFixed::StickyTableViewFixed(QWidget *parent) : QTableView(parent) , m_stickyColumns(1) , m_stickyColumnWidth(0) { // Настройка горизонтального скроллбара setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); } void StickyTableViewFixed::setStickyColumns(int count) { if (m_stickyColumns != count) { m_stickyColumns = count; updateStickyColumnGeometry(); viewport()->update(); } } void StickyTableViewFixed::paintEvent(QPaintEvent *event) { // Сначала рисуем обычную таблицу QTableView::paintEvent(event); // Затем рисуем липкие столбцы поверх if (m_stickyColumns > 0 && model()) { QPainter painter(viewport()); paintStickyColumns(&painter); } } void StickyTableViewFixed::scrollContentsBy(int dx, int dy) { QTableView::scrollContentsBy(dx, dy); // Обновляем геометрию липких столбцов после скролла updateStickyColumnGeometry(); } void StickyTableViewFixed::resizeEvent(QResizeEvent *event) { QTableView::resizeEvent(event); updateStickyColumnGeometry(); } QModelIndex StickyTableViewFixed::indexAt(const QPoint &point) const { // Проверяем, находится ли точка в области липких столбцов if (point.x() < m_stickyColumnWidth) { // Ищем в липких столбцах for (int row = 0; row < model()->rowCount(); ++row) { for (int col = 0; col < m_stickyColumns; ++col) { QRect rect = stickyColumnRect(row, col); if (rect.contains(point)) { return model()->index(row, col); } } } } // Иначе используем стандартную логику return QTableView::indexAt(point); } QRect StickyTableViewFixed::visualRect(const QModelIndex &index) const { if (!index.isValid()) return QRect(); // Если это липкий столбец, возвращаем его координаты if (index.column() < m_stickyColumns) { return stickyColumnRect(index.row(), index.column()); } // Иначе используем стандартную логику return QTableView::visualRect(index); } void StickyTableViewFixed::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); } // НЕ устанавливаем отступы для viewport - это вызывает проблемы // Вместо этого будем правильно обрабатывать координаты } void StickyTableViewFixed::paintStickyColumns(QPainter *painter) { if (!model() || m_stickyColumns <= 0) return; // Сохраняем состояние painter painter->save(); // Получаем видимые строки QRect visibleRect = viewport()->rect(); int topRow = rowAt(visibleRect.top()); int bottomRow = rowAt(visibleRect.bottom()); if (topRow < 0) topRow = 0; if (bottomRow < 0) bottomRow = model()->rowCount() - 1; // Рисуем липкие столбцы for (int row = topRow; row <= bottomRow && row < model()->rowCount(); ++row) { for (int col = 0; col < m_stickyColumns && col < model()->columnCount(); ++col) { QRect cellRect = stickyColumnRect(row, col); // Рисуем фон ячейки QModelIndex index = model()->index(row, col); QStyleOptionViewItem option; option.initFrom(this); option.rect = cellRect; option.state = QStyle::State_Enabled; if (selectionModel() && 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(); } QRect StickyTableViewFixed::stickyColumnRect(int row, int col) const { if (!model() || row < 0 || col < 0 || col >= m_stickyColumns) return QRect(); int y = rowViewportPosition(row); int currentRowHeight = rowHeight(row); int x = 0; for (int i = 0; i < col; ++i) { x += columnWidth(i); } return QRect(x, y, columnWidth(col), currentRowHeight); }