Qt编程-QTableView同时冻结行和列

前言

Qt编程-QTableView同时冻结行和列。如题,先看效果是不是你需要的。网上找到的代码片段要么不全要么不是想要的。如果你只需要需要冻结行或冻结列,请看上篇博客 Qt编程-QTableView冻结行或冻结列或冻结局部单元格 ,代码更少一些。

同时冻结行列带表头:
在这里插入图片描述

同时冻结行列不带表头:
在这里插入图片描述

原理

冻结行或者冻结列原理: 使用3个tableview ,内容一样,最上层tableview显示交叉部分内容,中间层显示冻结的行tableview和冻结列tableview 把非冻结的内容隐藏掉,下层显示全部内容 下层tableview正常滑动就有冻结行或者列的效果了。

代码

代码改造来自 Qt自带例子 。可通过宏变量FREEZE_COL和FREEZE_ROW控制冻结行或冻结列,宏变量TABLE_HEAD控制表头显示。完整工程代码下载

主要代码如下:

freezetablewidget.h

#ifndef FREEZETABLEWIDGET_H
#define FREEZETABLEWIDGET_H

#include <QTableView>

//! [Widget definition]
class FreezeTableWidget : public QTableView {
    Q_OBJECT

public:
    FreezeTableWidget(QAbstractItemModel * model);
    ~FreezeTableWidget();


protected:
    void resizeEvent(QResizeEvent *event) override;
    QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
    void scrollTo (const QModelIndex & index, ScrollHint hint = EnsureVisible) override;

private:
    QTableView *frozenCroTableView; //冻结行冻结列交叉部分的TableView
    QTableView *frozenColTableView; //冻结列的TableView
    QTableView *frozenRowTableView; //冻结行的TableView
    void initCroTable();
    void initColTable();
    void initRowTable();
    void updateFrozenCroTableGeometry();
    void updateFrozenColTableGeometry();
    void updateFrozenRowTableGeometry();


private slots:
    void updateSectionWidth(int logicalIndex, int oldSize, int newSize);
    void updateSectionHeight(int logicalIndex, int oldSize, int newSize);
private:
    //冻结的行列数
    int m_iFreezeCols = 3;
    int m_iFreezeRows = 3;
};
//! [Widget definition]
#endif // FREEZETABLEWIDGET_H

freezetablewidget.cpp

#include "freezetablewidget.h"

#include <QScrollBar>
#include <QHeaderView>
#include <QDebug>

#define FREEZE_COL 1 //冻结列开关
#define FREEZE_ROW 1 //冻结行开关
#define TABLE_HEAD 0 //表头是否显示

//! [constructor]
FreezeTableWidget::FreezeTableWidget(QAbstractItemModel * model)
{
    /*
      冻结行或者冻结列 原理:实质上有2个tableview
            FreezeTableWidget 这个正常显示所有的表格数据
            frozenColTableView 这个表格放在FreezeTableWidget的上面 只显示 冻结的列,这样下面的 FreezeTableWidget 正常滑动就有冻结列的效果了。
      同时冻结行列 原理类似,不过是3个tableview,冻结行和冻结列的tableview交叉部分单独作为一个tableview要放在最顶层,下面是冻结行和冻结列的tableview 最下面是 FreezeTableWidget的tableview。
     */
    verticalHeader()->setVisible(TABLE_HEAD);
    horizontalHeader()->setVisible(TABLE_HEAD);

    setModel(model);

#if (FREEZE_COL && FREEZE_ROW)
    frozenCroTableView = new QTableView(this);
    initCroTable();
#endif

#if FREEZE_COL
    frozenColTableView = new QTableView(this);
    initColTable();
#endif

#if FREEZE_ROW
    frozenRowTableView = new QTableView(this);
    initRowTable();
#endif


    //connect the headers and scrollbars of both tableviews together
#if FREEZE_COL
    connect(horizontalHeader(),&QHeaderView::sectionResized, this,
            &FreezeTableWidget::updateSectionWidth);
#endif
#if FREEZE_ROW
    connect(verticalHeader(),&QHeaderView::sectionResized, this,
            &FreezeTableWidget::updateSectionHeight);
#endif

    //LUpdate
    //冻结列,纵向滚动条可正常滑动
#if FREEZE_COL
    connect(frozenColTableView->verticalScrollBar(), &QAbstractSlider::valueChanged,
            verticalScrollBar(), &QAbstractSlider::setValue);
    connect(verticalScrollBar(), &QAbstractSlider::valueChanged,
            frozenColTableView->verticalScrollBar(), &QAbstractSlider::setValue);
#endif
    //冻结行,横向向滚动条可正常滑动
#if FREEZE_ROW
    connect(frozenRowTableView->horizontalScrollBar(), &QAbstractSlider::valueChanged,
            horizontalScrollBar(), &QAbstractSlider::setValue);
    connect(horizontalScrollBar(), &QAbstractSlider::valueChanged,
            frozenRowTableView->horizontalScrollBar(), &QAbstractSlider::setValue);
#endif

}
//! [constructor]

