如何在 QML/Pyside2 中创建鼠标按下或单击事件而不实际按下鼠标
How to create mouse press or click events in QML/Pyside2 without actually pressing the mouse
对于我正在做的项目,我需要能够创建只有 QML 可以看到而无需物理按下鼠标的“人工”鼠标事件。
在我当前的实现中,我尝试使用“按键按下”事件来触发这些人工鼠标事件。我目前正在使用函数“Qt.createQmlObject”创建一个 MouseEvent,然后将其作为鼠标单击信号的参数。但是,我不断收到一条错误消息,提示“MouseEvent 不是一种类型”。我对不同的实现持开放态度。
import QtQuick.Controls 2.12
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.11
import QtGraphicalEffects 1.12
import QtMultimedia 5.12
import QtQml.Models 2.12
import "../components"
Item{
id: widget
width: 600
height: 600
//MouseArea
MouseArea{
id: mouseArea
anchors.fill: parent
propagateComposedEvents: true
hoverEnabled: true
onClicked: {
console.log("The mouse was clicked")
widget.focus = true
mouse.accepted = false
}
onPressed: {
console.log("The mouse was pressed")
mouse.accept = false
}
onEntered:{
widget.focus = true
}
}
//Defines key event changes
Keys.onPressed: {
if(event.key == Qt.Key_0){
var mouEvent = Qt.createQmlObject('import QtQuick 2.12; import QtQuick.Controls 2.12; MouseEvent{x: 0; y: 0; accepted: false; button: Qt.LeftButton; buttons: Qt.LeftButton; flags: 0; modifiers: Qt.NoModifier; source: Qt.MouseEventSynthesizedByApplication; wasHeld: false}', mouseArea, "error")
mouseArea.clicked(mouEvent)
}
}
}
MouseEvent 不是可以或应该创建的元素,简单来说,MouseEvent 是 QMouseEvent 的包装器,允许获取事件信息。
调用信号也不意味着事件将被传输,相反,您必须使用 Qt 事件系统,它不能从 QML 使用,而是从 C++ 使用(在您的情况下,它等同于 python) .
所以逻辑是创建一个class,将事件通知给Qt,Qt必须通过window将事件发送给item,如下所示:
from PySide2.QtCore import (
QCoreApplication,
QEvent,
QObject,
QPointF,
Qt,
QTimer,
QUrl,
Slot,
)
from PySide2.QtGui import QGuiApplication, QMouseEvent
from PySide2.QtQuick import QQuickItem, QQuickView
class MouseEmulator(QObject):
@Slot(QQuickItem, Qt.MouseButton)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF, int)
def mouseClick(self, item, button, modifier=Qt.NoModifier, pos=QPointF(), delay=-1):
self.mousePress(item, button, modifier, pos, delay)
self.mouseRelease(item, button, modifier, pos, 2 * delay)
@Slot(QQuickItem, Qt.MouseButton)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF, int)
def mousePress(self, item, button, modifier=Qt.NoModifier, pos=QPointF(), delay=-1):
self._send_mouse_events(
QEvent.MouseButtonPress, item, button, modifier, pos, delay
)
@Slot(QQuickItem, Qt.MouseButton)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF, int)
def mouseRelease(
self, item, button, modifier=Qt.NoModifier, pos=QPointF(), delay=-1
):
self._send_mouse_events(
QEvent.MouseButtonRelease, item, button, modifier, pos, delay
)
@Slot(QQuickItem, Qt.MouseButton)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF, int)
def mouseDClick(
self, item, button, modifier=Qt.NoModifier, pos=QPointF(), delay=-1
):
self.mousePress(item, button, modifier, pos, delay)
self.mouseRelease(item, button, modifier, pos, 2 * delay)
self.mousePress(item, button, modifier, pos, 3 * delay)
self._send_mouse_events(
QEvent.MouseButtonDblClick, item, button, pos, 4 * delay
)
self.mouseRelease(item, button, modifier, pos, 5 * delay)
def _send_mouse_events(self, type_, item, button, modifier, pos, delay):
window = item.window()
if pos.isNull():
pos = item.boundingRect().center()
sp = item.mapToScene(pos).toPoint()
event = QMouseEvent(
type_, pos, window.mapToGlobal(sp), button, button, modifier
)
if delay < 0:
delay = 0
def on_timeout():
QCoreApplication.instance().notify(window, event)
QTimer.singleShot(delay, on_timeout)
def main():
import os
import sys
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
app = QGuiApplication(sys.argv)
mouse_emulator = MouseEmulator()
view = QQuickView()
view.rootContext().setContextProperty("mouse_emulator", mouse_emulator)
filename = os.path.join(CURRENT_DIR, "main.qml")
view.setSource(QUrl.fromLocalFile(filename))
view.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
import QtQuick 2.12
Item{
id: widget
width: 600
height: 600
MouseArea{
id: mouseArea
anchors.fill: parent
propagateComposedEvents: true
hoverEnabled: true
onClicked: {
console.log("The mouse was clicked")
widget.focus = true
mouse.accepted = false
}
onPressed: {
console.log("The mouse was pressed")
mouse.accept = false
}
onEntered:{
widget.focus = true
}
}
Keys.onPressed: {
if(event.key == Qt.Key_0){
mouse_emulator.mouseClick(widget, Qt.LeftButton)
}
}
}
对于我正在做的项目,我需要能够创建只有 QML 可以看到而无需物理按下鼠标的“人工”鼠标事件。
在我当前的实现中,我尝试使用“按键按下”事件来触发这些人工鼠标事件。我目前正在使用函数“Qt.createQmlObject”创建一个 MouseEvent,然后将其作为鼠标单击信号的参数。但是,我不断收到一条错误消息,提示“MouseEvent 不是一种类型”。我对不同的实现持开放态度。
import QtQuick.Controls 2.12
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.11
import QtGraphicalEffects 1.12
import QtMultimedia 5.12
import QtQml.Models 2.12
import "../components"
Item{
id: widget
width: 600
height: 600
//MouseArea
MouseArea{
id: mouseArea
anchors.fill: parent
propagateComposedEvents: true
hoverEnabled: true
onClicked: {
console.log("The mouse was clicked")
widget.focus = true
mouse.accepted = false
}
onPressed: {
console.log("The mouse was pressed")
mouse.accept = false
}
onEntered:{
widget.focus = true
}
}
//Defines key event changes
Keys.onPressed: {
if(event.key == Qt.Key_0){
var mouEvent = Qt.createQmlObject('import QtQuick 2.12; import QtQuick.Controls 2.12; MouseEvent{x: 0; y: 0; accepted: false; button: Qt.LeftButton; buttons: Qt.LeftButton; flags: 0; modifiers: Qt.NoModifier; source: Qt.MouseEventSynthesizedByApplication; wasHeld: false}', mouseArea, "error")
mouseArea.clicked(mouEvent)
}
}
}
MouseEvent 不是可以或应该创建的元素,简单来说,MouseEvent 是 QMouseEvent 的包装器,允许获取事件信息。
调用信号也不意味着事件将被传输,相反,您必须使用 Qt 事件系统,它不能从 QML 使用,而是从 C++ 使用(在您的情况下,它等同于 python) .
所以逻辑是创建一个class,将事件通知给Qt,Qt必须通过window将事件发送给item,如下所示:
from PySide2.QtCore import (
QCoreApplication,
QEvent,
QObject,
QPointF,
Qt,
QTimer,
QUrl,
Slot,
)
from PySide2.QtGui import QGuiApplication, QMouseEvent
from PySide2.QtQuick import QQuickItem, QQuickView
class MouseEmulator(QObject):
@Slot(QQuickItem, Qt.MouseButton)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF, int)
def mouseClick(self, item, button, modifier=Qt.NoModifier, pos=QPointF(), delay=-1):
self.mousePress(item, button, modifier, pos, delay)
self.mouseRelease(item, button, modifier, pos, 2 * delay)
@Slot(QQuickItem, Qt.MouseButton)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF, int)
def mousePress(self, item, button, modifier=Qt.NoModifier, pos=QPointF(), delay=-1):
self._send_mouse_events(
QEvent.MouseButtonPress, item, button, modifier, pos, delay
)
@Slot(QQuickItem, Qt.MouseButton)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF, int)
def mouseRelease(
self, item, button, modifier=Qt.NoModifier, pos=QPointF(), delay=-1
):
self._send_mouse_events(
QEvent.MouseButtonRelease, item, button, modifier, pos, delay
)
@Slot(QQuickItem, Qt.MouseButton)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF)
@Slot(QQuickItem, Qt.MouseButton, Qt.KeyboardModifier, QPointF, int)
def mouseDClick(
self, item, button, modifier=Qt.NoModifier, pos=QPointF(), delay=-1
):
self.mousePress(item, button, modifier, pos, delay)
self.mouseRelease(item, button, modifier, pos, 2 * delay)
self.mousePress(item, button, modifier, pos, 3 * delay)
self._send_mouse_events(
QEvent.MouseButtonDblClick, item, button, pos, 4 * delay
)
self.mouseRelease(item, button, modifier, pos, 5 * delay)
def _send_mouse_events(self, type_, item, button, modifier, pos, delay):
window = item.window()
if pos.isNull():
pos = item.boundingRect().center()
sp = item.mapToScene(pos).toPoint()
event = QMouseEvent(
type_, pos, window.mapToGlobal(sp), button, button, modifier
)
if delay < 0:
delay = 0
def on_timeout():
QCoreApplication.instance().notify(window, event)
QTimer.singleShot(delay, on_timeout)
def main():
import os
import sys
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
app = QGuiApplication(sys.argv)
mouse_emulator = MouseEmulator()
view = QQuickView()
view.rootContext().setContextProperty("mouse_emulator", mouse_emulator)
filename = os.path.join(CURRENT_DIR, "main.qml")
view.setSource(QUrl.fromLocalFile(filename))
view.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
import QtQuick 2.12
Item{
id: widget
width: 600
height: 600
MouseArea{
id: mouseArea
anchors.fill: parent
propagateComposedEvents: true
hoverEnabled: true
onClicked: {
console.log("The mouse was clicked")
widget.focus = true
mouse.accepted = false
}
onPressed: {
console.log("The mouse was pressed")
mouse.accept = false
}
onEntered:{
widget.focus = true
}
}
Keys.onPressed: {
if(event.key == Qt.Key_0){
mouse_emulator.mouseClick(widget, Qt.LeftButton)
}
}
}