#!python # -*- mode: python; Encoding: utf-8; coding: utf-8 -*- # Last updated: <2016/10/25 10:07:24 +0900> """ PySide + QGraphicsView上でマウスカーソルに何かを追従させる 動作確認環境 : Windows10 x64 + Python 2.7.11 + PySide 1.2.4 """ import sys from PySide.QtCore import * from PySide.QtGui import * brushFile = "brush.png" canvasSize = (640, 480) padding = 48 status = None class DrawAreaScene(QGraphicsScene): """ 描画ウインドウ用Scene """ def __init__(self, *argv, **keywords): super(DrawAreaScene, self).__init__(*argv, **keywords) global brushFile global canvasSize global padding # Scene に 空QPixmap を追加 w, h = canvasSize self.pixmap = QPixmap(w, h) self.pixmap.fill(QColor(192, 192, 192, 255)) self.imgItem = QGraphicsPixmapItem(self.pixmap) self.addItem(self.imgItem) self.imgItem.setX(padding) self.imgItem.setY(padding) # Scene にブラシ画像を追加 self.brushPixmap = QPixmap(brushFile) self.brushImgItem = QGraphicsPixmapItem(self.brushPixmap) self.addItem(self.brushImgItem) def mousePressEvent(self, event): """ マウスボタンを押した """ x, y = self.getMousePos(event, "Click") def mouseReleaseEvent(self, event): """ マウスボタンを離した """ x, y = self.getMousePos(event, "Release") def mouseMoveEvent(self, event): """ マウスを動かしてる時に呼ばれる処理。 デフォルトではマウスボタンを押してる間(ドラッグ中)しか呼ばれないが、 親のQGraphicsView で viewport() の mouseTracking を True にすれば マウスを動かした際に常時呼ばれるようになる。 """ x, y = self.getMousePos(event, "Move") # ブラシが非表示なら表示を有効化 if not self.brushImgItem.isVisible(): self.setVisibleBrush(True) # ブラシの表示位置を変更 pm = self.brushImgItem.pixmap() xd = pm.width() / 2 yd = pm.height() / 2 self.brushImgItem.setOffset(int(x - xd), int(y - yd)) def getMousePos(self, event, msg): """ マウス座標を取得 """ x = event.scenePos().x() y = event.scenePos().y() global status status.showMessage("(%d , %d) %s" % (x, y, msg)) return (x, y) def setVisibleBrush(self, flag): """ ブラシ表示の有効無効切り替え """ self.brushImgItem.setVisible(flag) class DrawAreaView(QGraphicsView): """ メインになるQGraphicsView """ def __init__(self, *argv, **keywords): super(DrawAreaView, self).__init__(*argv, **keywords) self.setBackgroundBrush(QColor(64, 64, 64, 255)) # 背景色を設定 self.setCacheMode(QGraphicsView.CacheBackground) # self.setRenderHints(QPainter.Antialiasing | # QPainter.SmoothPixmapTransform | # QPainter.TextAntialiasing) # Sceneを登録 scene = DrawAreaScene(self) self.setScene(scene) self.setSceneNewRect() # 子のSceneに対してマウストラッキングを有効に vp = self.viewport().setMouseTracking(True) def resizeEvent(self, event): """ リサイズ時に呼ばれる処理 """ super(DrawAreaView, self).resizeEvent(event) self.setSceneNewRect() def scrollContentsBy(self, dx, dy): """ スクロールバー操作時に呼ばれる処理 """ # スクロール中、Scene内にブラシがあると # 何故かゴミが残るので、ブラシを非表示にしている self.scene().setVisibleBrush(False) super(DrawAreaView, self).scrollContentsBy(dx, dy) def setSceneNewRect(self): """ Sceneの矩形を更新 """ # 以下は、Sceneのアイテム群境界ボックスを取得する例 # rect = self.scene().itemsBoundingRect() # 以下は、viewport のサイズを指定する例 # rect = QRectf(self.viewport().rect()) global canvasSize global padding w, h = canvasSize # キャンバス周辺に余白を設けたサイズを求める w += padding * 2 h += padding * 2 rect = QRectF(0, 0, w, h) # Sceneの矩形を更新。自動でスクロールバーの長さも変わってくれる self.scene().setSceneRect(rect) class MyVWidget(QWidget): """ メインウインドウ周辺に配置するWidget """ def __init__(self, parent=None): super(MyVWidget, self).__init__(parent) l = QVBoxLayout() # 縦に並べる l.addWidget(QLabel("Dummy")) self.setLayout(l) class MyMainWindow(QMainWindow): """ メインウインドウ """ def __init__(self, *argv, **keywords): super(MyMainWindow, self).__init__(*argv, **keywords) self.setWindowTitle("Mouse Tracking Test") self.resize(640, 480) # メニューバー mb = QMenuBar() file_menu = QMenu("&File", self) exit_action = file_menu.addAction("&Close") exit_action.setShortcut('Ctrl+Q') exit_action.triggered.connect(qApp.quit) mb.addMenu(file_menu) self.setMenuBar(mb) # ステータスバー global status status = QStatusBar(self) self.setStatusBar(status) status.showMessage("Status Bar") # 左ドック self.leftDock = QDockWidget("Left Dock", self) self.leftDock.setWidget(MyVWidget(self)) self.addDockWidget(Qt.LeftDockWidgetArea, self.leftDock) # 中央Widget self.gview_image = DrawAreaView(self) self.setCentralWidget(self.gview_image) def main(): """ メイン処理 """ # このあたりを指定すると描画が速くなるという話を見かけたが、 # "native"、"raster"、"opengl" を指定しても結果は変わらなかった… QApplication.setGraphicsSystem("raster") app = QApplication(sys.argv) w = MyMainWindow() w.show() sys.exit(app.exec_()) if __name__ == '__main__': main()