FreezeTableWidget::~FreezeTableWidget()
{
#if FREEZE_COL
    delete frozenColTableView;
#endif
#if FREEZE_ROW
    delete frozenRowTableView;
#endif
#if FREEZE_COL && FREEZE_ROW
    delete frozenCroTableView;
#endif
}

//! [init part1]
void FreezeTableWidget::initCroTable()
{
    frozenCroTableView->setModel(model());
    frozenCroTableView->setObjectName("frozenCroTableView");
    frozenCroTableView->setFocusPolicy(Qt::NoFocus);
    frozenCroTableView->verticalHeader()->setFixedWidth(verticalHeader()->width());
    frozenCroTableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
    frozenCroTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
#if !TABLE_HEAD
    frozenCroTableView->horizontalHeader()->hide();
    frozenCroTableView->verticalHeader()->hide();
#endif

    viewport()->stackUnder(frozenCroTableView);
    //! [init part1]

    //! [init part2]
    frozenCroTableView->setStyleSheet("#frozenCroTableView{ border: none;"
                                      "background-color: #AEC8FF;"
                                      "selection-background-color: #999}"); //for demo purposes
    frozenCroTableView->setSelectionModel(selectionModel());

    //LUpdate
    //隐藏冻结列以外的数据
    for (int col = m_iFreezeCols; col < model()->columnCount(); ++col)
        frozenCroTableView->setColumnHidden(col, true);

    for(int i = 0; i < m_iFreezeCols; i++)
    {
        frozenCroTableView->setColumnWidth(i, columnWidth(0));
    }
    //隐藏冻结行以外的行的数据
    for (int row = m_iFreezeRows; row < model()->rowCount(); ++row)
        frozenCroTableView->setRowHidden(row, true);
    for(int i = 0; i < m_iFreezeRows; i++)
    {
        frozenCroTableView->setRowHeight(i, rowHeight(0));
    }

    frozenCroTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    frozenCroTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    frozenCroTableView->show();

    updateFrozenCroTableGeometry();

    setHorizontalScrollMode(ScrollPerPixel);
    setVerticalScrollMode(ScrollPerPixel);
    frozenCroTableView->setVerticalScrollMode(ScrollPerPixel);
    frozenCroTableView->setHorizontalScrollMode(ScrollPerPixel);
}

//! [init part1]
void FreezeTableWidget::initColTable()
{
    frozenColTableView->setModel(model());
    frozenColTableView->setObjectName("frozenColTableView");
    frozenColTableView->setFocusPolicy(Qt::NoFocus);
    frozenColTableView->verticalHeader()->setFixedWidth(verticalHeader()->width());
    frozenColTableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
    frozenColTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
#if !TABLE_HEAD
    frozenColTableView->horizontalHeader()->hide();
    frozenColTableView->verticalHeader()->hide();
#endif

#if FREEZE_COL && FREEZE_ROW
    frozenColTableView->stackUnder(frozenCroTableView);
#else
    viewport()->stackUnder(frozenColTableView);
#endif

    //! [init part1]

    //! [init part2]
    frozenColTableView->setStyleSheet("#frozenColTableView{ border: none;"
                                      "background-color: #8EDE21;"
                                      "selection-background-color: #999}"); //for demo purposes
    frozenColTableView->setSelectionModel(selectionModel());

    //LUpdate
    //隐藏冻结列以外的数据
    for (int col = m_iFreezeCols; col < model()->columnCount(); ++col)
        frozenColTableView->setColumnHidden(col, true);

    for(int i = 0; i < m_iFreezeCols; i++)
    {
        frozenColTableView->setColumnWidth(i, columnWidth(0));
    }

    frozenColTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    frozenColTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    frozenColTableView->show();

    updateFrozenColTableGeometry();

    setHorizontalScrollMode(ScrollPerPixel);
    setVerticalScrollMode(ScrollPerPixel);
    frozenColTableView->setVerticalScrollMode(ScrollPerPixel);
    frozenColTableView->setHorizontalScrollMode(ScrollPerPixel);
}

