2016/10/13(木) [n年前の日記]
#2 [python] PySideでマウスを動かしてお絵かき
Windows10 x64 + Python 2.7.11 + PySide 1.2.4 で、ウインドウ上でマウスを動かすと何かを描ける、てな処理を QGraphics* を使って試してみたり。
_drawing_pyside_4.py
_ball.png
これで一応できた、のかな。
Qtには、ビットマップデータ相当として使える QPixmap てのがあるわけだけど。その QPixmap に対しては、QPainter を使って何か描き込むことができるわけで。
しかし、その QPixmap を渡して生成した QGraphicsPixmapItem の見た目を更新する方法がどうにも分からず。
結局、生成時に作った QPixmap を更新するたびに、QGraphicsPixmapItem の setPixmap() で設定し直してみたら、見た目も更新されるようになったけど…。果たしてコレでいいのだろうか…?
もしかして、QGraphicsPixmapItem が持ってる QPixmap は、QGraphicsPixmapItem の生成時、あるいは setPixmap() を呼んだ時に渡された QPixmap の内容を丸々コピーして持ってたりするのだろうかと。仮にそうであれば、生成時に渡した QPixmap を後から更新したところで、見た目も即座に更新されるわけでは無い、てのも分かる気もする。が、実際はどういう仕組みになっているのやら。
それと、どうせ QGraphicsPixmapItem が QPixmap を持っているなら、その QPixmap に直接描き込んでしまえばいいのではないか、とも思ったのだけど。試してみたところ、Pythonスクリプトが強制終了してしまって。となると…。
よく分からないと言えば…。QGraphicsView を使うとスクロールバーがなんだか中途半端な長さで出てくるのだけど、コレって何をどうやって設定したり使用したりするのだろう…。今後の課題。
_drawing_pyside_4.py
_ball.png
""" PySideでウインドウに描画。 マウスを動かしてお絵かきできる。 QGraphics* を使う。 ヲドリテヒヅル PyQtでイメージビューワ http://melpystudio.blog82.fc2.com/blog-entry-138.html """ import sys from PySide.QtCore import * from PySide.QtGui import * width = 640 height = 480 brushPath = 'ball.png' class ImageViewScene(QGraphicsScene): """ メインビューと関連付けられる Scene """ def __init__(self, *argv, **keywords): super(ImageViewScene, self).__init__(*argv, **keywords) self.buttonFlag = False self.pixmap = QPixmap(width, height) self.pixmap.fill() self.brushImage = QPixmap(brushPath) # Scene に Item を追加 self.imgItem = QGraphicsPixmapItem(self.pixmap) self.addItem(self.imgItem) def mouseDoubleClickEvent(self, event): pass def mousePressEvent(self, event): """ マウスボタンが押された際の処理 """ if event.button() == Qt.LeftButton: self.buttonFlag = True self.drawing(event) elif event.button() == Qt.RightButton: self.pixmap.fill() self.imgItem.setPixmap(self.pixmap) def mouseMoveEvent(self, event): """ マウスカーソル移動中の処理 """ if self.buttonFlag: self.drawing(event) def mouseReleaseEvent(self, event): """ マウスボタンが離されたときの処理 """ if event.button() == Qt.LeftButton: self.buttonFlag = False def drawing(self, event): """ ブラシで描画 """ x = event.scenePos().x() y = event.scenePos().y() x -= self.brushImage.width() / 2 y -= self.brushImage.height() / 2 qp = QPainter() qp.begin(self.pixmap) qp.drawPixmap(x, y, self.brushImage) qp.end() del qp # 描画更新する方法が分からない… # 仕方なく、pixmap を再設定してるけど…これでいいの? self.imgItem.setPixmap(self.pixmap) # self.imgItem.update() # self.update() class ImageViewer(QGraphicsView): """ メインとなるビュー """ def __init__(self): super(ImageViewer, self).__init__() self.setCacheMode(QGraphicsView.CacheBackground) self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing ) scene = ImageViewScene(self) self.setScene(scene) scene.setSceneRect(QRectF(self.rect())) def resizeEvent(self, event): """ ビューをリサイズ時にシーンの矩形を更新 """ super(ImageViewer, self).resizeEvent(event) self.scene().setSceneRect(QRectF(self.rect())) if __name__ == '__main__': app = QApplication(sys.argv) viewer = ImageViewer() viewer.show() sys.exit(app.exec_())
これで一応できた、のかな。
Qtには、ビットマップデータ相当として使える QPixmap てのがあるわけだけど。その QPixmap に対しては、QPainter を使って何か描き込むことができるわけで。
しかし、その QPixmap を渡して生成した QGraphicsPixmapItem の見た目を更新する方法がどうにも分からず。
結局、生成時に作った QPixmap を更新するたびに、QGraphicsPixmapItem の setPixmap() で設定し直してみたら、見た目も更新されるようになったけど…。果たしてコレでいいのだろうか…?
もしかして、QGraphicsPixmapItem が持ってる QPixmap は、QGraphicsPixmapItem の生成時、あるいは setPixmap() を呼んだ時に渡された QPixmap の内容を丸々コピーして持ってたりするのだろうかと。仮にそうであれば、生成時に渡した QPixmap を後から更新したところで、見た目も即座に更新されるわけでは無い、てのも分かる気もする。が、実際はどういう仕組みになっているのやら。
それと、どうせ QGraphicsPixmapItem が QPixmap を持っているなら、その QPixmap に直接描き込んでしまえばいいのではないか、とも思ったのだけど。試してみたところ、Pythonスクリプトが強制終了してしまって。となると…。
- QGraphicsPixmapItem が持ってる QPixmap は、デスクトップ上の描画にせっせと使ったりしてる関係で、中身を変更しちゃダメだよ、読み出しはともかく書き込みはNGだよ、ということになっている、とか?
- あるいは、中身を変更したいならしかるべき手順を踏んでから更新しないとダメだよ、ということになっている、とか?
よく分からないと言えば…。QGraphicsView を使うとスクロールバーがなんだか中途半端な長さで出てくるのだけど、コレって何をどうやって設定したり使用したりするのだろう…。今後の課題。
[ ツッコむ ]
以上です。