FrontPage / Python / PySide / plotter.py

FrontPage/Python/PySide

https://gist.github.com/peace098beat/c61a781712cab34f05ae

class Plotter(QtGui.QWidget):
   def __init__(self, parent=None):
       super(Plotter, self).__init__(parent)
       ##########################################
       # member
       ##########################################
       self.Margin = 50
       self.curveMap = {}  # QMap<int, QVector<QPointF>>
       self.zoomStack = []  # QVector<PlotSettings>
       self.curZoom = 0  # int
       self.rubberBandIsShown = True
       self.rubberBandRect = QtCore.QRect()
       self.pixmap = QtGui.QPixmap()
       ##########################################
       # Widget初期設定
       ##########################################
       # self.setBackgroundRole(QtGui.QPalette.Dark)
       self.setBackgroundRole(QtGui.QPalette.Shadow)
       self.setAutoFillBackground(True)
       self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
       self.setFocusPolicy(QtCore.Qt.StrongFocus)
       self.rubberBandIsShown = False
       ##########################################
       # Setup UI
       ##########################################
       # Zoom In Button セッティング
       self.zoomInButton = QtGui.QToolButton(self)
       self.zoomInButton.setIcon(QtGui.QIcon(":/images/zoomin.png"))
       self.zoomInButton.adjustSize()
       self.connect(self.zoomInButton, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("zoomIn()"))
       # Zoom Out Button セッティング
       self.zoomOutButton = QtGui.QToolButton(self)
       self.zoomOutButton.setIcon(QtGui.QIcon(":/images/zoomout.png"))
       self.zoomOutButton.adjustSize()
       self.connect(self.zoomOutButton, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("zoomOut()"))
       # 描画設定
       iniSetting = PlotSettings()
       self.setPlotSettings(iniSetting)
   def setPlotSettings(self, settings):
       self.zoomStack = []
       self.zoomStack.append(settings)
       self.curZoom = 0
       self.zoomInButton.hide()
       self.zoomOutButton.hide()
       self.refreshPixmap()
       pass
   def setCurveData(self, id, data):
       # 辞書要素に追加
       self.curveMap[id] = data
       self.refreshPixmap()
       print self.curveMap
       pass
   def clearCurve(self, id):
       ''' 曲線データを削除する
       id:曲線データのインデックス
       '''
       if self.curveMap.has_key(id):
           self.curveMap.pop(id)
       self.refreshPixmap()
       print self.curveMap
       pass
   def minimumSizeHint(self):
       '''ウィジェットの理想的な最小サイズ
       '''
       return QtCore.QSize( 6 * self.Margin, 4 * self.Margin)
       pass
   def sizeHint(self):
       '''ウィジェットの理想的なサイズ
       '''
       return QtCore.QSize( 12 * self.Margin, 8 * self.Margin)
       pass
   ##########################################
   # Slot
   ##########################################
   @QtCore.Slot()
   def zoomIn(self):
       print 'Call zoomIn()'
       if (self.curZoom < len(self.zoomStack) - 1 ):
           self.curZoom = self.curZoom + 1
           self.zoomInButton.setEnabled(self.curZoom < len(self.zoomStack) - 1)
           self.zoomOutButton.setEnabled(True)
           self.zoomOutButton.show()
           self.refreshPixmap()
       pass
   @QtCore.Slot()
   def zoomOut(self):
       print 'Call zoomOut()'
       if (self.curZoom > 0):
           self.curZoom = self.curZoom - 1
           self.zoomOutButton.setEnabled(self.curZoom > 0)
           self.zoomInButton.setEnabled(True)
           self.zoomInButton.show()
           self.refreshPixmap()
       pass
   ##########################################
   # protected
   # 再実装の必要なQWidgetのイベントハンドラを宣言
   ##########################################
   def paintEvent(self, event):
       print 'paintEvent()'
       # 1. イメージ(グラフ)の描画
       painter = QtGui.QStylePainter(self)
       painter.drawPixmap(0,0,self.pixmap)
       # 2. ラバーバンドの描画
       if self.rubberBandIsShown:
           print 'draw to rubberBand'
           # ライトカラーの指定(QStyleに依存している)
           painter.setPen(self.palette().light().color())
           painter.setPen(QtCore.Qt.red)
           painter.drawRect(self.rubberBandRect.normalized().adjusted(0,0,-1,-1))
       # 3. ウィジェットがフォーカスされているときの色処理
       if self.hasFocus():
           option = QtGui.QStyleOptionFocusRect()
           option.initFrom(self)
           option.backgroundColor = self.palette().dark().color()
           option.backgroundColor = self.palette().shadow().color()
           painter.drawPrimitive(QtGui.QStyle.PE_FrameFocusRect, option)
       pass
   def resizeEvent(self, event):
       x = self.width() - (self.zoomInButton.width() + self.zoomOutButton.width() + 10)
       self.zoomInButton.move(x, 5)
       self.zoomOutButton.move(x + self.zoomInButton.width() + 5, 5)
       self.refreshPixmap()
       pass
   def mousePressEvent(self, event):
       rect = QtCore.QRect(self.Margin, self.Margin,
                           self.width()-2*self.Margin,
                           self.height()-2*self.Margin)
       if event.button() == QtCore.Qt.LeftButton:
           print 'push left button'
           if rect.contains(event.pos()):
               self.rubberBandIsShown = True
               self.rubberBandRect.setTopLeft(event.pos())
               self.rubberBandRect.setBottomRight(event.pos())
               self.updateRubberBandRegion()
               self.setCursor(QtCore.Qt.CrossCursor)
       pass
   def mouseMoveEnvent(self, event):
       if self.rubberBandIsShown:
           self.updateRubberBandRegion()
           self.rubberBandRect.setBottomRight(event.pos())
           self.updateRubberBandRegion()
       pass
   def mouseReleaseEvent(self, event):
       if (event.button() == QtCore.Qt.LeftButton) and self.rubberBandIsShown:
           self.rubberBandIsShown = False
           self.updateRubberBandRegion()
           self.unsetCursor()
           rect = self.rubberBandRect.normalized()
           if rect.width()<4 or rect.height()<4:
               return
           rect.translate(-self.Margin, -self.Margin)
           prevSettings = self.zoomStack[self.curZoom]
           settings = PlotSettings()
           dx = prevSettings.spanX() / (self.width() - 2*self.Margin)
           dy = prevSettings.spanY() / (self.height() - 2*self.Margin)
           settings.minX = prevSettings.minX + dx * rect.left()
           settings.maxX = prevSettings.maxX + dx * rect.right()
           settings.minY = prevSettings.minY - dy * rect.bottom()
           settings.maxY = prevSettings.maxY - dy * rect.top()
           settings.adjust()
           self.zoomStack.append(settings)
           self.zoomIn()
       pass
   def keyPressEvent(self, event):
       e =event.key()
       if e == QtCore.Qt.Key_Plus:
           self.zoomIn()
       elif e == QtCore.Qt.Key_Minus:
           self.zoomOut()
       elif e == QtCore.Qt.Key_Left:
           self.zoomStack[self.curZoom].scroll(-1, 0)
           self.refreshPixmap()
       elif e == QtCore.Qt.Key_Right:
           self.zoomStack[self.curZoom].scroll(+1, 0)
           self.refreshPixmap()
       elif e == QtCore.Qt.Key_Down:
           self.zoomStack[self.curZoom].scroll(0, -1)
           self.refreshPixmap()
       elif e == QtCore.Qt.Key_Up:
           self.zoomStack[self.curZoom].scroll(0, +1)
           self.refreshPixmap()
       else:
           QtGui.QWidget.keyPressEvent(event)
   def wheelEvent(self, event):
       pass
   ##########################################
   # private
   # 描画に必要な関数、定数、メンバ変数を宣言
   ##########################################
   def updateRubberBandRegion(self):
       print 'updateRubberBandRegion'
       rect = self.rubberBandRect.normalized()
       self.update(rect.left(), rect.top(), rect.width(), 1)
       self.update(rect.left(), rect.top(), 1, rect.height())
       self.update(rect.left(), rect.bottom(), rect.width(), 1)
       self.update(rect.right(), rect.top(), 1, rect.height())
       pass
   def refreshPixmap(self):
       '''オフスクリーンピックスマップ上に曲線をプロットし、画面を更新する
       '''
       self.pixmap = QtGui.QPixmap(self.size())
       self.pixmap.fill(self, 0, 0)
       painter = QtGui.QPainter(self.pixmap)
       painter.initFrom(self)
       self.drawGrid(painter)
       self.drawCurves(painter)
       self.update()
       pass
   def drawGrid(self, painter):
       rect = QtCore.QRect(self.Margin,
                           self.Margin,
                           self.width() - 2*self.Margin,
                           self.height() - 2*self.Margin)
       if not rect.isValid():
           return
       # グラフプロットの設定
       settings = self.zoomStack[self.curZoom]
       # ペンの色の指定
       # quiteDark = self.palette().dark().color()
       quiteDark = self.palette().dark().color()
       light = self.palette().light().color()
       # 横軸の目盛線の描画
       for i in range(settings.numXTicks+1):
           x = rect.left() + (i * (rect.width() - 1)/settings.numXTicks)
           label = settings.minX + (i * settings.spanX()/settings.numXTicks)
           painter.setPen(quiteDark)
           painter.drawLine(x, rect.top(), x, rect.bottom())
           painter.setPen(light)
           painter.drawLine(x, rect.bottom(), x, rect.bottom() + 5)
           painter.drawText(x-50, rect.bottom()+5, 100, 15,
                            QtCore.Qt.AlignCenter|QtCore.Qt.AlignTop,
                            unicode('%0.2f' % label))
       # 縦軸の目盛線の描画
       for j in range(settings.numYTicks+1):
           y = rect.bottom() - (j * (rect.height() - 1)/settings.numYTicks)
           label = settings.minY + (j * settings.spanY()/settings.numYTicks)
           painter.setPen(quiteDark)
           painter.drawLine(rect.left(), y, rect.right(), y)
           painter.setPen(light)
           painter.drawLine(rect.left()-5, y, rect.left(), y)
           painter.drawText(rect.left()-self.Margin, y-10, self.Margin-5, 20,
                            QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter,
                            unicode('%0.2f' % label))
       painter.drawRect(rect.adjusted(0,0,-1,-1))
   def drawCurves(self, painter):
       '''グリッドの上に曲線を描画する'''
       colorForIds = [QtCore.Qt.red, QtCore.Qt.green, QtCore.Qt.blue, QtCore.Qt.cyan, QtCore.Qt.magenta, QtCore.Qt.yellow]
       settings = self.zoomStack[self.curZoom]
       rect = QtCore.QRect(self.Margin, self.Margin, self.width()-2*self.Margin, self.height()-2*self.Margin)
       if not rect.isValid():
           return
       # 再描画する範囲を、曲線が含まれる矩形内のみに指定
       painter.setClipRect(rect.adjusted(+1, +1, -1, -1))
       for id, data in self.curveMap.iteritems():
           polyline = QtGui.QPolygonF(data.length())
           for j in range(data.length()):
               dx = data.x[j] - settings.minX
               dy = data.y[j] - settings.minY
               x = rect.left() + (dx * (rect.width()-1)/settings.spanX())
               y = rect.bottom() - (dy * (rect.height()-1)/settings.spanY())
               polyline.append(QtCore.QPointF(x,y))
           painter.setPen( colorForIds[id % 6] )
           painter.drawPolyline(polyline)
       pass
トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-11-19 (木) 19:59:21 (755d)