Advertisement
StSav012

zoomlinechart

May 13th, 2025
328
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.12 KB | Source Code | 0 0
  1. """
  2. Copyright (C) 2023 The Qt Company Ltd.
  3. SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
  4. """
  5.  
  6. import sys
  7. from math import pi, sin
  8. from typing import cast
  9.  
  10. from PySide6.QtCharts import QChart, QChartView, QLineSeries
  11. from PySide6.QtCore import QEvent, QPoint, QPointF, QRandomGenerator, Qt
  12. from PySide6.QtGui import QKeyEvent, QMouseEvent, QPainter, QWheelEvent
  13. from PySide6.QtWidgets import (
  14.     QApplication,
  15.     QGestureEvent,
  16.     QGraphicsItem,
  17.     QMainWindow,
  18.     QPanGesture,
  19.     QPinchGesture,
  20.     QWidget,
  21. )
  22.  
  23.  
  24. class Chart(QChart):
  25.     def __init__(
  26.         self,
  27.         parent: QGraphicsItem | None = None,
  28.         flags: Qt.WindowType = Qt.WindowType(0),
  29.         /,
  30.     ) -> None:
  31.         super().__init__(QChart.ChartType.ChartTypeCartesian, parent, flags)
  32.  
  33.         # Seems that QGraphicsView (QChartView) does not grab gestures.
  34.         # They can only be grabbed here in the QGraphicsWidget (QChart).
  35.         self.grabGesture(Qt.GestureType.PanGesture)
  36.         self.grabGesture(Qt.GestureType.PinchGesture)
  37.  
  38.     def sceneEvent(self, event: QEvent, /) -> bool:
  39.         if event.type() == QEvent.Type.Gesture:
  40.             return self.gestureEvent(cast(QGestureEvent, event))
  41.         return super().event(event)
  42.  
  43.     def gestureEvent(self, event: QGestureEvent, /) -> bool:
  44.         if (gesture := event.gesture(Qt.GestureType.PanGesture)) is not None:
  45.             pan: QPanGesture = cast(QPanGesture, gesture)
  46.             super().scroll(-(pan.delta().x()), pan.delta().y())
  47.  
  48.         if (gesture := event.gesture(Qt.GestureType.PinchGesture)) is not None:
  49.             pinch: QPinchGesture = cast(QPinchGesture, gesture)
  50.             if pinch.changeFlags() & QPinchGesture.ChangeFlag.ScaleFactorChanged:
  51.                 super().zoom(pinch.scaleFactor())
  52.  
  53.         return True
  54.  
  55.  
  56. class ChartView(QChartView):
  57.     def __init__(self, chart: QChart | None, /, parent: QWidget | None = None) -> None:
  58.         super().__init__(chart, parent)
  59.  
  60.         self._is_touching: bool = False
  61.         self._drag_start: QPointF = QPointF()
  62.  
  63.         self.setRubberBand(QChartView.RubberBand.RectangleRubberBand)
  64.  
  65.     def viewportEvent(self, event: QEvent) -> bool:
  66.         if event.type() == QEvent.Type.TouchBegin:
  67.             # By default, touch events are converted to mouse events. So
  68.             # after this event we will get a mouse event also, but we want
  69.             # to handle touch events as gestures only. So we need this safeguard
  70.             # to block mouse events that are actually generated from touch.
  71.             self._is_touching = True
  72.  
  73.             # Turn off animations when handling gestures they
  74.             # will only slow us down.
  75.             self.chart().setAnimationOptions(QChart.AnimationOption.NoAnimation)
  76.  
  77.         elif event.type() == QEvent.Type.Wheel:
  78.             delta: QPoint = cast(QWheelEvent, event).angleDelta()
  79.             if delta.y() > 0:
  80.                 self.chart().zoomIn()
  81.             elif delta.y() < 0:
  82.                 self.chart().zoomOut()
  83.  
  84.         return super().viewportEvent(event)
  85.  
  86.     def mousePressEvent(self, event: QMouseEvent) -> None:
  87.         if self._is_touching:
  88.             return
  89.         if event.button() == Qt.MouseButton.MiddleButton:
  90.             self._drag_start = event.position()
  91.             self.chart().setAnimationOptions(QChart.AnimationOption.NoAnimation)
  92.             print("middle", event.position(), end=" ")
  93.             return
  94.  
  95.         return super().mousePressEvent(event)
  96.  
  97.     def mouseMoveEvent(self, event: QMouseEvent) -> None:
  98.         if self._is_touching:
  99.             return
  100.         if event.buttons() == Qt.MouseButton.MiddleButton:
  101.             position: QPointF = event.position()
  102.             if not self._drag_start.isNull():
  103.                 self.chart().scroll(
  104.                     self._drag_start.x() - position.x(),
  105.                     position.y() - self._drag_start.y(),
  106.                 )
  107.             self._drag_start = position
  108.             return
  109.         return super().mouseMoveEvent(event)
  110.  
  111.     def mouseReleaseEvent(self, event: QMouseEvent) -> None:
  112.         if self._is_touching:
  113.             self._is_touching = False
  114.  
  115.         if event.button() == Qt.MouseButton.MiddleButton:
  116.             self._drag_start = QPointF()
  117.             self.chart().setAnimationOptions(QChart.AnimationOption.SeriesAnimations)
  118.             return
  119.  
  120.         # Because we disabled animations when touch event was detected
  121.         # we must put them back on.
  122.         self.chart().setAnimationOptions(QChart.AnimationOption.SeriesAnimations)
  123.  
  124.         return super().mouseReleaseEvent(event)
  125.  
  126.     def keyPressEvent(self, event: QKeyEvent) -> None:
  127.         match event.key():
  128.             case Qt.Key.Key_Plus:
  129.                 self.chart().zoomIn()
  130.             case Qt.Key.Key_Minus:
  131.                 self.chart().zoomOut()
  132.             case Qt.Key.Key_Left:
  133.                 self.chart().scroll(-10, 0)
  134.             case Qt.Key.Key_Right:
  135.                 self.chart().scroll(10, 0)
  136.             case Qt.Key.Key_Up:
  137.                 self.chart().scroll(0, 10)
  138.             case Qt.Key.Key_Down:
  139.                 self.chart().scroll(0, -10)
  140.             case _:
  141.                 super().keyPressEvent(event)
  142.  
  143.  
  144. def main() -> int:
  145.     a: QApplication = QApplication(sys.argv)
  146.  
  147.     series: QLineSeries = QLineSeries()
  148.     for i in range(500):
  149.         p: QPointF = QPointF(float(i), sin(pi / 50 * i) * 100)
  150.         p.setY(p.y() + QRandomGenerator.global_().bounded(20))
  151.         series << p
  152.  
  153.     chart: Chart = Chart()
  154.     chart.addSeries(series)
  155.     chart.setTitle(chart.tr("Zoom in/out example"))
  156.     chart.setAnimationOptions(QChart.AnimationOption.SeriesAnimations)
  157.     chart.legend().hide()
  158.     chart.createDefaultAxes()
  159.  
  160.     chart_view: ChartView = ChartView(chart)
  161.     chart_view.setRenderHint(QPainter.RenderHint.Antialiasing)
  162.  
  163.     window: QMainWindow = QMainWindow()
  164.     window.setCentralWidget(chart_view)
  165.     window.resize(400, 300)
  166.     window.grabGesture(Qt.GestureType.PanGesture)
  167.     window.grabGesture(Qt.GestureType.PinchGesture)
  168.     window.show()
  169.  
  170.     return a.exec()
  171.  
  172.  
  173. if __name__ == "__main__":
  174.     main()
  175.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement
OSZAR »