Closed SineStriker closed 1 year ago
我确实一直想改进这个地方,非常感谢你的帮助!
我已经参考你的代码修改了FramelessHelper的做法,现在确实不需要手动实现那几个接口了,都是用Qt自己的事件驱动。你有时间的话能拿最新代码测试一下吗?
我去试试
我是5.15.2,QHoverEvent不支持5个参数的构造函数,另外QEnterEvent是在Qt5里就引入了。已经提交了一个PR,但是还有一个问题,就是鼠标按下按钮然后在外面放开的话,虽然点击事件没有触发,但是hover状态并不会解除。
输出了一下每次emulateQtMouseEvent的参数,觉得现在这样是有问题的,因为每次Hover/Press/Release会发送好几个Normal,没看过细节不知道这是为什么。
但是还有一个问题,就是鼠标按下按钮然后在外面放开的话,虽然点击事件没有触发,但是hover状态并不会解除。
这个我也发现了,正想办法解决。不过暂时不知道为什么会这样
每次Hover/Press/Release会发送好几个Normal
Normal不会发给正在被hover或者press的按钮的,应该没什么问题。你看到的应该是我发给其他按钮的normal
每次Hover/Press/Release会发送好几个Normal
Normal不会发给正在被hover或者press的按钮的,应该没什么问题。你看到的应该是我发给其他按钮的normal
你说得对,我发现了,那我试试看能不能解决这个问题。
我明白了,是因为鼠标在外部松开的时候不会发送 Release 事件,而 press 状态的解除必须发送 Release 事件。在 QAbstractButton::mouseReleaseEvent 的处理中,如果鼠标不在按钮内那么是不会触发 clicked 的。另外,MouseMove事件不应该在 Hover 状态下一直发送,应当判断是否设置了mouseTracking(由于 utils.cpp 没有链接 QtWidgets 只能读取 QProperty),如果没有设,那么只能在 Pressed 的时候才发送 MouseMove。
正常的控件是这样的: 鼠标移入,变成 hover;鼠标按下,变成 pressed;按下后鼠标移到外部,变成 hover;不松开鼠标再移回,变成 pressed。在鼠标放开之前,是不会变回 normal 的。但要完成这个功能,估计得在框架内标记控件的状态了。
感谢你的深入研究!不过Qt内部应该有记录控件状态的系统吧,我们能否通过Qt的私有接口对接进去?如果我们自己实现一套,感觉可能会与Qt自身失去同步。
我还有一点疑惑,就是我们模拟的鼠标事件究竟应该发给谁,是控件本身,还是其顶层窗口?我试验了几次,好像发给控件和窗口都有不同的效果。
鼠标在外部松开的时候不会发送 Release 事件,而 press 状态的解除必须发送 Release 事件。在 QAbstractButton::mouseReleaseEvent 的处理中,如果鼠标不在按钮内那么是不会触发 clicked 的
明白了,我想办法额外发送一次release事件就可以了
MouseMove事件不应该在 Hover 状态下一直发送,应当判断是否设置了mouseTracking(由于 utils.cpp 没有链接 QtWidgets 只能读取 QProperty),如果没有设,那么只能在 Pressed 的时候才发送 MouseMove。
明白了,非常感谢。我去修改。
我还有一点疑惑,就是我们模拟的鼠标事件究竟应该发给谁,是控件本身,还是其顶层窗口?我试验了几次,好像发给控件和窗口都有不同的效果。
鼠标事件的话,MousePress和MouseRelease建议是都发送给QWindow,因为我上面提过有个隐式 grab 的指针 qt_button_down,这个东西就是 Qt 自己记录状态的数据结构之一,在控件外部放开鼠标等价于一个不明目标的 MouseRelease 产生出来,QApplication就会把它分发给 qt_button_down,这个指针我们也可以用(但是需要链接 QtWidgets,你看怎么方便怎么处理,但是对 QtQuick 可能会有点影响)。其他鼠标事件直接发送到 widget 就行了,但是我没用过QtQuick...所以这里面就不了解了。
我又尝试了很多做法,有以下发现:
(1) 发送release事件必定会触发click信号,不管鼠标在哪里 (2) 对于QWidget,如果把hover事件发给QWindow,则无法触发QWidget自己的事件,只有把事件发给具体的QWidget才行,而QtQuick则正好相反。
感觉一定要设一个 setHovered、setPressed、clicked 信号有以下缺点:
我现在是这么做的。
setHovered 和 setPressed 的处理可以参考这样的做法,clicked 可以直接不要(因为 QAbstractButton 在 mouseReleaseEvent 中会发出这个信号)。
其他可以参考的点:
extern Q_WIDGETS_EXPORT QWidget *qt_button_down;
,是一个导出的符号,因此我们是可以使用的。它在 qwidgetwindow.cpp 与 qwidget.cpp 中都被引用了,其中 QWidgetWindow::handleMouseEvent 会对这个值进行更新,因此为了与Qt框架更好地 integrate,建议是在 setPressed 的处理中将鼠标点击和释放事件发送给 QWindow,并监视这个指针。(我上面为了方便就直接把事件发送给 widget 自己了,但是在 framelesshelper 框架中是没法拿到 QAbstractButton::isDown() 的,因为 widget 不一定是个按钮,所以推荐使用 qt_button_down)