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

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

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

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

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

Python

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

Q&A

解決済

1回答

10597閲覧

PyQt5:QGraphicsViewとQGraphicsSceneの大きさの関係

Ykkykk

総合スコア140

Python 3.x

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

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

Python

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

0グッド

1クリップ

投稿2018/10/09 03:05

編集2018/10/09 03:18

PyQtでのQGraphicsViewとQGraphicsSceneの大きさの関係がよくわかりません。

Python3

1import sys 2from PyQt5.QtWidgets import * 3from PyQt5.QtGui import * 4from PyQt5.QtCore import * 5 6class Example(QGraphicsItem): 7 def __init__(self, width=400, height=400): 8 super(Example, self).__init__() 9 10 self.width = width 11 self.height = height 12 self.x_origin = width / 2 13 self.y_origin = height / 2 14 self.scale = 20 15 16 def paint(self, painter, option, widget): 17 painter.setPen(Qt.black) 18 painter.drawLine(0, self.y_origin, self.width, self.y_origin) 19 painter.drawLine(self.x_origin, 0, self.x_origin, self.height) 20 print("paint") 21 22 for i in range(100): 23 x = self.x_origin + i * self.scale 24 y = self.y_origin + i * self.scale 25 painter.setPen(Qt.black) 26 painter.setBrush(QBrush(Qt.red, Qt.SolidPattern)) 27 painter.drawEllipse(QPointF(x, y), 9, 9) 28 29 def boundingRect(self): 30 return QRectF(0, 0, self.width, self.height) 31 32 def setScale(self, x): 33 self.scale = x 34 35 def getScale(self): 36 return self.scale 37 38 def repaint(self): 39 self.update() 40 41class MyWindow(QMainWindow): 42 def __init__(self): 43 super().__init__() 44 self.initUI() 45 46 def initUI(self): 47 self.setGeometry(0, 0, 600, 500) 48 self.setWindowTitle("Ex") 49 50 self.setWindow() 51 52 self.show() 53 54 def setWindow(self): 55 self.w = QWidget() 56 57 self.view = QGraphicsView() 58 self.scene = QGraphicsScene(self.view) 59 self.srect = self.view.rect() 60 width = self.srect.width() 61 height = self.srect.height() 62 self.scene.setSceneRect(QRectF(self.srect)) 63 self.graph = Example(width, height) 64 self.scene.addItem(self.graph) 65 self.view.setScene(self.scene) 66 67 label = QLabel(" X ") 68 self.box = QLineEdit() 69 x = self.getScale() 70 self.box.setText("{}".format(x)) 71 update = QPushButton('Update') 72 update.clicked.connect(self.setScale) 73 74 main = QGridLayout() 75 76 main.addWidget(self.view, 0, 0, 30, 5) 77 main.addWidget(label, 0, 10, 1, 3) 78 main.addWidget(self.box, 1, 10, 1, 3) 79 main.addWidget(update, 2, 10, 1, 3) 80 81 self.w.setLayout(main) 82 self.setCentralWidget(self.w) 83 84 def getScale(self): 85 return self.graph.getScale() 86 87 def setScale(self): 88 self.x = int(self.box.text()) 89 self.graph.setScale(self.x) 90 self.graph.repaint() 91 92def main(): 93 app = QApplication(sys.argv) 94 gui = MyWindow() 95 sys.exit(app.exec_()) 96 97 98if __name__ == '__main__': 99 main()

現在、以上のような構成でウィンドウを作成していみているのですが、円が見切れる形になっております。

ここで表示されているスクロールバーは、恐らく設定されているviewの大きさ分しか動かすことができないということだと思うのですが、すべての円を表示するためにはどのようにすればよいのでしょうか?
また、右側で用意しているテキストボックスを使用して、円と円の間隔を変えるようにした場合、動的にスクロールバーの長さを変更するようなことはできるのでしょうか?

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

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

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

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

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

guest

回答1

0

ベストアンサー

全部表示されない原因

ここで表示されているスクロールバーは、恐らく設定されているviewの大きさ分しか動かすことができないということだと思うのですが、すべての円を表示するためにはどのようにすればよいのでしょうか?

