【发布时间】:2021-08-24 19:28:16
【问题描述】:
我有一个来自 PySide6 的Callout example 的QChart。现在我已经为我的项目重写了一些代码,但是当我将鼠标悬停在“QLineSeries”上时,标注看起来比我实际指向的位置更高或更低。
这是一些代码:
Callout 类(几乎与example 中的相同)
class Callout(QGraphicsItem):
def __init__(self, chart):
QGraphicsItem.__init__(self, chart)
self.chart = chart
self._text = ""
self._textRect = QRectF()
self._anchor = QPointF()
self._font = QFont()
self._rect = QRectF()
def boundingRect(self):
anchor = self.mapFromParent(self.chart.mapToPosition(self._anchor))
rect = QRectF()
rect.setLeft(min(self._rect.left(), anchor.x()))
rect.setRight(max(self._rect.right(), anchor.x()))
rect.setTop(min(self._rect.top(), anchor.y()))
rect.setBottom(max(self._rect.bottom(), anchor.y()))
return rect
def paint(self, painter, option, widget):
path = QPainterPath()
path.addRoundedRect(self._rect, 5, 5)
anchor = self.mapFromParent(self.chart.mapToPosition(self._anchor))
if not self._rect.contains(anchor) and not self._anchor.isNull():
point1 = QPointF()
point2 = QPointF()
# establish the position of the anchor point in relation to _rect
above = anchor.y() <= self._rect.top()
above_center = (anchor.y() > self._rect.top() and
anchor.y() <= self._rect.center().y())
below_center = (anchor.y() > self._rect.center().y() and
anchor.y() <= self._rect.bottom())
below = anchor.y() > self._rect.bottom()
on_left = anchor.x() <= self._rect.left()
left_of_center = (anchor.x() > self._rect.left() and
anchor.x() <= self._rect.center().x())
right_of_center = (anchor.x() > self._rect.center().x() and
anchor.x() <= self._rect.right())
on_right = anchor.x() > self._rect.right()
# get the nearest _rect corner.
x = (on_right + right_of_center) * self._rect.width()
y = (below + below_center) * self._rect.height()
corner_case = ((above and on_left) or (above and on_right) or
(below and on_left) or (below and on_right))
vertical = abs(anchor.x() - x) > abs(anchor.y() - y)
x1 = (x + left_of_center * 10 - right_of_center * 20 + corner_case *
int(not vertical) * (on_left * 10 - on_right * 20))
y1 = (y + above_center * 10 - below_center * 20 + corner_case *
vertical * (above * 10 - below * 20))
point1.setX(x1)
point1.setY(y1)
x2 = (x + left_of_center * 20 - right_of_center * 10 + corner_case *
int(not vertical) * (on_left * 20 - on_right * 10))
y2 = (y + above_center * 20 - below_center * 10 + corner_case *
vertical * (above * 20 - below * 10))
point2.setX(x2)
point2.setY(y2)
path.moveTo(point1)
path.lineTo(anchor)
path.lineTo(point2)
path = path.simplified()
painter.setBrush(QColor(255, 255, 255))
painter.drawPath(path)
painter.drawText(self._textRect, self._text)
def mousePressEvent(self, event):
if event.button() == Qt.RightButton:
self.removecallout()
event.setAccepted(True)
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
self.setPos(self.mapToParent(
event.pos() - event.buttonDownPos(Qt.LeftButton)))
event.setAccepted(True)
else:
event.setAccepted(False)
def set_text(self, text):
self._text = text
metrics = QFontMetrics(self._font)
self._textRect = QRectF(metrics.boundingRect(
QRect(0.0, 0.0, 150.0, 150.0), Qt.AlignLeft, self._text))
self._textRect.translate(5, 5)
self.prepareGeometryChange()
self._rect = self._textRect.adjusted(-5, -5, 5, 5)
def set_anchor(self, point):
self._anchor = QPointF(point)
def update_geometry(self):
self.prepareGeometryChange()
self.setPos(self.chart.mapToPosition(
self._anchor) + QPointF(10, -50))
def removecallout(self):
self.hide()
生成图表的类:
class CreateChart(QChartView):
def __init__(self, data):
super().__init__()
self.serieses = self.getserieses(data)
i = 0
self.chart = QChart()
self.buddy = None
self.chart.legend().setVisible(False)
xaxis = QValueAxis()
xaxis.setTitleText("Time")
self.chart.addAxis(xaxis, Qt.AlignBottom)
for key in self.serieses.keys():
if i >= 100:
break
else:
self.serieses[key].setName(key)
self.chart.addSeries(self.serieses[key])
self.serieses[key].hovered.connect(self.tooltip) #The connections for the temporary callout of the coordinates
self.serieses[key].clicked.connect(self.keep_callout) #The connection for the permanent callout of the coordinates
axis = QValueAxis()
axis.setTitleText(key)
axis.setTitleBrush(self.serieses[key].color())
self.chart.addAxis(axis, Qt.AlignLeft if ((i % 2) == 0) else Qt.AlignRight)
self.serieses[key].attachAxis(axis)
self.serieses[key].attachAxis(xaxis)
i += 1
print("Finished Loading")
self.chart.legend().setMarkerShape(QLegend.MarkerShapeFromSeries)
self.chart_view = super()
self.chart_view.setRenderHint(QPainter.Antialiasing)
self.chart_view.setChart(self.chart)
#self.chart_view.setMaximumWidth(300)
#QGraphicsView.RubberbandDrag = Selecting an area which can be retrieved by **Your QChartView**.rubberBandRect()
self.chart_view.setDragMode(QGraphicsView.RubberBandDrag)
self.chart_view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) #Don't need these, as they don't move the Graph. but the whole window
self.chart_view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # ^
self.chart.setFocusPolicy(Qt.NoFocus)
self._tooltip = Callout(self.chart)
self._callouts = []
self.setMouseTracking(True) #Must be on
def tooltip(self, point, state):
#point = self.Mouse
if self._tooltip == 0:
self._tooltip = Callout(self._chart)
if state:
x = point.x()
y = point.y()
self._tooltip.set_text(f"X: {x:.1f} \nY: {y:.1f} ")
self._tooltip.set_anchor(point)
self._tooltip.setZValue(11)
self._tooltip.update_geometry()
self._tooltip.show()
else:
self._tooltip.hide()
def keep_callout(self):
self._callouts.append(self._tooltip)
self._tooltip = Callout(self.chart)
现在,当我执行此操作时,标注在一个系列上看起来很完美,但在所有其他系列上标注出现在我的鼠标实际位置的上方或下方,因为标注绘制在与系列不同的轴上
【问题讨论】:
-
您的问题不清楚,具有多个 y 轴的 Qt 标注示例与 我将鼠标悬停在“QLineSeries”上,标注看起来更高或低于我实际指向的位置?
-
标注被绘制在与系列不同的轴上,因此它们不会连接到我实际悬停的点