QTreeView实现圆角样式

QTreeView实现圆角样式QTreeView实现圆角样式在QTreeView等继承于QAbstractItemView表格中,定制表格样式通常都是通过设置项目代理(ItemDelegate)来实现。在这种实现方法中,每个项目(Item)基本上是孤立的,无法有效判断己身周遭环境。如果以此种方法来实现圆角样式,行首或许还能通过方法intQModelindex::column()来判断是否属于第一列来断定,然而行尾难道还要通过QAbstractItemModelQModelindex::*model()获取模型(Model)之后再

大家好,又见面了,我是你们的朋友全栈君。

QTreeView实现圆角样式

在QTreeView等继承于QAbstractItemView表格中,定制表格样式通常都是通过设置项目代理(ItemDelegate)来实现。在这种实现方法中,每个项目(Item)基本上是孤立的,无法有效判断己身周遭环境。
如果以此种方法来实现圆角样式,行首或许还能通过方法int QModelindex::column()来判断是否属于第一列来断定,然而行尾难道还要通过QAbstractItemModel QModelindex::*model()获取模型(Model)之后再来判断吗?且视图(View)本身可以隐藏、拖拽指定行、列,所以这种方式并不靠谱。
更正:
QStyleOptionViewItem提供了获取可视项目位置的接口,可通过

QStyleOptionViewItem::viewItemPosition

这个枚举值获取。更正此处错误描述并更新

QPainterPath TreeViewStyle::roundedPath(const QStyleOptionViewItem *o, const QWidget *w) const

样式表(StyleSheet)似乎也不支持此种操作。

继承QProxyStyle

为了保持与系统或部件所使用的样式一致,应当选择继承QProxyStyle而非QStyle及其它(QCommonStyle等)。

class TreeViewStyle : public QProxyStyle
{ 
   
	Q_OBJECT
public:
    explicit TreeViewStyle(QStyle *style = nullptr);
}

重载绘制函数

    void drawPrimitive(QStyle::PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w) const override;

绘制选中状态

    void drawPanelItemViewRow(const QStyleOption *opt, QPainter *p, const QWidget *w) const;

绘制行背景

行背景即列表背景,通常情况下没有绘制。一般仅在设置了行颜色交替的情况下绘制。

    void drawPanelItemViewItem(const QStyleOption *opt, QPainter *p, const QWidget *w) const;

绘制路径计算函数

计算绘制路径即选中状态、行背景所需绘制区域。

    QPainterPath roundedPath(const QStyleOptionViewItem *opt, const QWidget *w) const;

用法

QTreeView view = new QTreeView(this);
view->setStyle(new TreeViewStyle(view->style()));

效果

圆角样式的QTreeView,选中行的色块与颜色交替行的色块四角都是圆角

相关代码

TreeViewStyle.h

#ifndef TREEVIEWSTYLE_H
#define TREEVIEWSTYLE_H

#include <QProxyStyle>

class QStyleOptionViewItem;
class TreeViewStyle : public QProxyStyle
{ 
   
    Q_OBJECT
public:
    explicit TreeViewStyle(QStyle *style = nullptr);

    void drawPrimitive(QStyle::PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w) const override;
    QPainterPath roundedPath(const QStyleOptionViewItem *opt, const QWidget *w) const;
    void drawPanelItemViewRow(const QStyleOption *opt, QPainter *p, const QWidget *w) const;
    void drawPanelItemViewItem(const QStyleOption *opt, QPainter *p, const QWidget *w) const;
};

#endif // TREEVIEWSTYLE_H

TreeViewStyle.cpp

#include "TreeViewStyle.h"

#include <QStyleOption>
#include <QPainter>
#include <DStyle> //仅用于获取部件设置的圆角大小,非Dtk用户请删除此行

TreeViewStyle::TreeViewStyle(QStyle *style) : QProxyStyle(style)
{ 
   

}

void TreeViewStyle::drawPrimitive(QStyle::PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w) const
{ 
   
    switch (pe) { 
   
    case PE_PanelItemViewRow:
        drawPanelItemViewRow(opt, p, w);
        break;
    case PE_PanelItemViewItem:
        drawPanelItemViewItem(opt, p, w);
        break;
    default:
        QProxyStyle::drawPrimitive(pe, opt, p, w);
        break;
    }
}

QPainterPath TreeViewStyle::roundedPath(const QStyleOptionViewItem *o, const QWidget *w) const
{ 
   
    int radius = Dtk::Widget::DStyle::pixelMetric(this, Dtk::Widget::DStyle::PM_FrameRadius, o, w); 
    //用于获取部件设置的圆角大小,非Dtk用户请直接设置radius的值,Dtk中默认为8
    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    QRect corner(0, 0, radius, o->rect.height());
    switch (o->viewItemPosition) { 
   
    case QStyleOptionViewItem::Beginning:
        path.addRoundedRect(o->rect, radius, radius);
        corner.moveTopRight(o->rect.topRight());
        path.addRect(corner);
        break;
    case QStyleOptionViewItem::End:
        path.addRoundedRect(o->rect, radius, radius);
        corner.moveTopLeft(o->rect.topLeft());
        path.addRect(corner);
        break;
    case QStyleOptionViewItem::OnlyOne:
        path.addRoundedRect(o->rect, radius, radius);
        break;
    case QStyleOptionViewItem::Middle:
        path.addRect(o->rect);
        break;
    case QStyleOptionViewItem::Invalid:
        break;
    }
// path.addRoundedRect(o->rect, radius, radius);
// QRect corner;
// corner.setSize({radius, radius});
// if (o->rect.right() != w->rect().right()) { 
   
// corner.moveTopRight(o->rect.topRight());
// path.addRect(corner);
// corner.moveBottomRight(o->rect.bottomRight());
// path.addRect(corner);
// }
// if (o->rect.left() != w->rect().left()) { 
   
// corner.moveTopLeft(o->rect.topLeft());
// path.addRect(corner);
// corner.moveBottomLeft(o->rect.bottomLeft());
// path.addRect(corner);
// }
    return path;
}

