Qt自定义Delegate实现QTableWidget整行选中圆角矩形高亮效果

问题背景

参照一个现有的Linux桌面应用,尽可能的模仿它的UI,其中有一个UI效果就是列表整行选中后是一个圆角矩形高亮效果,如下图所示。
在这里插入图片描述

参考代码

先放代码,实现的思路就是用代理来重绘我们想要的效果。

#include <QStyledItemDelegate>
class MyDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    MyDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {}
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;

private:
    void paintBackground(QPainter *painter, const QRect &rect, const int &column, const QBrush &brush) const;
    void paintBackgroundBase(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void paintBackgroundAlternateBase(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void paintBackgroundHighLighted(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

    void paintForegroundText(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                         const QModelIndex &index) const
{
    if (option.state & QStyle::State_Selected)
    {
        paintBackgroundHighLighted(painter, option, index);
    }
    else if ( index.row() % 2 == 0)
    {
        paintBackgroundBase(painter, option, index);
    }
    else
    {
        paintBackgroundAlternateBase(painter, option, index);
    }

    paintForegroundText(painter, option, index);
}

void MyDelegate::paintBackgroundHighLighted(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    paintBackground(painter, option.rect, index.column(), option.palette.highlight());
}

void MyDelegate::paintBackgroundBase(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    paintBackground(painter, option.rect, index.column(), option.palette.base());
}

void MyDelegate::paintBackgroundAlternateBase(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    paintBackground(painter, option.rect, index.column(), option.palette.alternateBase());
}

void MyDelegate::paintBackground(QPainter *painter, const QRect &rect, const int &column, const QBrush &brush) const
{
    int width = rect.width();
    if ( column == 0 /*option.viewItemPosition == QStyleOptionViewItem::Beginning*/)
    {
        QPainterPath path;
        path.setFillRule(Qt::WindingFill);
        path.addRoundedRect(rect, 8, 8);
        path.addRect(QRect(rect.x() + width / 2, rect.y(), width / 2, rect.height()));
        painter->fillPath(path, brush);
    }
    else if ( column == 2/*option.viewItemPosition == QStyleOptionViewItem::End*/)
    {
        QPainterPath path;
        path.setFillRule(Qt::WindingFill);
        path.addRoundedRect(rect, 8, 8);
        path.addRect(QRect(rect.x(), rect.y(), width / 2, rect.height()));
        painter->fillPath(path, brush);
    }
    else
    {
         painter->fillRect(rect, brush);
    }
}

void MyDelegate::paintForegroundText(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QFontMetrics fontMetrics(painter->font());
    QString msg = fontMetrics.elidedText(index.data().toString(), Qt::ElideRight, option.rect.width());
    QApplication::style()->drawItemText(painter, option.rect, option.displayAlignment, QApplication::palette(), true, msg);
}

代码讲解

推荐继承自QStyledItemDelegate,因为它可以使用当前的Sytle绘制Items,而继承QItemDelegate需要自定义Sytle。具体可以参考Qt的手册 QStyledItemDelegate vs. QItemDelegate,讲解的比较详细。

QStyledItemDelegate vs. QItemDelegate
Since Qt 4.4, there are two delegate classes: QItemDelegate and QStyledItemDelegate. However, the default delegate is QStyledItemDelegate. These two classes are independent alternatives to painting and providing editors for items in views. The difference between them is that QStyledItemDelegate uses the current style to paint its items. We therefore recommend using QStyledItemDelegate as the base class when implementing custom delegates or when working with Qt style sheets. The code required for either class should be equal unless the custom delegate needs to use the style for drawing. If you wish to customize the painting of item views, you should implement a custom style. Please see the QStyle class documentation for details.

Qt没有部分绘制圆角,部分绘制直角矩形的接口,所以实现上述效果有两个思路:

  1. 从点线开始,完全重绘一个满足我们要求的矩形;
  2. 将圆角矩形和直角矩形部分重叠,从而实现一半是圆角,一半是直角的矩形。

采用第二种办法,代码如下,需要注意的是填充效果需要是Qt::WindingFill

QPainterPath path;
path.setFillRule(Qt::WindingFill); /* 填充效果 */
path.addRoundedRect(rect, 8, 8);
path.addRect(QRect(rect.x() + width / 2, rect.y(), width / 2, rect.height()));
painter->fillPath(path, brush);

如果表格中的文字太长的话,人性化的效果是被遮挡的部分用省略号表示出来,代码如下所示。继承自QStyledItemDelegate后,我们就不用关心这行文字的效果是高亮选中的,还是普通效果,直接丢给接口即可。

void MyDelegate::paintForegroundText(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QFontMetrics fontMetrics(painter->font());
    QString msg = fontMetrics.elidedText(index.data().toString(), Qt::ElideRight, option.rect.width());
    QApplication::style()->drawItemText(painter, option.rect, option.displayAlignment, QApplication::palette(), true, msg);
}

推荐使用表格背景交替的显示效果,并且未选中高亮的背景也是圆角矩形显示。提取出两个接口

    void paintBackgroundBase(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void paintBackgroundAlternateBase(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值