QRowTable表格控件-支持hover整行、checked整行、指定列排序等

原文连接:QRowTable表格控件-支持hover整行、checked整行、局部列排序等浏览器

1、开心一刻

老公和老婆晚上回家,路旁忽然跳出三个持刀蒙面大汉:“绑架!你俩能够走一个,回家等消息。”ide

老公一把将老婆推开:“老婆快走!”待老婆走远后,三个蒙面人摘下面具:“尼玛如今找你打个麻将这么费劲?”函数

五分钟后老公致电老婆:"往卡里打五千块,别报警,他们说关我一晚上明早放人。"十分钟后老公从卡里取走五千块战斗到天明。测试

第二天老公回家,老婆扑上来含泪说:“关键时候才能看出老公对个人好,老公之后我啥都听你的!字体

2、嘴一嘴

看完笑话,咱们进入正题。this

本篇文章咱们带来的是一个表格的简单使用,主要是把表格的hover、checked进行了从新定制,支持用户本身去设置相关颜色,而且能够对指定列进行放大缩小等。spa

为何会写这篇文章呢?博主本身使用Qt也好几年了,对于Qt的使用算是比较有心得了吧。最近在作表格的一些相关东西,发现网上的不少文章讲的不是特别好,所以将本身作的一个简单事例作一分享,但愿能帮到有须要的同窗。插件

本篇文章咱们主要对表格的如下内容进行了封装,内容比较有限,有深度定制需求的同窗能够加我QQ详谈。设计

  1. hover行背景色
  2. checked行背景色
  3. 列宽是否可排序
  4. 列宽容许拖动范围
  5. 准肯定位hover状态

3、效果展现

以下图所示,一个简单的gif效果展现。

配色时博主本身随便搞的,配色只能说很通常,你们主要看效果和实现思路。

4、浅谈实现

使用过QTableView或者了解控件的同窗应该都很清楚,表格是一个很强大的控件,支持咱们作各类各样的功能,博主以前也想过几篇相关的文章,都是讲述表格控件的。

  1. Qt实现表格控件-支持多级列表头、多级行表头、单元格合并、字体设置等

  2. Qt高仿Excel表格组件-支持冻结列、冻结行、内容自适应和合并单元格

  3. 属性浏览器控件QtTreePropertyBrowser编译成动态库(设计师插件)

  4. 超级实用的属性浏览器控件--QtTreePropertyBrowser

  5. Qt之表格控件蚂蚁线

固然了表格控件的使用远远不止于此,后续有时间和精力我会陆续推出更多有用好玩儿的功能。

本篇文章的功能实现也比较简单,写这个demo我大概用了大半天的时间,代码量其实很少,大部分的时间主要用来设计接口和重构逻辑功能了。

以下图所示,是整个工程目录结构,这里主要重写了数据源model和view

下面咱们就分别讲述model和view都干了些什么

5、自定义数据源

所谓数据源,其实主要就是给view提供数据的地方,这里咱们取了一个巧,数据源直接继承自QStandarItemModel,这样的话数据的存储和获取大部分的工做都不须要咱们去关心,由于QStandarItemModel这个类已经作的很完善。

这里咱们主要从写了两个接口

virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

virtual Qt::ItemFlags flags(const QModelIndex & index) const override;

一、data函数

视图获取数据的接口就是data,所以这个接口咱们必须重写,实现代码也很简单,主要是须要你们对Qt的MVC有一个基本的认识。

QVariant QRowModel::data(const QModelIndex & index, int role /*= Qt::DisplayRole*/) const
{
    if (Qt::BackgroundRole == role)
    {
        if (index.row() == m_iHoverRow)
        {
            return m_HoverColor;
        }
    }
    else if (role == Qt::ForegroundRole)
    {
        if (index.row() == m_iHoverRow)
        {
            return m_HoverColor.lighter(255);
        }
    }

    return QStandardItemModel::data(index, role);
}

看上述代码,当绘制视图的时候,hover一行时,咱们须要返回自定义的颜色值,其余状况走默认处理便可,是否是很简单。

关于checked的实现不能放在这里,由于当item被选中的时候,item的背景色不是取自Qt::BackgroundRole,同时前景色也不是取自Qt::ForegroundRole,所以这里处理不了。

