170 lines
5.5 KiB
C++
170 lines
5.5 KiB
C++
#include "stickytableview_fixed.h"
|
|
#include <QScrollBar>
|
|
#include <QHeaderView>
|
|
#include <QPainter>
|
|
#include <QApplication>
|
|
#include <QDebug>
|
|
|
|
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);
|
|
}
|