当鼠标习惯于calculation (of values for progress bars)时,我想跟踪draw in one of the two QGraphicsView
的鼠标移动。使用下面的代码,您可以在QGraphicsView
或中绘制,以获取鼠标在QGraphicsView
上的移动坐标,但不能一次绘制两个坐标。如何做到这一点?
gridLayout
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor, QPainterPath, QPen
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPathItem
from PyQt5.uic import loadUi
app = None
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
loadUi("mainwindow.ui", self)
self.showMaximized()
self.setMouseTracking(True)
self.centralWidget().setAttribute(Qt.WA_MouseTracking)
self._old_x = QCursor.pos().x()
self._old_y = QCursor.pos().y()
self.verticalLayout_top.addWidget(GraphicsView())
self.verticalLayout_bottom.addWidget(GraphicsView())
@staticmethod
def _update_bar(progress_bar, delta):
current_value = progress_bar.value()
new_value = current_value + delta
progress_bar.setValue(new_value)
def mouseMoveEvent(self, event):
new_x = event.x()
new_y = event.y()
if new_x > self._old_x:
self._update_bar(self.progressBar_x_plus, new_x - self._old_x)
if new_x < self._old_x:
self._update_bar(self.progressBar_x_minus, self._old_x - new_x)
if new_y > self._old_y:
self._update_bar(self.progressBar_y_plus, new_y - self._old_y)
if new_y < self._old_y:
self._update_bar(self.progressBar_y_minus, self._old_y - new_y)
self._old_x = new_x
self._old_y = new_y
class GraphicsView(QGraphicsView):
def __init__(self):
super().__init__()
self.start = None
self.end = None
self.setScene(QGraphicsScene())
self.path = QPainterPath()
self.item = GraphicsPathItem()
self.scene().addItem(self.item)
self.contents_rect = self.contentsRect()
self.setSceneRect(0, 0, self.contents_rect.width(), self.contents_rect.height())
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
def mousePressEvent(self, event):
self.start = self.mapToScene(event.pos())
self.path.moveTo(self.start)
def mouseMoveEvent(self, event):
self.end = self.mapToScene(event.pos())
self.path.lineTo(self.end)
self.start = self.end
self.item.setPath(self.path)
class GraphicsPathItem(QGraphicsPathItem):
def __init__(self):
super().__init__()
pen = QPen()
pen.setColor(Qt.black)
pen.setWidth(5)
self.setPen(pen)
def main():
global app
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
问题是,除了您的重写mouseMoveEvent的策略外,mousePressEvent不一定从父窗口小部件传播到子窗口小部件(行为取决于每种类型的窗口小部件,例如QLabel如果它传播鼠标事件)。如果您想听其他小部件的事件,则方法是有限的。
考虑到上述情况,一种可能的解决方案是使用eventFilter侦听任何小部件的事件,另一个改进是使用全局位置而不是局部位置,以便当鼠标从QGraphicsView更改时不受以下影响。本地坐标系。
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1003</width>
<height>703</height>
</rect>
</property>
<property name="windowTitle">
<string>Mouse Pointer</string>
</property>
<property name="locale">
<locale language="English" country="UnitedKingdom"/>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_top"/>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_x_plus">
<property name="text">
<string>X+</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QProgressBar" name="progressBar_x_plus">
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_x_minus">
<property name="text">
<string>X-</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QProgressBar" name="progressBar_x_minus">
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_y_plus">
<property name="text">
<string>Y+</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QProgressBar" name="progressBar_y_plus">
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_y_minus">
<property name="text">
<string>Y-</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QProgressBar" name="progressBar_y_minus">
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_bottom"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1003</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
更新:
class MouseListener(QObject):
posChanged = pyqtSignal(QPoint)
def __init__(self, widget):
super().__init__(widget)
self._widget = widget
self._widget.setMouseTracking(True)
self._widget.installEventFilter(self)
def eventFilter(self, obj, event):
if obj is self._widget and event.type() == QEvent.MouseMove:
self.posChanged.emit(event.globalPos())
return super().eventFilter(obj, event)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
loadUi("mainwindow.ui", self)
self.showMaximized()
self.global_pos = QCursor.pos()
for lay in (self.verticalLayout_top, self.verticalLayout_bottom):
view = GraphicsView()
listener = MouseListener(view.viewport())
listener.posChanged.connect(self.on_pos_changed)
lay.addWidget(view)
@staticmethod
def _update_bar(progress_bar, delta):
current_value = progress_bar.value()
new_value = current_value + delta
progress_bar.setValue(new_value)
def on_pos_changed(self, pos):
new_x = pos.x()
new_y = pos.y()
old_x = self.global_pos.x()
old_y = self.global_pos.y()
if new_x > old_x:
self._update_bar(self.progressBar_x_plus, new_x - old_x)
if new_x < old_x:
self._update_bar(self.progressBar_x_minus, old_x - new_x)
if new_y > old_y:
self._update_bar(self.progressBar_y_plus, new_y - old_y)
if new_y < old_y:
self._update_bar(self.progressBar_y_minus, old_y - new_y)
self.global_pos = pos