自定义QGraphicsItem选中样式-阿里云开发者社区

开发者社区> 潘志闻> 正文

自定义QGraphicsItem选中样式

简介: 简述 在 Scene 中添加 QGraphicsItem 后,当选中该 item 时,会看到边缘区域出现虚线,感觉不太美观。下面,我们来讲解如何去掉虚线并自定义选中样式。 简述 默认样式 虚线的由来 去掉虚线 自定义选中样式 默认样式 以椭圆为例,其它如:矩形、多边形等 item 类似。 // 构建一个椭圆 QGraphicsEllipseItem
+关注继续查看

简述

在 Scene 中添加 QGraphicsItem 后,当选中该 item 时,会看到边缘区域出现虚线,感觉不太美观。下面,我们来讲解如何去掉虚线并自定义选中样式。

默认样式

以椭圆为例,其它如:矩形、多边形等 item 类似。

// 构建一个椭圆
QGraphicsEllipseItem *pItem = new QGraphicsEllipseItem();
// 设置可选中、可移动
pItem->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);

// 设置样式(画笔 - 边框色 画刷 - 背景色)
QPen pen = pItem->pen();
pen.setWidth(2);
pen.setColor(QColor(0, 160, 230));
pItem->setPen(pen);
pItem->setBrush(QColor(247, 160, 57));
// ......

要出现选中效果,需要为 item 设置选中标识 QGraphicsItem::ItemIsSelectable。设置之后,选中 item,默认样式如下:

这里写图片描述

边框区域出现虚线部分,下面我们来逐步分析。

虚线的由来

要知道虚线是怎么来的,最好的办法就是看源码。还是那句话 - 源码面前,了无秘密!

void QGraphicsPathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                              QWidget *widget)
{
    Q_D(QGraphicsPathItem);
    Q_UNUSED(widget);
    painter->setPen(d->pen);
    painter->setBrush(d->brush);
    painter->drawPath(d->path);

    if (option->state & QStyle::State_Selected)
        qt_graphicsItem_highlightSelected(this, painter, option);
}

前半部分正是椭圆的样式,虚线部分主要是后半部分 qt_graphicsItem_highlightSelected() 所实现的内容,进去看看吧!

static void qt_graphicsItem_highlightSelected(
    QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option)
{
    const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1));
    if (qFuzzyIsNull(qMax(murect.width(), murect.height())))
        return;

    const QRectF mbrect = painter->transform().mapRect(item->boundingRect());
    if (qMin(mbrect.width(), mbrect.height()) < qreal(1.0))
        return;

    qreal itemPenWidth;
    switch (item->type()) {
        case QGraphicsEllipseItem::Type:
            itemPenWidth = static_cast<QGraphicsEllipseItem *>(item)->pen().widthF();
            break;
        case QGraphicsPathItem::Type:
            itemPenWidth = static_cast<QGraphicsPathItem *>(item)->pen().widthF();
            break;
        case QGraphicsPolygonItem::Type:
            itemPenWidth = static_cast<QGraphicsPolygonItem *>(item)->pen().widthF();
            break;
        case QGraphicsRectItem::Type:
            itemPenWidth = static_cast<QGraphicsRectItem *>(item)->pen().widthF();
            break;
        case QGraphicsSimpleTextItem::Type:
            itemPenWidth = static_cast<QGraphicsSimpleTextItem *>(item)->pen().widthF();
            break;
        case QGraphicsLineItem::Type:
            itemPenWidth = static_cast<QGraphicsLineItem *>(item)->pen().widthF();
            break;
        default:
            itemPenWidth = 1.0;
    }
    const qreal pad = itemPenWidth / 2;

    const qreal penWidth = 0; // cosmetic pen

    const QColor fgcolor = option->palette.windowText().color();
    const QColor bgcolor( // ensure good contrast against fgcolor
        fgcolor.red()   > 127 ? 0 : 255,
        fgcolor.green() > 127 ? 0 : 255,
        fgcolor.blue()  > 127 ? 0 : 255);

    painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine));
    painter->setBrush(Qt::NoBrush);
    painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));

    painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine));
    painter->setBrush(Qt::NoBrush);
    painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
}