void TreeViewStyle::drawPanelItemViewRow(const QStyleOption *opt, QPainter *p, const QWidget *w) const
{ 
   
    p->save();
    if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) { 
   
        p->setRenderHint(QPainter::Antialiasing);
        QPainterPath path = roundedPath(vopt, w);
        QPalette::ColorGroup cg = (w ? w->isEnabled() : (vopt->state & QStyle::State_Enabled))
                                  ? QPalette::Normal : QPalette::Disabled;
        if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
            cg = QPalette::Inactive;

        if ((vopt->state & QStyle::State_Selected) &&  proxy()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, opt, w))
            p->fillRect(vopt->rect, vopt->palette.brush(cg, QPalette::Highlight));
        else if (vopt->features & QStyleOptionViewItem::Alternate)
            p->fillPath(path, vopt->palette.brush(cg, QPalette::AlternateBase));
    }
    p->restore();
}

void TreeViewStyle::drawPanelItemViewItem(const QStyleOption *opt, QPainter *p, const QWidget *w) const
{ 
   
    p->save();
    if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) { 
   
        p->setRenderHint(QPainter::Antialiasing);
        QPainterPath path = roundedPath(vopt, w);
        QPalette::ColorGroup cg = (w ? w->isEnabled() : (vopt->state & QStyle::State_Enabled))
                                  ? QPalette::Normal : QPalette::Disabled;
        if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
            cg = QPalette::Inactive;
        if (vopt->showDecorationSelected && (vopt->state & QStyle::State_Selected)) { 
   
            p->fillPath(path, vopt->palette.brush(cg, QPalette::Highlight));
        } else { 
   
            if (vopt->backgroundBrush.style() != Qt::NoBrush) { 
   
                QPointF oldBO = p->brushOrigin();
                p->setBrushOrigin(vopt->rect.topLeft());
                p->fillPath(path, vopt->backgroundBrush);
                p->setBrushOrigin(oldBO);
            }

            if (vopt->state & QStyle::State_Selected) { 
   
                QRect textRect = subElementRect(QStyle::SE_ItemViewItemText,  opt, w);
                p->fillRect(textRect, vopt->palette.brush(cg, QPalette::Highlight));
            }
        }
    }
    p->restore();
}

联系方式

QQ群:236510798

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/134345.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • mysql数据库忘记密码时如何修改(本地)「建议收藏」

    mysql数据库忘记密码时如何修改(本地)「建议收藏」mysql数据库忘记密码时如何修改(本地)

    2022年4月24日
    56
  • jquery 正则表达式验证_前端正则校验

    jquery 正则表达式验证_前端正则校验在实际的开发中,我们经常遇到的校验莫非于非空校验、数字校验、电话校验、邮箱校验,在这里我就以以上校验作例子,其他的校验网上一搜一大把。其实使用正则表达式校验是比较灵活的一种方式,首先介绍正则表达式校验。下面我直接贴代码了,有一点要注意的,就是非空校验,很多时候我们需要校验非空,是连带空格都要校验的,所以例子中的非空校验是会校验空格的。 非空:不能为空 电话号码:请输入正确的电

    2022年10月3日
    0
  • js正则表达式语法大全_vb 正则表达式

    js正则表达式语法大全_vb 正则表达式 JavaScript正则表达式的用法正则表达式是一种可以用于模式匹配和替换的强大工具,在很多语言中都可以应用。JavaScript对正则表达式提供了很好的支持,Javascript中有一个正则表达式对象RegExp。该对象提供了大量的属性和方法来处理正则表达式,同时,String对象也提供了相关的方法来处理正则表达式,在Web应用中,经常使用正则表达式来验证用户输入的信息,例如在用

    2022年9月20日
    0
  • 使用ctk库

    使用ctk库上篇文章写的如何生成一个简易ctk动态库https://blog.csdn.net/qq_16238157/article/details/86602476这篇文章写如何简易的使用交代路径下图上篇文章已经写过关于ctk动态库如何生成下面介绍一下各个文件夹:CTK文件夹:是ctk的源码ctkWork文件夹:用vs编译生成的ctk插件myCTK文件夹:是网上找的一个调用ct…

    2022年6月3日
    68
  • 基于TCP的socket编程原理概述「建议收藏」

    基于TCP的socket编程原理概述「建议收藏」解:服务器端:1)创建套接字socket;2)bind(将套接字绑定到本地地址和端口上)3)listen(将套接字设置为监听模式,准备接受连接请求)4)accept等待客户请求到来,当请求到后,接受连接请求,返回一个新的对应于此次连接的套接字5)用返回的套接字和客户端进行通信(send/receive)6)返回等待另个客户请求7)关闭套接字客户端:1)创

    2022年10月18日
    1
  • 全球ipv4地址耗尽了_ip起始地址和结束地址

    全球ipv4地址耗尽了_ip起始地址和结束地址重要消息:就在2019/11/25UTC+115:35时,一封来自欧洲RIPENCC的邮件中得到确认:全球的IPv4地址已经彻底耗尽。IPv4大家应该很熟悉了,就是我们平常所知道的IP地址,如:192.168.1.168。其实,很多年前就在说IPv4要用完了,只是没想到这天居然来得这么早,只能说互联网发展真的太快了。对于IPv4地址耗尽的问题,大家也不用担心…

    2025年5月23日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号