質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

5513閲覧

PyQt5で既存のQGraphicViewにマウスのドラッグ&ドロップで矩形を描画したい。

isc

総合スコア2

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/07/10 07:27

編集2020/07/12 15:26

前提・実現したいこと

QGraphicViewに先にjpg形式の画像を貼っておき、その上から矩形を描画したいと考えています。
矩形の描画は一時的でよく、ドラッグ&ドロップをやり直すと矩形が再描画できるのが理想です。

該当のソースコード

python

1 2import sys,re 3from PyQt5.QtCore import Qt 4from PyQt5.QtGui import QPainter 5from PyQt5.QtWidgets import QApplication,QWidget 6 7class Widget(QWidget): 8 9 global start_x,start_y,end_x,end_y 10 11 def __init__(self, parent=None): 12 QWidget.__init__(self, parent) 13 self.points = [] 14 self.psets = [] 15 self.points_a = [] 16 self.setMinimumSize(500, 500) 17 self.setMaximumSize(500, 500) 18 19 def mousePressEvent(self, event): 20 self.points.append(event.pos()) 21 22 #無知が故の文字列処理です################## 23 arr = [str(i) for i in self.points] 24 moji =','.join(arr) 25 global start_x ,start_y 26 result = moji.replace('PyQt5.QtCore.QPoint','') 27 result = result.strip('()') 28 result = result.replace(',','') 29 l_result = result.split() 30 ####################################### 31 start_x = l_result[0] 32 start_y = l_result[1] 33 34 35 36 def mouseMoveEvent(self, event): 37 self.points_a =[] 38 self.points_a.append(event.pos()) 39 arr = [str(i) for i in self.points_a] 40 moji =','.join(arr) 41 global end_x ,end_y 42 result = moji.replace('PyQt5.QtCore.QPoint','') 43 result = result.strip('()') 44 result = result.replace(',','') 45 l_result = result.split() 46 end_x = l_result[0] 47 end_y = l_result[1] 48 painter = QPainter(self) 49 painter.setPen(Qt.black) 50 painter.drawRect(int(start_x),int(start_y),int(end_x)-int(start_x),int(end_y)-int(start_y)) 51 self.update() 52 53 def mouseReleaseEvent(self, event): 54 self.psets = [] 55 self.psets.append(event.pos()) 56 57 58 59 arr = [str(i) for i in self.psets] 60 moji =','.join(arr) 61 global end_x ,end_y 62 result = moji.replace('PyQt5.QtCore.QPoint','') 63 result = result.strip('()') 64 result = result.replace(',','') 65 l_result = result.split() 66 end_x = l_result[0] 67 end_y = l_result[1] 68 69 70 self.points = [] 71 self.update() 72 73 74 75 def paintEvent(self, event): 76 painter = QPainter(self) 77 painter.setPen(Qt.black) 78 79 for points in self.psets: 80 painter.drawRect(int(start_x),int(start_y),int(end_x)-int(start_x),int(end_y)-int(start_y)) 81 print(start_x,start_y,end_x,end_y) 82 83if __name__ == '__main__': 84 app = QApplication(sys.argv) 85 w = Widget() 86 w.show() 87 sys.exit(app.exec_())

試したこと

参考プログラムをもとに上記のプログラムを書きました(適当に書きすぎて本当に汚いです…)
マウスのドラッグ&ドロップで矩形を描画するのはこちらのサイトでも例があります。
これをQGraphicViewの画像の上で再現することができません。
mainwindowなどでやると動作はしますが、画像が入らないという問題が出てきました。

補足情報(FW/ツールのバージョンなど)

python 3.6

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

2つの異なる方法を混在させて使おうとしてるのが原因です。

GGraphicsViewクラスは、paintEventをオーバーライドして
Scene で管理する Item を描画するという独自の描画の枠組みを提供しているので、

元の機能を保ったまま独自に拡張する場合は、
親クラスのpaintEvent を呼び出す必要があります。(暫定的な解決策)

(↑ QGraphicViewを使ったコードは解らない為、ここは推測ですが
QGraphicViewを継承し拡張しようとしている場合)

それよりも、GGraphicsView で出来る事ならば
その枠組み内でやってしまった方が良いです。

QGraphicsView 上の場合、矩形の描画には
QGraphicsRectItem等を用います。
マウスのイベントでアイテムの表示非表示/移動・リサイズを行うことで
選択範囲の枠描画は実現できます。


mainwindowなどでやると動作はしますが、画像が入らないという問題が出てきました。

通常のwidgetの場合
QPainter で画像を描画する場合は、drawImage や drawPixmap を使います。


イメージ説明

出典: https://stackoverflow.com/questions/52728462/pyqt-add-rectangle-in-qgraphicsscene

サンプルコードを数カ所改変しました。

  • 画像との重ね合わせを考慮して、透過色 QtGui.QColor(255, 0, 0, 128)
  • 短形は一つのみ表示 self.removeItem(self._current_rect_item)
  • 不要な設定の削除 ItemIsMovable フラグ

python

