我有一个包含两个按钮的小部件,可以使用鼠标中键(拖放)交换。我试图在拖放qpushbutton时阻止鼠标光标离开qwidget区域。。。我使用的是dragmoveevent(),每次光标穿过小部件的边界时,它都会偏移光标。当您缓慢移动鼠标时,它会工作,但快速移动会使光标离开该区域。实现这一目标的最佳方式是什么?谢谢
import os
import random
import sys
import time
from PySide2 import QtOpenGL
from PySide2 import QtWidgets
from PySide2.QtCore import QEvent, QMimeData, QPoint, QRect
from PySide2.QtGui import QCursor, QDrag, QWindow
# import nuke
# import nukescripts
from collapse import Collapse
try:
from PySide import QtGui, QtCore
except ImportError:
from PySide2 import QtCore
from PySide2 import QtWidgets as QtGui
from PySide2 import QtGui as QtG
class CreateNodeBoard(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.nukePathSeparator = "/"
#self.toolPath = self.getFullPathWithExt()
self.currentDir = os.path.dirname(os.path.realpath(__file__))
################################################################################
# GUI
################################################################################
self.setMinimumWidth(350)
self.mainLayout = QtGui.QVBoxLayout()
self.mainLayout.setSpacing(0)
self.mainLayout.setAlignment(QtCore.Qt.AlignTop)
self.setLayout(self.mainLayout)
self.target = None
self.setAcceptDrops(True)
self.nodeBoardWidget = QtGui.QWidget()
self.nodeBoardWidget.setAcceptDrops(True)
nodeBoardVLayout = QtWidgets.QVBoxLayout()
self.nodeBoardWidget.setLayout(nodeBoardVLayout)
self.userButtonLayout = QtGui.QGridLayout()
nodeBoardVLayout.addLayout(self.userButtonLayout)
button1 = QtWidgets.QPushButton("a")
button2 = QtWidgets.QPushButton("b")
self.userButtonLayout.addWidget(button1)
self.userButtonLayout.addWidget(button2)
self.userButtonLayout.setAlignment(QtCore.Qt.AlignLeft)
self.mainLayout.addWidget(self.nodeBoardWidget)
def get_index(self, pos):
for i in range(self.userButtonLayout.count()):
buttonGlob = self.userButtonLayout.itemAt(i).widget().mapToGlobal(QPoint(0,0))
if QtCore.QRect(buttonGlob.x(), buttonGlob.y(), 80, 23).contains(pos) and i != self.target:
return i
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.MiddleButton:
self.target = self.get_index(QCursor.pos())
else:
self.target = None
def mouseMoveEvent(self, event):
if event.buttons() & QtCore.Qt.MiddleButton and self.target is not None:
print("moving")
drag = QDrag(self.userButtonLayout.itemAt(self.target).widget())
pix = self.userButtonLayout.itemAt(self.target).widget().grab()
mimedata = QMimeData()
mimedata.setImageData(pix)
drag.setMimeData(mimedata)
drag.setPixmap(pix)
drag.setHotSpot(QPoint(40,10))
drag.exec_()
def dragMoveEvent(self, event):
cursorPos = QCursor.pos()
widgetPos = self.nodeBoardWidget.mapToGlobal(QPoint(0,0))
if cursorPos.x() < widgetPos.x() or cursorPos.y() < widgetPos.y():
QCursor.setPos(QCursor.pos().x() + 1 , QCursor.pos().y() + 1 )
event.accept()
def dragEnterEvent(self, event):
print("drag enter event")
if event.mimeData().hasImage():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
print("drop")
buttonGlob = self.userButtonLayout.itemAt(self.target).widget().mapToGlobal(self.pos())
if not QtCore.QRect(buttonGlob.x(), buttonGlob.y(), 80, 23).contains(QCursor.pos()):
source = self.get_index(QCursor.pos())
if source is None:
return
i, j = max(self.target, source), min(self.target, source)
p1, p2 = self.userButtonLayout.getItemPosition(i), self.userButtonLayout.getItemPosition(j)
self.userButtonLayout.addItem(self.userButtonLayout.takeAt(i), *p2)
self.userButtonLayout.addItem(self.userButtonLayout.takeAt(j), *p1)
self.target = None
app = QtWidgets.QApplication(sys.argv)
# Create a Qt widget, which will be our window.
window = CreateNodeBoard()
window.show() # IMPORTANT!!!!! Windows are hidden by default.
# Start the event loop.
app.exec_()
1条答案
按热度按时间bd1hkmkf1#
前提
这个答案仅限于特定的问题(防止用户将鼠标移动到给定小部件的边界之外)。不幸的是,由于给定代码中存在许多概念性问题,这并不是一个完整的解决方案:
拖放事件应始终由实际处理它们的小部件管理(在本例中,
nodeBoardWidget
),而不是他们的父母;获取项目的布局索引应始终考虑项目几何结构(使用固定大小是令人沮丧的,因为控件大小取决于很多方面)和项目不能是小部件的事实(嵌套布局仍然是布局项目)。
layout.itemAt().widget()
可能会回来None
);基于项目索引的“交换”项目并不总是保留项目索引,因为生成的索引可能不可靠(特别是对于网格布局);
部分解
要记住的一个重要方面是,尝试移动鼠标一小部分并固定其位置是错误的,因为鼠标事件不是连续的:如果鼠标从
x=0
到x=100
并不是所有值都在0到100之间,而是中间位置的一小部分。出于同样的原因,尝试仅通过固定数量的像素“固定”位置是错误的,因为偏移量可以根据鼠标速度而变化。
上述结果
dragMoveEvent
如果鼠标在父边界外移动过快,则不会调用。虽然在您的具体案例中它“起作用”,但这只是因为您在父级中实现了该功能(如前所述,这不是建议的方法,这是一个明确的例子)。如果必须“包含”鼠标位置,则dragLeaveEvent
而必须实施。我强烈建议您研究上面的示例和注意事项,因为您的代码有许多概念性问题,如果不从头创建一个全新的示例,我的答案将无法解决这些问题。另外,很明显,您从web上的各种来源获取代码,因此我也建议您提高认识。模仿是一种很好的学习方式,但不是不了解正在做什么。研究所有使用的函数和类,研究所有相关文档,从布局管理器开始,拖放,不要忘记官方代码样式实践。