View の大きさ以上スクロールできないのは、QGraphicsScene の SceneRect にビューの大きさを設定しているからです。

self.scene.setSceneRect(QRectF(self.srect))

これをコメントアウトして、SceneRect を設定しない場合は、QgraphicsScene はアイテムがすべて収まるサイズに QGraphicsScene が拡張されます。
今回は Example という QGraphisItem だけなので、この大きさは

def boundingRect(self): return QRectF(0, 0, self.width, self.height)

で定義されています。この self.width, self.height は次のコンストラクタ引数で QGraphicsView のサイズを設定していたので、QGraphicsView のサイズになります。

self.graph = Example(width, height)

すべての円を表示するには

ここで表示されているスクロールバーは、恐らく設定されているviewの大きさ分しか動かすことができないということだと思うのですが、すべての円を表示するためにはどのようにすればよいのでしょうか? また、右側で用意しているテキストボックスを使用して、円と円の間隔を変えるようにした場合、動的にスクロールバーの長さを変更するようなことはできるのでしょうか?

すべての円が表示されるように Example クラスの def boundingRect(self) が返す Rect を動的に変更する必要があります。

全部表示されるように変更したコード

  • 原寸大で表示したい場合は fitInView() の2箇所をコメントアウトしてください。
  • GGraphicsItem の大きさ等変更する場合 (scale の変更など) は変更前に prepareGeometryChange() をよんでください。変更が完了したら、update() で再描画すればよいです。

python

1import sys 2from PyQt5.QtWidgets import * 3from PyQt5.QtGui import * 4from PyQt5.QtCore import * 5 6 7class Example(QGraphicsItem): 8 def __init__(self, width=400, height=400): 9 super(Example, self).__init__() 10 11 self.width = width 12 self.height = height 13 self.x_origin = width / 2 14 self.y_origin = height / 2 15 self.scale = 20 16 17 def paint(self, painter, option, widget): 18 painter.setPen(Qt.black) 19 painter.drawLine(0, self.y_origin, self.width, self.y_origin) 20 painter.drawLine(self.x_origin, 0, self.x_origin, self.height) 21 print("paint") 22 23 for i in range(100): 24 x = self.x_origin + i * self.scale 25 y = self.y_origin + i * self.scale 26 painter.setPen(Qt.black) 27 painter.setBrush(QBrush(Qt.red, Qt.SolidPattern)) 28 painter.drawEllipse(QPointF(x, y), 9, 9) 29 30 def boundingRect(self): 31 width = self.y_origin + 100 * self.scale + 30 32 height = self.y_origin + 100 * self.scale + 30 33 return QRectF(0, 0, width, height) 34 35 def setScale(self, x): 36 self.prepareGeometryChange() 37 self.scale = x 38 self.update() 39 40 def getScale(self): 41 return self.scale 42 43 44class MyWindow(QMainWindow): 45 def __init__(self): 46 super().__init__() 47 self.initUI() 48 49 def initUI(self): 50 self.setGeometry(50, 50, 600, 500) 51 self.setWindowTitle("Ex") 52 self.setWindow() 53 self.show() 54 55 def setWindow(self): 56 self.w = QWidget() 57 self.view = QGraphicsView() 58 self.scene = QGraphicsScene(self.view) 59 self.srect = self.view.rect() 60 width = self.srect.width() 61 height = self.srect.height() 62 # self.scene.setSceneRect(QRectF(self.srect)) 63 self.graph = Example(width, height) 64 self.scene.addItem(self.graph) 65 self.view.setScene(self.scene) 66 self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) 67 68 label = QLabel(" X ") 69 self.box = QLineEdit() 70 x = self.getScale() 71 self.box.setText("{}".format(x)) 72 update = QPushButton('Update') 73 update.clicked.connect(self.setScale) 74 75 main = QGridLayout() 76 main.addWidget(self.view, 0, 0, 30, 5) 77 main.addWidget(label, 0, 10, 1, 3) 78 main.addWidget(self.box, 1, 10, 1, 3) 79 main.addWidget(update, 2, 10, 1, 3) 80 81 self.w.setLayout(main) 82 self.setCentralWidget(self.w) 83 84 def getScale(self): 85 return self.graph.getScale() 86 87 def setScale(self): 88 self.x = int(self.box.text()) 89 self.graph.setScale(self.x) 90 self.scene.setSceneRect(self.scene.itemsBoundingRect()) 91 self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) 92 93 94def main(): 95 app = QApplication(sys.argv) 96 gui = MyWindow() 97 sys.exit(app.exec_()) 98 99 100if __name__ == '__main__': 101 main()