若是非要让checked状态在这里实现也是有办法的,咱们能够重写flags函数,让item不能被选中,这个办法博主是试过的,没有问题。 可是就存在一个隐,若是后期咱们的item想被选中,就比较麻烦了。

基于以上设想,咱们只须要这样重写flags函数,而后在data函数中返回checked行的背景色和前景色便可。

Qt::ItemFlags QRowModel::flags(const QModelIndex & index) const
{
    return Qt::ItemIsEnabled;
}

二、flags函数

上一小节flags函数都已经展现出来了,item处于可用状态,这里还须要在添加上可选中状态,以避免有其余坑

Qt::ItemFlags QRowModel::flags(const QModelIndex & index) const
{
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

以上就是model函数的重写了,比较简单,下面放出model的头文件

/**
* 简介: 主要提供接口 提供hover行
*/
class QRowModel : public QStandardItemModel
{
    Q_OBJECT

public:
    explicit QRowModel(QObject * parent = 0);
    ~QRowModel();

private:
    //hover时背景色  不建议外部直接调用
    void SetHoverColor(const QColor & color);
    QColor GetHoverColor() const { return m_HoverColor; }

    //设置当前hover行  不建议外部直接调用
    void SetHoverRow(int row);
    int GetHoverRow() const { return m_iHoverRow; }

protected:
    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

    virtual Qt::ItemFlags flags(const QModelIndex & index) const override;

private:
    int m_iHoverRow = -1;//没有hover
    QColor m_HoverColor = QColor(20, 22, 23);

    friend class QRowTable;
};

6、自定义视图

下面讲述今天的重头戏view。

首先须要搞清楚,重写视图须要完成哪些工做,才能更好的准备定位每一个函数的意思。

一、目的

  1. hover时,把hover行通知到数据源
  2. 准确的hover和取消hover状态,这个问题确实搞了很久
  3. 点击item时,设置行选中色
  4. 指定列可排序

有了以上目标以后,咱们逐个问题解决。

二、问题分析

针对以上4个目的,咱们逐个分析解决办法

一、鼠标hover到这个比较简单,并且能够经过多种方式进行获取。

想要拿到这个状态,有一个很重要的属性须要开启:setMouseTracking(true);

a、若是咱们重写的是QTableWidget这个类,那么能够去接收cellEntered这个信号

b、若是重写跟本篇文章同样,重写的QTableView这个类,那么咱们须要重写mouseMoveEvent这个函数,而后经过indexAt函数获取当前行。

void QRowTable::mouseMoveEvent(QMouseEvent * event)
{
    QTableView::mouseMoveEvent(event);

    const QModelIndex & index = indexAt(event->pos());
    int row = -1;
    if (index.isValid())
    {
        row = index.row();
    }

    if (m_pModel->GetHoverRow() != row)
    {
        m_pModel->SetHoverRow(index.row());
        viewport()->update();
    }
}

二、取消hover装态

这个问题处理确实化了好长时间,主要仍是想处理的办法更优雅,效率高一些。

这里为了实现不在item上时马上取消hover状态,主要作了2件事。

第一件事

重写leaveEvent函数,鼠标离开时,恢复hover行为-1

void QRowTable::leaveEvent(QEvent * e)
{
    if (m_pModel->GetHoverRow() != -1)
    {
        m_pModel->SetHoverRow(-1);
        viewport()->update();
    }
    QTableView::leaveEvent(e);
}

第二件事

重写了QHeaderView,当鼠标在表头移动时,发送MouseMove信号,重置当前hover行为-1

void QRowHeader::mouseMoveEvent(QMouseEvent * event)
{
    emit MouseMove();

    QHeaderView::mouseMoveEvent(event);
}
auto callback = [this]{
    if (m_pModel->GetHoverRow() != -1)
    {
        m_pModel->SetHoverRow(-1);
        viewport()->update();
    }
};
connect(vHeader, &QRowHeader::MouseMove, this, callback);
connect(hHeader, &QRowHeader::MouseMove, this, callback);

以上这个办法也是不得已为之,若是你们有更好的办法,欢迎评论区留言

三、点击item时设置当前行高亮背景色

第一小节的最后,咱们也提到了,checked正行能够放到data函数中完成,可是因为咱们的item有了可选择属性后,当前选中的item,或者选中行的背景色和前景色都是取自如下两个属性,所以这里咱们只须要把这两个属性颜色值进行设置便可。

QPalette::Highlight
QPalette::HighlightedText

设置checked行颜色实现方式以下。

void QRowTable::SetCheckedColor(const QColor & color)
{
    m_CheckedColor = color;

    QPalette palette = this->palette();
    palette.setBrush(QPalette::Inactive, QPalette::Highlight, m_CheckedColor);
    palette.setBrush(QPalette::Inactive, QPalette::HighlightedText, m_CheckedColor.lighter(255));
    setPalette(palette);
}

若是仔细想想,可能就会以为有些问题,这里咱们怎么去控制是一个单元格背景色仍是整行背景色呢?

莫慌,加上如下两个属性便可,接口真的很简单,啥意思我就不说了。若是实现不知道的同窗,欢迎评论区留言

setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QTableView::SingleSelection);//不能多选

