如何将 Qt 鼠标事件转发到 QQuickView?

Posted

技术标签:

【中文标题】如何将 Qt 鼠标事件转发到 QQuickView?【英文标题】:How to forward Qt Mouse event to QQuickView? 【发布时间】:2018-10-19 06:46:17 【问题描述】:

在我的QMainWindow 中,我有一个QFrame 和一个QWidget,它们包装了一个QQuickView 并通过qml 文件显示用户界面。

我正在尝试实现拖放功能,在QFrame 中按下鼠标并移动鼠标时,缩略图会一直跟随光标的位置,直到鼠标释放。鼠标释放将在QQuickView 内进行。

QQuickView 中的悬停事件没有问题,我可以成功获取悬停事件。当在QFrame 中按下鼠标然后将鼠标移动到QQuickView 时,就会出现问题,我无法在QQuickView 中获得任何鼠标事件。

左边是QFrame,右边是QQuickView

单独悬停在QQuickView

QFrame 中按下鼠标并在QQuickView 中移动鼠标:

任何鼠标事件都只能在鼠标释放后捕获。

这些是我目前所写的:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QFrame, QLabel, QGridLayout, QVBoxLayout
from PyQt5.QtCore import Qt, QMimeData, QUrl
from PyQt5.QtGui import QDrag, QPixmap
from PyQt5.QtQuick import QQuickView

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.centralWidget = QWidget(self)

        gridlayout = QGridLayout(self.centralWidget)
        gridlayout.setContentsMargins(0,0,0,0)
        gridlayout.setHorizontalSpacing(0)
        gridlayout.setVerticalSpacing(0)

        self.setCentralWidget(self.centralWidget)
        self.leftPanel = QVBoxLayout()
        self.rightPanel = QVBoxLayout()

        gridlayout.addLayout(self.leftPanel, 0, 0, 1, 1)
        gridlayout.addLayout(self.rightPanel, 0, 1, 1, 1)
        gridlayout.setSpacing(0)

        self.setStyleSheet("background:grey")
        self.resize(300, 200)
        self.show()

class Left(QFrame):
    def __init__(self):
        super().__init__()
        self.resize(500, 500)
        self.label = QLabel(self)
        self.label.resize(50, 50)

    def mouseMoveEvent(self, e):
        mimeData = QMimeData()
        drag = QDrag(self)
        self.thumbnail = QPixmap('./test.png').scaled(50, 50, Qt.KeepAspectRatio)
        drag.setPixmap(self.thumbnail)
        drag.setMimeData(mimeData)
        drag.exec_(Qt.MoveAction)

class Right(QQuickView):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.rootContext().setContextProperty('Right', self)
        self.setSource(QUrl('./drag.qml'))
        self.setMinimumHeight(200)
        self.setMinimumWidth(150)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = MainWindow()
    main_window.leftPanel.addWidget(Left())
    main_window.rightPanel.addWidget(QWidget.createWindowContainer(Right()))
    app.exec_()

根据我从不同来源和Qt 文档中阅读的内容,我想我必须将事件从QFrame 转发到QQuickView,否则似乎存在某种形式的全局鼠标事件处理。

我该如何实现这一目标?

【问题讨论】:

【参考方案1】:

原来我使用了错误的 qml 元素。 DropArea 应该在qml 中使用。

import QtQuick 2.7

Rectangle 

    id: root

    anchors.fill: parent
    color: 'transparent'

    Column 
        anchors.centerIn: parent
        Rectangle 
            width: 50
            height: 50
            color: 'red'
            anchors.horizontalCenter: parent.horizontalCenter
            DropArea 
                anchors.fill: parent
                onEntered: parent.color = 'blue'
                onExited: parent.color = 'red'
                onDropped: console.log('triggger this thing yo')
            
        
        Text 
            width: parent.parent.width
            text: 'on hover over box, color changes from red to blue and vice versa when hover out'
            wrapMode: Text.Wrap
            horizontalAlignment: Text.AlignHCenter
        
    

希望这将能够帮助某人在路上。感谢raven-worx Qt Forum 的解决方案。

【讨论】:

以上是关于如何将 Qt 鼠标事件转发到 QQuickView?的主要内容,如果未能解决你的问题,请参考以下文章

将 QML(QQuickView) 添加到现有 UI

退出时删除 QQuickView 会导致 Qt 应用程序冻结

在 Qt5.3(mingw32) 中删除 QQuickView 的内存管理问题

Qt 中的事件是如何工作的?

在 QT 中为图像标签创建鼠标事件

带有 QQuickView 的 QML 信号 QT 插槽