QTableView鼠标双击先触发单击信号

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

最近开发一个项目遇到了一个问题,QTableView同时绑定doubleClicked和clicked信号,结果发现鼠标左键双击必然先触发一次单击信号,鼠标右键双击就不会触发单击信号。我的需求是同时绑定单击和双击信号,结果某些场景下同时触发信号,我该怎么办呢?

这个问题我终于在源代码里找到了答案。


一、QAbstractItemView

QTableView继承这个类,它的单击和双击信号就是从这个类触发的。

单击:鼠标抬起事件

cpp 复制代码
void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
{
    Q_D(QAbstractItemView);

    QPoint pos = event->pos();
    QPersistentModelIndex index = indexAt(pos);

    if (state() == EditingState) {
        if (d->isIndexValid(index)
            && d->isIndexEnabled(index)
            && d->sendDelegateEvent(index, event))
            update(index);
        return;
    }

    bool click = (index == d->pressedIndex && index.isValid());
    bool selectedClicked = click && (event->button() == Qt::LeftButton) && d->pressedAlreadySelected;
    EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
    const bool edited = click ? edit(index, trigger, event) : false;

    d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;

    if (d->selectionModel && d->noSelectionOnMousePress) {
        d->noSelectionOnMousePress = false;
        d->selectionModel->select(index, selectionCommand(index, event));
    }

    setState(NoState);

    if (click) {
        if (event->button() == Qt::LeftButton)
            emit clicked(index);
        if (edited)
            return;
        QStyleOptionViewItem option = d->viewOptionsV1();
        if (d->pressedAlreadySelected)
            option.state |= QStyle::State_Selected;
        if ((d->model->flags(index) & Qt::ItemIsEnabled)
            && style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
            emit activated(index);
    }
}

重点是下面这几句:

cpp 复制代码
    if (click) {
        if (event->button() == Qt::LeftButton)
            emit clicked(index);

先不用管它做了什么判断,我简略说下:只有index有效才会触发单击信号;换言之,index无效不会触发这个信号。而且必须是鼠标左键点击才行!

可以明显看到,clicked总是在doubleClicked之前触发。也就是第一次鼠标抬起的时候触发,那个时候还没触发双击信号。

双击信号:双击事件触发时

cpp 复制代码
void QAbstractItemView::mouseDoubleClickEvent(QMouseEvent *event)
{
    Q_D(QAbstractItemView);

    QModelIndex index = indexAt(event->pos());
    if (!index.isValid()
        || !d->isIndexEnabled(index)
        || (d->pressedIndex != index)) {
        QMouseEvent me(QEvent::MouseButtonPress,
                       event->localPos(), event->windowPos(), event->screenPos(),
                       event->button(), event->buttons(), event->modifiers(), event->source());
        mousePressEvent(&me);
        return;
    }
    // signal handlers may change the model
    QPersistentModelIndex persistent = index;
    emit doubleClicked(persistent);
    if ((event->button() == Qt::LeftButton) && !edit(persistent, DoubleClicked, event)
        && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this))
        emit activated(persistent);
    d->pressedIndex = QModelIndex();
}

重点是下面这几句:

cpp 复制代码
emit doubleClicked(persistent);

鼠标双击事件由底层系统触发,鼠标左键和右键均可以触发。

由此,我们看到当你用鼠标左键单击的时候总会发送一个单击信号+一个双击信号,而且单击信号一定在双击信号前面。

二、解决问题

其实没有什么问题需要解决,本来就可以同时绑定单击和双击信号。严格来说只要你的单击信号和双击信号没有重叠的业务逻辑,你就可以无视这个问题。但是,有时候偏偏出现我只要双击不要单击的场景怎么办呢?

办法还是有的,先看下面的函数:

cpp 复制代码
int doubleClickInterval = QApplication::doubleClickInterval();  // 单位:毫秒

其实是有双击触发间隔的,意思就是只要两次单击在这个时间间隔内就可以触发双击信号,要不然就触发两次单击。这个值在Windows上默认是500ms,在Mac/Linux上默认是400ms,我们暂时不考虑更改这个值,但这个值对我们有用。

解决思路也不难,触发单击的时候等待这个时间间隔,如果间隔内触发了双击就拦截单击信号,否则放行。

cpp 复制代码
// 推荐做法:使用系统间隔
connect(&m_timer, &QTimer::timeout, this, &MyClass::handleSingleClick);
m_timer.setSingleShot(true);
m_timer.start(QApplication::doubleClickInterval());  // 关键点

总结

1、如果你遇到了非解决不可的场景可以考虑我的方法,如果你对这个场景无所谓就无需关心。

相关推荐
吾当每日三饮五升21 小时前
RapidJSON 自定义内存分配器详解与实战
c++·后端·性能优化·json
小欣加油1 天前
leetcode 129 求根节点到叶节点数字之和
数据结构·c++·算法·leetcode
O_o3811 天前
QT多窗口跳转
开发语言·qt
徽先生1 天前
vscode中编写c++程序
c++·ide·vscode
大橘1 天前
【qml-10】Quick3D实现机器人渲染(mesh)记录
qt·机器人·qml
铭哥的编程日记1 天前
C++优选算法精选100道编程题(附有图解和源码)
开发语言·c++·算法
深思慎考1 天前
LinuxC++项目开发日志——基于正倒排索引的boost搜索引擎(2——Parser解析html模块)
linux·c++·搜索引擎
-Aerolite-1 天前
【C/C++】C/C++状态机实现方法
c语言·c++
轩情吖1 天前
Qt常用控件之QLabel(一)
开发语言·数据库·c++·qt·小程序·qlabel·桌面开发
m0_552200821 天前
《UE5_C++多人TPS完整教程》学习笔记58 ——《P58 旋转奔跑动画(Rotate Running Animations)》
c++·游戏·ue5