来看最主要的部分:先使用颜色为 bgcolor 的画笔绘制实线,再使用窗体文本的颜色绘制虚线,而绘制的区域则是 boundingRect() 边界区域的各个方向分别向外扩展 pad 像素。

去掉虚线

既然知道了原理,那么去掉虚线就变得很容易。

这里写图片描述

class CustomItem : public QGraphicsEllipseItem
{
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) Q_DECL_OVERRIDE {
        QStyleOptionGraphicsItem op;
        op.initFrom(widget);

        // 判断选中时,设置状态为 State_None
        if (option->state & QStyle::State_Selected)
            op.state = QStyle::State_None;

        // 调用默认方法,进行原始绘制
        QGraphicsEllipseItem::paint(painter, &op, widget);
    }
};

自定义选中样式

去掉虚线后,选中时没有样式也不行,那就随便添加一个自定义样式吧,根据源码修改。

这里写图片描述

class CustomItem : public QGraphicsEllipseItem
{
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) Q_DECL_OVERRIDE {
        QStyleOptionGraphicsItem op;
        op.initFrom(widget);

        // 判断选中时,设置状态为 State_None
        if (option->state & QStyle::State_Selected)
            op.state = QStyle::State_None; ;

        // 调用默认方法,进行原始绘制
        QGraphicsEllipseItem::paint(painter, &op, widget);

        // 选中时绘制
        if (option->state & QStyle::State_Selected) {
            qreal itemPenWidth = pen().widthF();
            const qreal pad = itemPenWidth / 2;
            const qreal penWidth = 0;

            // 边框区域颜色
            QColor color = QColor(Qt::yellow);

            // 绘制实线
            painter->setPen(QPen(color, penWidth, Qt::SolidLine));
            painter->setBrush(Qt::NoBrush);
            painter->drawRect(boundingRect().adjusted(pad, pad, -pad, -pad));

            // 绘制虚线
            painter->setPen(QPen(color, 0, Qt::DashLine));
            painter->setBrush(Qt::NoBrush);
            painter->drawRect(boundingRect().adjusted(pad, pad, -pad, -pad));
        }
    }
};

这时,我们实现了一个选中时边框区域为黄色的虚线框(其他样式,同理)。很简单吧,所以呢,没事多瞅瞅源码吧O(∩_∩)O~!

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10093 0
自定义博客样式
自定义博客样式 用了一天时间简单的更改了下博客的样式,前端技术不甚了解,暂且粗制至此。 有一些问题没解决,还有些功能没实现。 模板使用博客园的官方模板:En_summerGarden。基于此模板进行自定义。
880 0
自定义QGraphicsItem选中样式
简述 在 Scene 中添加 QGraphicsItem 后,当选中该 item 时,会看到边缘区域出现虚线,感觉不太美观。下面,我们来讲解如何去掉虚线并自定义选中样式。 简述 默认样式 虚线的由来 去掉虚线 自定义选中样式 默认样式 以椭圆为例,其它如:矩形、多边形等 item 类似。 // 构建一个椭圆 QGraphicsEllipseItem
3395 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13893 0
Qt-网易云音乐界面实现-7 消息中心实现,主要是QListWidget 自定义Item 和QTabwidget使用
最近写的有点烦躁, 感觉内容真的很多!很多!很多。 目前真的想知道网易官方在出这款产品是,用了多少人和多长时间。
11 0
WPF界面设计技巧(4)—自定义列表项样式
原文:WPF界面设计技巧(4)—自定义列表项样式   有前面修改按钮样式的基础,我们可以尝试来定制一个即好看又好用的 ListBox ,今天先来讲“好看”部分。   打开 Microsoft Visual Studio 2008 ,建立一个WPF应用程序,调整窗体大小,在窗体内创建一个 ListBox 和一个 Button ,按下图所示布局。
776 0
+关注
潘志闻
互联网挖掘者
290
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载