void FreezeTableWidget::initRowTable()
{
    frozenRowTableView->setModel(model());
    frozenRowTableView->setObjectName("frozenRowTableView");
    frozenRowTableView->setFocusPolicy(Qt::NoFocus);
    frozenRowTableView->verticalHeader()->setFixedWidth(verticalHeader()->width());
    frozenRowTableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
    frozenRowTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
#if !TABLE_HEAD
    frozenRowTableView->horizontalHeader()->hide();
    frozenRowTableView->verticalHeader()->hide();
#endif

#if FREEZE_COL
    frozenRowTableView->stackUnder(frozenColTableView);
#else
    viewport()->stackUnder(frozenRowTableView);
#endif

    //! [init part1]

    //! [init part2]
    frozenRowTableView->setStyleSheet("#frozenRowTableView{ border: none;"
                                      "background-color: #f44c46;"
                                      "selection-background-color: #999}"); //for demo purposes
    frozenRowTableView->setSelectionModel(selectionModel());

    //LUpdate
    //隐藏冻结行以外的行的数据
    for (int row = m_iFreezeRows; row < model()->rowCount(); ++row)
        frozenRowTableView->setRowHidden(row, true);
    for(int i = 0; i < m_iFreezeRows; i++)
    {
        frozenRowTableView->setRowHeight(i, rowHeight(0));
    }

    frozenRowTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    frozenRowTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    frozenRowTableView->show();

    updateFrozenRowTableGeometry();

    setHorizontalScrollMode(ScrollPerPixel);
    setVerticalScrollMode(ScrollPerPixel);
    frozenRowTableView->setVerticalScrollMode(ScrollPerPixel);
    frozenRowTableView->setHorizontalScrollMode(ScrollPerPixel);
}
//! [init part2]


//! [sections]
void FreezeTableWidget::updateSectionWidth(int logicalIndex, int /* oldSize */, int newSize)
{
    qDebug() << "updateSectionWidth" << logicalIndex << newSize;
    //LUpdate
#if FREEZE_COL
    if (logicalIndex == m_iFreezeCols-1){

        int width = 0;
        for(int i = 0; i< m_iFreezeCols-1; i++)
        {
            width += columnWidth(i);
        }

        for(int i = 0; i< m_iFreezeCols; i++)
        {
            frozenColTableView->setColumnWidth(i, (newSize+width)/m_iFreezeCols);
        }
        updateFrozenColTableGeometry();
    }
#else
    frozenColTableView->setColumnWidth(logicalIndex, newSize);
#endif
}

void FreezeTableWidget::updateSectionHeight(int logicalIndex, int /* oldSize */, int newSize)
{
    qDebug() << "updateSectionHeight" << logicalIndex << newSize;
    //LUpdate
#if FREEZE_ROW
    if (logicalIndex == m_iFreezeRows-1){

        int height = 0;
        for(int i = 0; i< m_iFreezeRows-1; i++)
        {
            height += rowHeight(i);
        }

        for(int i = 0; i< m_iFreezeRows; i++)
        {
            frozenRowTableView->setRowHeight(i, (newSize+height)/m_iFreezeRows);
        }
        updateFrozenRowTableGeometry();
    }
#else
    frozenRowTableView->setRowHeight(logicalIndex, newSize);
#endif
}
//! [sections]


//! [resize]
void FreezeTableWidget::resizeEvent(QResizeEvent * event)
{
    QTableView::resizeEvent(event);
#if FREEZE_COL
    updateFrozenColTableGeometry();
#endif

#if FREEZE_ROW
    updateFrozenRowTableGeometry();
#endif

#if FREEZE_ROW && FREEZE_COL
    updateFrozenCroTableGeometry();
#endif

}
//! [resize]


