這是我的code。
在View上有兩個可移動按鈕
我可以通過拖動鼠標在View上畫線。
但我想要做的是在兩個按鈕之間畫線。
希望功能 : 如果我右鍵btn1(Test1)然後右鍵btn2(Test2),將在兩個按鈕之間建一個按鈕,然後會跟著按鈕移動而移動。
我在這個問題卡了一個多月。
懇請大家幫忙!
from PyQt5 import QtGui, QtCore
from PyQt5.QtWidgets import *
class Window(QWidget):
def __init__(self):
QWidget.__init__(self)
self.view = View(self)
self.button = QPushButton('Clear View', self)
self.button.clicked.connect(self.handleClearView)
layout = QVBoxLayout(self)
layout.addWidget(self.view)
layout.addWidget(self.button)
def handleClearView(self):
self.view.scene().clear()
class DragButton(QPushButton):
def mousePressEvent(self, event):
self.__mousePressPos = None
self.__mouseMovePos = None
if event.button() == QtCore.Qt.LeftButton:
self.__mousePressPos = event.globalPos()
self.__mouseMovePos = event.globalPos()
def mouseMoveEvent(self, event):
if event.buttons() == QtCore.Qt.LeftButton:
currPos = self.mapToGlobal(self.pos())
globalPos = event.globalPos()
diff = globalPos - self.__mouseMovePos
newPos = self.mapFromGlobal(currPos + diff)
self.move(newPos)
self.__mouseMovePos = globalPos
def mouseReleaseEvent(self, event):
if self.__mousePressPos is not None:
moved = event.globalPos() - self.__mousePressPos
if moved.manhattanLength() > 3:
event.ignore()
return
class View(QGraphicsView):
def __init__(self, parent):
QGraphicsView.__init__(self, parent)
self.setScene(QGraphicsScene(self))
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
btn1=DragButton('Test1', self)
btn2=DragButton('Test2', self)
def mousePressEvent(self, event):
self._start = event.pos()
def mouseReleaseEvent(self, event):
start = QtCore.QPointF(self.mapToScene(self._start))
end = QtCore.QPointF(self.mapToScene(event.pos()))
self.scene().addItem(
QGraphicsLineItem(QtCore.QLineF(start, end)))
for point in (start, end):
text = self.scene().addSimpleText(
'(%d, %d)' % (point.x(), point.y()))
text.setBrush(QtCore.Qt.red)
text.setPos(point)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())
嘗試在改動最小的狀態下,改到我看的懂你要的部分...
因為我實在看不懂你要啥。
from PyQt5 import QtGui, QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
class Window(QWidget):
def __init__(self):
QWidget.__init__(self)
self.view = View(self)
self.button = QPushButton('Clear View', self)
self.button.clicked.connect(self.handleClearView)
layout = QVBoxLayout(self)
layout.addWidget(self.view)
layout.addWidget(self.button)
def handleClearView(self):
self.view.scene().clear()
class DragButton(QPushButton):
def __init__(self, title, parent=None):
super().__init__(title, parent)
def mouseMoveEvent(self, e):
if e.buttons() != Qt.LeftButton:
return
mimeData = QMimeData()
drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.exec_(Qt.MoveAction)
class View(QGraphicsView):
def __init__(self, parent):
QGraphicsView.__init__(self, parent)
self.setScene(QGraphicsScene(self))
self.setAcceptDrops(True)
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
self.btn1=DragButton('Test1', self)
self.btn2=DragButton('Test2', self)
def clearScene(self):
self.scene().clear()
def dragEnterEvent(self, e):
if e.source() in [self.btn1, self.btn2]:
self.clearScene()
e.accept()
def dragMoveEvent(self, e):
e.accept()
def dropEvent(self, e):
btn = e.source()
otherBtn = self.btn2 if btn == self.btn1 else self.btn1
position = e.pos()
btn.move(position)
start = QtCore.QPointF(self.mapToScene(btn.pos()))
end = QtCore.QPointF(self.mapToScene(otherBtn.pos()))
self.scene().addItem(
QGraphicsLineItem(QtCore.QLineF(start, end)))
e.setDropAction(Qt.MoveAction)
e.accept()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())
然後你原本的code:
class DragButton(QPushButton):
def mousePressEvent(self, event):
self.__mousePressPos = None
self.__mouseMovePos = None
if event.button() == QtCore.Qt.LeftButton:
self.__mousePressPos = event.globalPos()
self.__mouseMovePos = event.globalPos()
def mouseMoveEvent(self, event):
if event.buttons() == QtCore.Qt.LeftButton:
currPos = self.mapToGlobal(self.pos())
globalPos = event.globalPos()
diff = globalPos - self.__mouseMovePos
newPos = self.mapFromGlobal(currPos + diff)
self.move(newPos)
self.__mouseMovePos = globalPos
def mouseReleaseEvent(self, event):
if self.__mousePressPos is not None:
moved = event.globalPos() - self.__mousePressPos
if moved.manhattanLength() > 3:
event.ignore()
return
這個會允許你的btn移動超出view。
class View(QGraphicsView):
def __init__(self, parent):
QGraphicsView.__init__(self, parent)
self.setScene(QGraphicsScene(self))
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
btn1=DragButton('Test1', self)
btn2=DragButton('Test2', self)
def mousePressEvent(self, event):
self._start = event.pos()
def mouseReleaseEvent(self, event):
start = QtCore.QPointF(self.mapToScene(self._start))
end = QtCore.QPointF(self.mapToScene(event.pos()))
self.scene().addItem(
QGraphicsLineItem(QtCore.QLineF(start, end)))
for point in (start, end):
text = self.scene().addSimpleText(
'(%d, %d)' % (point.x(), point.y()))
text.setBrush(QtCore.Qt.red)
text.setPos(point)
重寫View的mousePressEvent和mouseReleaseEvent幹嘛?
你點到DragButton上,事件不會傳遞到View上,和HTML的冒泡機制不同,所以你拖曳DragButton並不會觸發View上的mousePressEvent,放開也不會觸發mouseReleaseEvent。
簡單的說就是不會依你所想的,按鈕移動由DragButton控制,畫線由View上的滑鼠座標控制。
實際上也不應該這樣,因為你滑鼠點擊時不一定會點到按鈕的同一位置,所以端點位置會不同。
應該由按鈕上做為標準的某點決定你線的端點。