仿Qt原生写一个QRubberBand,以及所悟

目的

仿Qt写一个在鼠标move过程中, 会有一个矩形的Elastic Band(可以清晰的表示当前的鼠标移动过程中的所可以选中范围区域)。 那么下面将直接进入主题了。

说明

之所以写着一篇博客, 主要是来源于我发现QListView有时候会有elastic band出现, 有时候没有。而QTreeView是直接没有。查看源码发现QListView::setViewMode这个导致, 默认情况下ListMode没有, IconMode 有。

void QListView::setViewMode(ViewMode mode)
{
    Q_D(QListView);
    if (d->commonListView && d->viewMode == mode)
        return;
    d->viewMode = mode;

    delete d->commonListView;
    if (mode == ListMode) {
        d->commonListView = new QListModeViewBase(this, d);
        if (!(d->modeProperties & QListViewPrivate::Wrap))
            d->setWrapping(false);
        if (!(d->modeProperties & QListViewPrivate::Spacing))
            d->setSpacing(0);
        if (!(d->modeProperties & QListViewPrivate::GridSize))
            d->setGridSize(QSize());
        if (!(d->modeProperties & QListViewPrivate::Flow))
            d->flow = TopToBottom;
        if (!(d->modeProperties & QListViewPrivate::Movement))
            d->movement = Static;
        if (!(d->modeProperties & QListViewPrivate::ResizeMode))
            d->resizeMode = Fixed;
        if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
            d->showElasticBand = false;
    } else {
        d->commonListView = new QIconModeViewBase(this, d);
        if (!(d->modeProperties & QListViewPrivate::Wrap))
            d->setWrapping(true);
        if (!(d->modeProperties & QListViewPrivate::Spacing))
            d->setSpacing(0);
        if (!(d->modeProperties & QListViewPrivate::GridSize))
            d->setGridSize(QSize());
        if (!(d->modeProperties & QListViewPrivate::Flow))
            d->flow = LeftToRight;
        if (!(d->modeProperties & QListViewPrivate::Movement))
            d->movement = Free;
        if (!(d->modeProperties & QListViewPrivate::ResizeMode))
            d->resizeMode = Fixed;
        if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
            d->showElasticBand = true;
    }

#if QT_CONFIG(draganddrop)
    bool movable = (d->movement != Static);
    setDragEnabled(movable);
    setAcceptDrops(movable);
#endif
    d->clear();
    d->doDelayedItemsLayout();
}

核心在于

 if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
            d->showElasticBand = true;

selectionRectVisible : bool, 可以通过这setSelectionRectVisible个接口设置显隐, 其他view是没有的。

参考对应源码, 你可以仿真写一个类似的, 以QTreeWidget为基类

void FileTableWidget::mousePressEvent(QMouseEvent *event)
{
    QTreeWidget::mousePressEvent(event);
    m_press_pos = event->pos();
    //......do something
}

void FileTableWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (QLineF(event->pos(), m_press_pos).length() >= QApplication::startDragDistance())
    {
        auto buttons = event->buttons();
        if (buttons & Qt::LeftButton) {
                QRect rect(m_press_pos, event->pos());
                rect = rect.normalized();
                this->viewport()->update(rect.united(m_elasticBand)); //viewport
                m_elasticBand = rect;
                m_showElasticBand = true;
        }
    }
    //......do something
    QTreeWidget::mouseMoveEvent(event);
}

void FileTableWidget::mouseReleaseEvent(QMouseEvent *event)
{
    //......do something
    QTreeWidget::mouseReleaseEvent(event);
    if(m_showElasticBand){
        this->viewport()->update(m_elasticBand);
        m_showElasticBand = false;
        m_elasticBand = QRect();
    }
}
//核心
void FileTableWidget::paintEvent(QPaintEvent *event)
{
    QTreeWidget::paintEvent(event);
    QPainter painter(this->viewport());
    if (m_elasticBand.isValid() && m_showElasticBand) {
        QStyleOptionRubberBand opt;
        opt.initFrom(this);
        opt.shape = QRubberBand::Rectangle;
        opt.opaque = false;
        opt.rect = this->m_elasticBand.intersected(this->viewport()->rect().adjusted(-16, -16, 16, 16));
        painter.save();
        style()->drawControl(QStyle::CE_RubberBand, &opt, &painter);
        painter.restore();
    }
}

主要核心 就是通过QPainter 绘制 QRubberBand::Rectangle, QPainter 是在viewport上, 以及对move过程中矩形区域进行normalized(), 取united,获取移动过程中最大的矩形区域。 所有的矩形区域操作都是基于viewport的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

道阻且长,行则降至

无聊,打赏求刺激而已

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值