追記 Qt の情報源

C++ も PyQt もライブラリの使い方は同じで情報量は C++ のほうが多いので、検索するときは PyQt ではなく Qt で調べたほうがいいです。(C++ の文法を知らなくても大丈夫です。)

検索は日本語で出てこなければ、英語のキーワードで調べたほうがいいです。Stack Overflow でだいたい既出です。

使用するクラスに関してだけ確認する。

  • Stack Overflow / Qt Centre などの質問サイト

例えば、「QGraphicsView の表示スケールを QGraphicsScene がすべて収まるように変更したい」と思った場合は「qgraphicsview auto scale」と検索してみると、

1個目、2個目に答えが出てきます。

Auto scale a QGraphicsView
how to Fit QGraphicsScene in a QGraphicsView

  • Qiita などの日本語のサイト

日本語の情報源もそれなりにあります。

Qiita

  • 公式の Example

Qt Creator をインストールするとかなりの数の Example がついてきます。

イメージ説明

投稿2018/10/09 04:11

編集2018/10/09 05:07
tiitoi

総合スコア21956

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

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

Ykkykk

2018/10/09 04:32 編集

コードまでご提示いただきありがとうございます。 ご指摘いただいた通り、boundingRect()の返り値を調節するところで詰まっておりました。 このboundingRect()内の操作は、どのような処理になっているのでしょうか? なぜ「原点+100×スケール+30」という処理になるのでしょうか? また、スケールの変更前にprepareGeometryChange()を呼ぶとのことですが、self.view.scale(2,2)とする前にprepareGeometryChange()を呼ぶという理解で正しいでしょうか? お手数ですが、ご教示いただけますと幸いです。
tiitoi

2018/10/09 04:39 編集

boundingRect() は、「QGraphicsItem を囲む長方形を返す」という役割があります。 QGraphicsScene 側からは各アイテムの boundingRect() を呼び出して、アイテムの矩形を判断しています。 質問のコードでは、boundingRect() の範囲を超えて楕円を描画しているので、超えた範囲の楕円は表示されないということになります。なので、描画したすべての円を表示したい場合は一番右下の円の座標を boundingRect() の width, height に設定してあげる必要があります。その座標は 原点+100×スケール+9 (円の半径) ですが、少し余裕をもたせて +30 としてあります。 あくまでサンプルなので、適宜調整してください。 ``` for i in range(100): x = self.x_origin + i * self.scale y = self.y_origin + i * self.scale ```
tiitoi

2018/10/09 04:43

prepareGeometryChange() は Example の boundingBox() の大きさが変更されるような場合に変更前によんでください。 たとえば、Example.setScale() でスケールが変更された場合です。 呼び出すのは、Example の中で呼び出せばよいです。 ``` def setScale(self, x): self.prepareGeometryChange() # 変更前に呼ぶ self.scale = x # スケールを変えたということは boundingBox() も変わる。 self.update() # 再描画リクエスト ``` http://doc.qt.io/qt-5/qgraphicsitem.html#prepareGeometryChange
Ykkykk

2018/10/09 04:49

再度詳細にお教えいただき本当にありがとうございます。 上記二点について確認いたしました。 また、本筋とはそれるのですが、Qtについてどのようにご習得になられたのでしょうか?Qtのリファレンス等を読むことが中心ですか??
tiitoi

2018/10/09 05:04

追記しました。自分は PyQt でアプリケーションを作ったりしたことはないのですが、C++ の Qt を使って GUI アプリを作成したりします。 リファレンスは量が多いので、「使うクラスだけ読む」という活用法がおすすめです。あと検索するときは「PyQt でなく、Qt で調べる」「英語で調べる」がいいかと思います。
Ykkykk

2018/10/09 06:04

Qtで調べたほうが良いのですね。ありがとうございます。 本筋とは異なる点までご追記いただき本当にありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問