四、 指定列排序

首先须要搞清楚Qt自带的排序处理逻辑,而后才能够对症下药,这里我也是跟了Qt本身代码,而后各类分析后,得出的处理方式。

Qt的代码分析这里不作讨论,有须要的同窗私信吧。

各类代码跟踪后发现,当咱们设置了setSortingEnabled为true时,Qt就支持排序了,而且在排序完成后会发给咱们一个sortIndicatorChanged信号,这个信号主要是用来显示排序三角形的。

若是咱们想不显示排序三角形,可是只是排序也是能够的,能够在接收这个信号后,调用setSortIndicatorShown接口隐藏三角形

为何会这样麻烦呢?由于楼主跟踪Qt的代码了,发现若是排序了,Qt的三角形就是必须画出来的

void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const
{
    ...
    if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex)
        opt.sortIndicator = (sortIndicatorOrder() == Qt::AscendingOrder)
                            ? QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp;
                            
    ...
}

是否是很刺激,Qt太强大了,啥事情都给咱们搞好了。

本篇文章咱们主要是实现指定列不能进行排序,所以处理函数是这么干的,当接收到非排序列排序信号时,调用setSortingEnabled接口设置禁止排序。

void QRowTable::SortColumnChanged(int logicalIndex, Qt::SortOrder order)
{
    if (m_Indicator.contains(logicalIndex) && m_Indicator[logicalIndex] == false)
    {
        if (isSortingEnabled())
        {
            setSortingEnabled(false);
        }
    }
    else
    {
        if (isSortingEnabled() == false)
        {
            setSortingEnabled(true);
        }
    }
}

7、测试

一、view配置

QRowTable w;

//前两列不可排序
w.SetIndicatorVisible(0, false);
w.SetIndicatorVisible(1, false);

//设置列最大宽度
w.SetColumnMinWidth(50);

//设置列最小宽度
w.SetColumnMaxWidth(150);

w.SetHoverColor(Qt::red);

二、model配置

QRowModel * model = w.GetModel();

QStringList headlist;
headlist << QStringLiteral("代码") << QStringLiteral("名称") << QStringLiteral("行业") << QStringLiteral("价格") << QStringLiteral("涨跌幅") << QStringLiteral("换手率");
model->setHorizontalHeaderLabels(headlist);

数据添加就跟咱们平时往QStandardItemModel中放数据相似,代码太长就不放出来了。

8、相关文章

  1. Qt实现表格控件-支持多级列表头、多级行表头、单元格合并、字体设置等

  2. Qt高仿Excel表格组件-支持冻结列、冻结行、内容自适应和合并单元格

  3. 属性浏览器控件QtTreePropertyBrowser编译成动态库(设计师插件)

  4. 超级实用的属性浏览器控件--QtTreePropertyBrowser

  5. Qt之表格控件蚂蚁线

以上就是本篇文章的全部内容了,一个简易的整行hover、整行checked的表格





若是您以为文章不错,不妨给个 打赏,写做不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!














很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权全部,转载时请用连接的方式,给出原文出处。同时写上原做者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时经过修改本文达到有利于转载者的目的。

相关文章
相关标签/搜索