//! [navigate]
QModelIndex FreezeTableWidget::moveCursor(CursorAction cursorAction,
                                          Qt::KeyboardModifiers modifiers)
{
    QModelIndex current = QTableView::moveCursor(cursorAction, modifiers);

#if FREEZE_COL
    if (cursorAction == MoveLeft && current.column() > 0
            && visualRect(current).topLeft().x() < frozenColTableView->columnWidth(0) ){
        const int newValue = horizontalScrollBar()->value() + visualRect(current).topLeft().x()
                - frozenColTableView->columnWidth(0);
        horizontalScrollBar()->setValue(newValue);
    }
#endif
#if FREEZE_ROW
    if(cursorAction == MoveDown && current.row() > 0
            && visualRect(current).topLeft().y() < frozenRowTableView->rowHeight(0))
    {
        const int newValue = verticalScrollBar()->value() + visualRect(current).topLeft().y()
                - frozenRowTableView->rowHeight(0);
        verticalScrollBar()->setValue(newValue);
    }
#endif
    return current;
}
//! [navigate]

void FreezeTableWidget::scrollTo (const QModelIndex & index, ScrollHint hint){
    if (index.column() > 0)
        QTableView::scrollTo(index, hint);
}

//! [geometry]
void FreezeTableWidget::updateFrozenCroTableGeometry()
{
    qDebug() << "updateFrozenCroTableGeometry ==";
    //LUpdate
    int width = 0, height = 0, x = 0, y = 0;
    qDebug() << "ver:" << verticalHeader()->width() << verticalHeader()->height();
    qDebug() << "hor:" << horizontalHeader()->width() << horizontalHeader()->height();
    qDebug() << "frame:" << frameWidth() << frameRect().width()<< frameRect().height() << frameRect().x() << frameRect().y();
    x = frameWidth();
    y = frameWidth();

#if FREEZE_COL && FREEZE_ROW
    width = verticalHeader()->width();
    for(int i = 0; i< m_iFreezeCols; i++)
    {
        width += columnWidth(i);
    }
    height = horizontalHeader()->height();
    for(int i = 0; i< m_iFreezeRows; i++)
    {
        height += rowHeight(i);
    }
#else
    width = viewport()->width()+verticalHeader()->width();
    height = viewport()->height()+horizontalHeader()->height();
#endif

    qDebug() << "x, y, width, height" << x << y << width << height;
    frozenCroTableView->setGeometry(x, y, width, height);
}
//! [geometry]

//! [geometry]
void FreezeTableWidget::updateFrozenColTableGeometry()
{
    qDebug() << "updateFrozenColTableGeometry ==";
    //LUpdate
    int width = 0, height = 0, x = 0, y = 0;
    qDebug() << "ver:" << verticalHeader()->width() << verticalHeader()->height();
    qDebug() << "hor:" << horizontalHeader()->width() << horizontalHeader()->height();
    qDebug() << "frame:" << frameWidth() << frameRect().width()<< frameRect().height() << frameRect().x() << frameRect().y();
    x = frameWidth();
    y = frameWidth();

#if FREEZE_COL
    width = verticalHeader()->width();
    for(int i = 0; i< m_iFreezeCols; i++)
    {
        width += columnWidth(i);
    }
#else
    width = viewport()->width()+verticalHeader()->width();
#endif

    height = viewport()->height()+horizontalHeader()->height();

    qDebug() << "x, y, width, height" << x << y << width << height;
    frozenColTableView->setGeometry(x, y, width, height);
}
//! [geometry]

//! [geometry]
void FreezeTableWidget::updateFrozenRowTableGeometry()
{
    qDebug() << "updateFrozenRowTableGeometry ==";
    //LUpdate
    int width = 0, height = 0, x = 0, y = 0;
    qDebug() << "ver:" << verticalHeader()->width() << verticalHeader()->height();
    qDebug() << "hor:" << horizontalHeader()->width() << horizontalHeader()->height();
    qDebug() << "frame:" << frameWidth() << frameRect().width()<< frameRect().height() << frameRect().x() << frameRect().y();
    x = frameWidth();
    y = frameWidth();
    width = viewport()->width()+verticalHeader()->width();
#if FREEZE_ROW
    height = horizontalHeader()->height();
    for(int i = 0; i< m_iFreezeRows; i++)
    {
        height += rowHeight(i);
    }
#else
    height = viewport()->height()+horizontalHeader()->height();
#endif

    qDebug() << "x, y, width, height" << x << y << width << height;
    frozenRowTableView->setGeometry(x, y, width, height);
}
//! [geometry]



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值