1from PyQt5 import QtCore, QtGui, QtWidgets 2 3class GraphicsScene(QtWidgets.QGraphicsScene): 4 def __init__(self, parent=None): 5 super(GraphicsScene, self).__init__(QtCore.QRectF(-500, -500, 1000, 1000), parent) 6 self._start = QtCore.QPointF() 7 self._current_rect_item = None 8 9 def mousePressEvent(self, event): 10 if self._current_rect_item: 11 self.removeItem(self._current_rect_item) 12 if self.itemAt(event.scenePos(), QtGui.QTransform()) is None: 13 self._current_rect_item = QtWidgets.QGraphicsRectItem() 14 self._current_rect_item.setBrush(QtGui.QColor(255, 0, 0, 128)) 15 # アイテムを移動可能にする -> すぐに削除する為不要 16 # self._current_rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) 17 self.addItem(self._current_rect_item) 18 self._start = event.scenePos() 19 r = QtCore.QRectF(self._start, self._start) 20 self._current_rect_item.setRect(r) 21 super(GraphicsScene, self).mousePressEvent(event) 22 23 def mouseMoveEvent(self, event): 24 if self._current_rect_item is not None: 25 r = QtCore.QRectF(self._start, event.scenePos()).normalized() 26 self._current_rect_item.setRect(r) 27 super(GraphicsScene, self).mouseMoveEvent(event) 28 29 def mouseReleaseEvent(self, event): 30 # self._current_rect_item = None 31 super(GraphicsScene, self).mouseReleaseEvent(event) 32 33 34class MainWindow(QtWidgets.QMainWindow): 35 def __init__(self, parent=None): 36 super(MainWindow, self).__init__(parent) 37 scene =GraphicsScene(self) 38 view = QtWidgets.QGraphicsView(scene) 39 self.setCentralWidget(view) 40 41 42if __name__ == '__main__': 43 import sys 44 45 app = QtWidgets.QApplication(sys.argv) 46 w = MainWindow() 47 w.resize(640, 480) 48 w.show() 49 sys.exit(app.exec_())

投稿2020/07/10 11:50

編集2020/07/10 12:08
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

isc

2020/07/10 14:48

丁寧なご回答ありがとうございます。 無知で大変申し訳ないのですが、回答者様のソース内で画像をウインドウ内に貼り付けるとしたらどの部分でしょうか?差し支えなければご教授願います。
teamikl

2020/07/10 15:24 編集

画像の読み込み形式は幾つか方法がありますが、 scene に対して追加します。 # 例) MainWindow.__init__ 内 image = QtGui.QImage("sample.png") item = scene.addPixmap(QtGui.QPixmap.fromImage(image)) # 追加したアイテムを操作できます、 # 以下はマウスドラッグで移動可能にする設定 item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
isc

2020/07/11 01:51

画像の上からクリックをしたときに、矩形描画が始まりません。これは mousePressEventが反応していないからでしょうか?もしそうであれば、これを反応させる方法はありますでしょうか。
teamikl

2020/07/11 02:58

>これは mousePressEventが反応していないからでしょうか? mousePressEvent 内で print() するなりして、 実際にイベントが呼ばれてるか確かめてみましょう。 短いコードなので一行づつ動作を確認していくと良いです。 原因は恐らく以下の2点 - アイテムのドラッグになってしまうので item.setFlag ItemIsMocable を削除 - if self.itemAt(event.scenePos(), QtGui.QTransform()) is None: 条件がクリック位置に他のアイテムがない場合となっているので、これを削除
isc

2020/07/11 18:31

画像をセットしてそのうえで矩形を描画するところまではteamikl様のおかげで完成することができました。 ですが、QGraphicsViewが固定できず、最後につまずいてしまいました。マウスでドラッグをして矩形を描く最中にQGraphicsViewの外枠に当たると拡張?(もしくはスクロールバーが追加されてしまう)ような状態になります。setMaximumSizeやsetFixed~などでは変化がありませんでした。これはどこの設定から変更できるのかご教授いただけると助かります。
teamikl

2020/07/11 19:27

最小限の動作テストしかしてなかったので、そのままの適応は難しかったようですね。 > マウスでドラッグをして矩形を描く最中にQGraphicsViewの外枠に当たると拡張?(もしくはスクロールバーが追加されてしまう)ような状態になります。 上記のサンプルコードに画像を追加しただけでは、 こちらでは再現できませんでした。 他のQGraphicsView のウィジェットの配置方法の影響でしょうか、 どの部分の setMaximumSizeやsetFixed~などか解らないので 質問を編集して問題を再現できるコードの記載をお願いします。 ---- もしくは、GraphicsView を使わない方法になりますが、 既に選択範囲の短形描画迄は出来てるようなので、 そちらに画像を表示する解決策の方が良いでしょうか? GraphicsViewの機能が必要かどうかで、どちらが適切かが変わってきますが、 差し支えなければ、どのような機能を実装したいか教えていただけますか。 例えば、画像の選択範囲の切り抜きならどちらでも実装可能ですが、 配置した画像を動かしてレイアウトを組んだりする画像編集のようなものを作るなら、 GraphicsView の方が都合が良かったりします。
isc

2020/07/12 15:24 編集

scene.setSceneRect(QtCore.QRectF(view.rect())) こちらが有用でした。ありがとうございました。
teamikl

2020/07/12 21:44

なるほど、自分の試していたサンプルでは、 ウィンドウサイズに合わせてたので発生しなかったようです。 余談になりますが、GraphicsView を使わない方での画像表示(質問の上のコード差分) # __init__ で self.image = QImage("sample.png") # paintEvent内で painter.drawImage(100, 100, self.image)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問