我修改了像素圖專案的繪制方法,因此它始終按小部件高度的百分比進行縮放,并以放置它的位置的 x 坐標為中心。
但是,結果項在被單擊時無法正確檢測。
在我的示例中,roi1 下方的大部磁區域報告“讓我”,而我找不到任何報告讓我了解 roi2 的地方。
import pyqtgraph as pg
from PyQt5 import QtWidgets, QtGui, QtCore
import numpy as np
from PyQt5.QtCore import Qt
import logging
class ScaleInvariantIconItem(QtWidgets.QGraphicsPixmapItem):
def __init__(self,*args, **kwargs):
self.id = kwargs.pop("id", "dummy")
self.count =0
super().__init__(*args, **kwargs)
self.setPixmap(QtWidgets.QLabel().style().standardPixmap(QtWidgets.QStyle.SP_FileDialogStart))
self.scale_percent = .25
self._pen = None
def setPen(self, pen):
self._pen=pen
self.update()
def mousePressEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
print("got me", self.id, self.count)
self.count = 1
def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionGraphicsItem', widget: QtWidgets.QWidget):
h_scene = self.scene().parent().height()
h = self.pixmap().height()
t = painter.transform();
s = (self.scale_percent*h_scene)/h
self.setTransformOriginPoint(self.pixmap().width()/2,0)
painter.save()
painter.setTransform(QtGui.QTransform(s, t.m12(), t.m13(),
t.m21(), s, t.m23(),
t.m31(), t.m32(), t.m33()))
painter.translate(-self.pixmap().width() / 2, 0)
super().paint(painter, option, widget)
if self._pen:
painter.setPen(self._pen)
painter.drawRect(self.pixmap().rect())
painter.restore()
app = QtWidgets.QApplication([])
pg.setConfigOption('leftButtonPan', False)
g = pg.PlotWidget()
#g = pg.PlotWidget()
QtWidgets.QGraphicsRectItem
roi = ScaleInvariantIconItem(id=1)
roi2 = ScaleInvariantIconItem(id=2)
roi2.setPos(10,20)
roi2.setPen(pg.mkPen('g'))
vb = g.plotItem.getViewBox()
vb.setXRange(-20,20)
vb.setYRange(-20,20)
g.addItem(roi)
#g.addItem(roi2)
g.addItem(roi2)
g.show()
app.exec_()
uj5u.com熱心網友回復:
更改專案的繪制方式不會更改其幾何形狀(“邊界矩形”)。
事實上,你很“幸運”,由于 pyqtgraph 的行為方式,你沒有得到繪圖工件,因為你實際上是在像素圖專案的邊界矩形之外繪圖。根據以下檔案
從上圖可以看出,專案的實際矩形與您正在繪制的矩形非常不同,如果您單擊新矩形,您將正確獲得相關的滑鼠事件。
現在,問題是 pyqtgraph 使用復雜的 QGraphicsItems 系統來顯示其內容,并使用其轉換和相對坐標系addItem實際將專案添加到其內部plotItem。
如果您不需要與其他專案的直接關系和互動,并且您可以固定位置,那么可能是子類化PlotWidget(這是 QGraphicsView 子類本身),并執行以下操作:
- 覆寫和覆寫
addItem(由 PlotWidget 覆寫并包裝到底層 PlotItem 物件方法),以便您可以向場景中添加“可擴展”專案,而不是將它們添加到 PlotItem;為此,您還需要為可縮放專案創建對繪圖專案的參考; - 向您的專案添加一個函式,該函式根據實際視圖大小(而不是視圖框!)縮放自身,并根據視圖框范圍定位自身;
- 覆寫
setPos您的專案以保持對基于視圖框的位置的參考,而不是場景的位置; - 在 PlotItem 上安裝事件過濾器以獲取調整大小事件并最終重新縮放/重新定位專案;
- 連接到
sigRangeChanged所述PlotItem的信號到計時器實際呼叫上述功能(這具有被延遲,由于該事件佇列,如即時呼叫會導致不可靠的結果);
這是上述的一個可能的實作:
class ScaleInvariantIconItem(QtWidgets.QGraphicsPixmapItem):
_pos = None
_pen = None
def __init__(self,*args, **kwargs):
self.id = kwargs.pop("id", "dummy")
self.count = 0
super().__init__(*args, **kwargs)
self.basePixmap = QtWidgets.QApplication.style().standardPixmap(
QtWidgets.QStyle.SP_FileDialogStart)
self.setPixmap(self.basePixmap)
self.scale_percent = .25
def setPos(self, *args):
if len(args) == 1:
self._pos = args[0]
else:
self._pos = QtCore.QPointF(*args)
def relativeResize(self, size):
newPixmap = self.basePixmap.scaled(
size * self.scale_percent, QtCore.Qt.KeepAspectRatio)
self.setPixmap(newPixmap)
pos = self.plotItem.getViewBox().mapViewToScene(self._pos or QtCore.QPointF())
super().setPos(pos - QtCore.QPointF(newPixmap.width() / 2, 0))
def setPen(self, pen):
self._pen = pen
self.update()
def mousePressEvent(self, event: 'QGraphicsSceneMouseEvent') -> None:
print("got me", self.id, self.count)
self.count = 1
def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionGraphicsItem', widget: QtWidgets.QWidget):
super().paint(painter, option, widget)
if self._pen:
painter.setPen(self._pen)
painter.drawRect(self.pixmap().rect())
class PlotWidget(pg.PlotWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.scalableItems = []
self.plotItemAddItem, self.addItem = self.addItem, self._addItem
self.plotItem.installEventFilter(self)
self.delayTimer = QtCore.QTimer(
interval=0, timeout=self.updateScalableItems, singleShot=True)
self.plotItem.sigRangeChanged.connect(self.delayTimer.start)
def updateScalableItems(self):
size = self.size()
for item in self.scalableItems:
item.relativeResize(size)
def eventFilter(self, obj, event):
if event.type() == QtWidgets.QGraphicsSceneResizeEvent:
self.updateScalableItems()
return super().eventFilter(obj, event)
def _addItem(self, item):
if isinstance(item, ScaleInvariantIconItem):
item.plotItem = self.plotItem
self.scalableItems.append(item)
self.scene().addItem(item)
else:
self.plotItemAddItem(item)
def resizeEvent(self, event):
super().resizeEvent(event)
if event:
# pyqtgraph calls resizeEvent with a None arguments during
# initialization, we should ignore it
self.updateScalableItems()
# ...
# use the custom subclass
g = PlotWidget()
# ...
注意:
- 這只在您只有一個視圖時才有效;雖然這通常不是 pyqtgraph 的問題,但實際上 QGraphicsScene 可以在多個 QGraphicsViews 中同時顯示,就像專案視圖中的專案模型一樣;
- 要獲得默認樣式,不要創建新的 QWidget 實體,只需訪問 QApplication
style(); - 空格對于代碼可讀性非常重要(這通常比其他東西更重要,比如打字);閱讀更多關于Python 代碼官方樣式指南(又名 PEP-8);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/382092.html
標籤:Python qt pyqt5 pyqtgraph qgraphicsitem
