回答編集履歴

4 説明補足

teamikl

teamikl score 2623

2020/05/23 15:09  投稿

> なぜかpredictcanvasだけ表示されません
複数の問題があります
- predictcanvas が表示されない (画面中央の領域)
 paintEvent がない
- 読み込んだ画像が反映されない (ファイル選択時のイベント)
 ToolFrame 内で別の PredictCanvas() を生成?
----
まず、表示されていますが、表示するものが何もない状態です。
- QImageを準備しているが、サイズが 0
- QImageは準備されただけで、何処にも描画されてない
 Canvas クラスと同様に paintEvent メソッドを実装しましょう。
----
次に、ファイルを選択したときの挙動ですが
画面中央に表示されているのは、MainWindowのpredict
ToolFrameのon_run()で呼び出しているのは、
ToolFrame内で生成されたPredictCanvas()と、それぞれ異なるものです。
メインウィンドウ側のpredict canvas のメソッドを呼び出すことで
問題自体は解決できますが、親ウィジェットを辿ってアクセスするのは、
クラスの利便性を損なうので、あまりお勧めしません。
Qtのシグナル/スロットを使った解消法を提案
- (1) ToolFrame でファイル選択時のシグナルを定義します
 `fileSelected = pyqtSignal(str)`
- (2) PredictCanvas 側で、ファイルを読み込むスロットを定義します
 `@pyqtSlot` ... `def loadImage(self, filename)`
- (3) MainWindow で双方を接続する
 `tools.fileSelected.connect(predict.loadImage)`
- (4) シグナル発火
 ToolFrame.on_run メソッド内 で `self.fileSelected.emit(filename)`
 
 ToolFrame.on_run メソッド内 で `self.fileSelected.emit(filename)` 
PyQt5 でのシグナル/スロットの使い方は
[PyQt5 signals_slots](https://doc.bccnsoft.com/docs/PyQt5/signals_slots.html) 等を参考に、コードの書き方は調べて下さい。
 
追記:  
 
因みに、pyqtではスロットの宣言は省略可能で、引数さえ一致すればよく  
例えば、Canva.openImage にも connect することができます。  
 
`tools.fileSelected.connect(self.canvas.openImage)`  
 
ToolFrame.on_runから親にアクセス  
self.parent().predict.loadImage(fileName) みたいなコードは、  
MainWindowに依存したコードになり、クラス・オブジェクトの構造が変わると使えなくなりますが、  
シグナル・スロットを用いることで、利用側が振る舞いを決められるようになり、  
ウィジェットの部品としての再利用性が高まります。  
----
```diff
--- main.orig.py   2020-05-23 14:52:14.587404600 +0900
+++ main.py   2020-05-23 14:55:03.595347700 +0900
@@ -5,7 +5,7 @@
from PyQt5.QtGui import QPainter, QImage, QPen, qRgb
from PyQt5.QtCore import Qt, QPoint, QRect, QSize, QDir
from collections import deque
-from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtCore import pyqtSlot, pyqtSignal
from PyQt5.QtGui import QIcon
class MainWindow(QMainWindow):
@@ -28,6 +28,9 @@
        hbox.addWidget(self.canvas)
        hbox.addWidget(predict)
        hbox.addWidget(tools)
+
+       tools.fileSelected.connect(predict.loadImage)
+
        return frame
  def setupUI(self):
@@ -124,9 +127,11 @@
    return False
class ToolFrame(QWidget):
+
+   fileSelected = pyqtSignal(str)
+
    def __init__(self, parent=None, *args, **kw):
        super().__init__(parent, *args, **kw)
-       self.predict=PredictCanvas()
        self.initUI()
    def initUI(self):
@@ -146,7 +151,7 @@
      fileName, _ = QFileDialog.getOpenFileName(self, "Open File", QDir.currentPath())
      if fileName:
-       self.predict.PredictImage(fileName)
+       self.fileSelected.emit(fileName)
        #self.canvas.openImage(fileName)
class Canvas(QWidget):
@@ -253,7 +258,12 @@
    self.image_predict = QImage()
    self.image_predict.fill(qRgb(255, 0, 255))
- def PredictImage(self, filename):
+ def paintEvent(self, event):
+   painter = QPainter(self)
+   painter.drawImage(0, 0, self.image_predict)
+
+ @pyqtSlot(str)
+ def loadImage(self, filename):
    image = QImage()
    if not image.load(filename):
      return False
```
3 シグナル名・スロット名を本文に合わせて修正

teamikl

teamikl score 2623

2020/05/23 14:56  投稿

> なぜかpredictcanvasだけ表示されません
複数の問題があります
- predictcanvas が表示されない (画面中央の領域)
 paintEvent がない
- 読み込んだ画像が反映されない (ファイル選択時のイベント)
 ToolFrame 内で別の PredictCanvas() を生成?
----
まず、表示されていますが、表示するものが何もない状態です。
- QImageを準備しているが、サイズが 0
- QImageは準備されただけで、何処にも描画されてない
 Canvas クラスと同様に paintEvent メソッドを実装しましょう。
----
次に、ファイルを選択したときの挙動ですが
画面中央に表示されているのは、MainWindowのpredict
ToolFrameのon_run()で呼び出しているのは、
ToolFrame内で生成されたPredictCanvas()と、それぞれ異なるものです。
メインウィンドウ側のpredict canvas のメソッドを呼び出すことで
問題自体は解決できますが、親ウィジェットを辿ってアクセスするのは、
クラスの利便性を損なうので、あまりお勧めしません。
Qtのシグナル/スロットを使った解消法を提案
- (1) ToolFrame でファイル選択時のシグナルを定義します
 `fileSelected = pyqtSignal(str)`
- (2) PredictCanvas 側で、ファイルを読み込むスロットを定義します
 `@pyqtSlot` ... `def loadImage(self, filename)`
- (3) MainWindow で双方を接続する
 `tools.fileSelected.connect(predict.loadImage)`
- (4) シグナル発火
 ToolFrame.on_run メソッド内 で `self.fileSelected.emit(filename)`
 
PyQt5 でのシグナル/スロットの使い方は
[PyQt5 signals_slots](https://doc.bccnsoft.com/docs/PyQt5/signals_slots.html) 等を参考に、コードの書き方は調べて下さい。
----
```diff
--- main.orig.py   2020-05-23 14:47:42.155965200 +0900
+++ main.py   2020-05-23 14:47:21.499922800 +0900
--- main.orig.py   2020-05-23 14:52:14.587404600 +0900
+++ main.py   2020-05-23 14:55:03.595347700 +0900
@@ -5,7 +5,7 @@
from PyQt5.QtGui import QPainter, QImage, QPen, qRgb
from PyQt5.QtCore import Qt, QPoint, QRect, QSize, QDir
from collections import deque
-from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtCore import pyqtSlot, pyqtSignal
from PyQt5.QtGui import QIcon
class MainWindow(QMainWindow):
@@ -28,6 +28,9 @@
        hbox.addWidget(self.canvas)
        hbox.addWidget(predict)
        hbox.addWidget(tools)
+
+       tools.onFileSelected.connect(predict.loadImageFile)
+       tools.fileSelected.connect(predict.loadImage)
+
        return frame
  def setupUI(self):
@@ -124,9 +127,11 @@
    return False
class ToolFrame(QWidget):
+
+   onFileSelected = pyqtSignal(str)
+   fileSelected = pyqtSignal(str)
+
    def __init__(self, parent=None, *args, **kw):
        super().__init__(parent, *args, **kw)
-       self.predict=PredictCanvas()
        self.initUI()
    def initUI(self):
@@ -146,7 +151,7 @@
      fileName, _ = QFileDialog.getOpenFileName(self, "Open File", QDir.currentPath())
      if fileName:
-       self.predict.PredictImage(fileName)
+       self.onFileSelected.emit(fileName)
+       self.fileSelected.emit(fileName)
        #self.canvas.openImage(fileName)
class Canvas(QWidget):
@@ -253,7 +258,13 @@
@@ -253,7 +258,12 @@
    self.image_predict = QImage()
    self.image_predict.fill(qRgb(255, 0, 255))
- def PredictImage(self, filename):
+ def paintEvent(self, event):
+   painter = QPainter(self)
+   painter.drawImage(0, 0, self.image_predict)
+
+ @pyqtSlot(str)
+ def loadImageFile(self, filename):
+ def loadImage(self, filename):
    image = QImage()
    if not image.load(filename):
      return False
```
2 動作確認できたので、コード差分を追記

teamikl

teamikl score 2623

2020/05/23 14:52  投稿

> なぜかpredictcanvasだけ表示されません
複数の問題があります
- predictcanvas が表示されない (画面中央の領域)
 paintEvent がない
- 読み込んだ画像が反映されない (ファイル選択時のイベント)
 ToolFrame 内で別の PredictCanvas() を生成?
----
まず、表示されていますが、表示するものが何もない状態です。
- QImageを準備しているが、サイズが 0
- QImageは準備されただけで、何処にも描画されてない
 Canvas クラスと同様に paintEvent メソッドを実装しましょう。
----
次に、ファイルを選択したときの挙動ですが
画面中央に表示されているのは、MainWindowのpredict
ToolFrameのon_run()で呼び出しているのは、
ToolFrame内で生成されたPredictCanvas()と、それぞれ異なるものです。
メインウィンドウ側のpredict canvas のメソッドを呼び出すことで
問題自体は解決できますが、親ウィジェットを辿ってアクセスするのは、
クラスの利便性を損なうので、あまりお勧めしません。
Qtのシグナル/スロットを使った解消法を提案
- (1) ToolFrame でファイル選択時のシグナルを定義します
 `fileSelected = pyqtSignal(str)`
- (2) PredictCanvas 側で、ファイルを読み込むスロットを定義します
 `@pyqtSlot` ... `def loadImage(self, filename)`
- (3) MainWindow で双方を接続する
 `tools.fileSelected.connect(predict.loadImage)`
- (4) シグナル発火
 ToolFrame.on_run メソッド内 で `self.fileSelected.emit(filename)`
 
PyQt5 でのシグナル/スロットの使い方は
[PyQt5 signals_slots](https://doc.bccnsoft.com/docs/PyQt5/signals_slots.html) 等を参考に、コードの書き方は調べて下さい。
[PyQt5 signals_slots](https://doc.bccnsoft.com/docs/PyQt5/signals_slots.html) 等を参考に、コードの書き方は調べて下さい。
----
```diff
--- main.orig.py   2020-05-23 14:47:42.155965200 +0900
+++ main.py   2020-05-23 14:47:21.499922800 +0900
@@ -5,7 +5,7 @@
from PyQt5.QtGui import QPainter, QImage, QPen, qRgb
from PyQt5.QtCore import Qt, QPoint, QRect, QSize, QDir
from collections import deque
-from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtCore import pyqtSlot, pyqtSignal
from PyQt5.QtGui import QIcon
class MainWindow(QMainWindow):
@@ -28,6 +28,9 @@
        hbox.addWidget(self.canvas)
        hbox.addWidget(predict)
        hbox.addWidget(tools)
+
+       tools.onFileSelected.connect(predict.loadImageFile)
+
        return frame
  def setupUI(self):
@@ -124,9 +127,11 @@
    return False
class ToolFrame(QWidget):
+
+   onFileSelected = pyqtSignal(str)
+
    def __init__(self, parent=None, *args, **kw):
        super().__init__(parent, *args, **kw)
-       self.predict=PredictCanvas()
        self.initUI()
    def initUI(self):
@@ -146,7 +151,7 @@
      fileName, _ = QFileDialog.getOpenFileName(self, "Open File", QDir.currentPath())
      if fileName:
-       self.predict.PredictImage(fileName)
+       self.onFileSelected.emit(fileName)
        #self.canvas.openImage(fileName)
class Canvas(QWidget):
@@ -253,7 +258,13 @@
    self.image_predict = QImage()
    self.image_predict.fill(qRgb(255, 0, 255))
- def PredictImage(self, filename):
+ def paintEvent(self, event):
+   painter = QPainter(self)
+   painter.drawImage(0, 0, self.image_predict)
+
+ @pyqtSlot(str)
+ def loadImageFile(self, filename):
    image = QImage()
    if not image.load(filename):
      return False
```
1 書式の修正

teamikl

teamikl score 2623

2020/05/23 14:41  投稿

> なぜかpredictcanvasだけ表示されません
複数の問題があります
- predictcanvas が表示されない (画面中央の領域)
 paintEvent がない
- 読み込んだ画像が反映されない (ファイル選択時のイベント)
 ToolFrame 内で別の PredictCanvas() を生成?
----
まず、表示されていますが、表示するものが何もない状態です。
- QImageを準備しているが、サイズが 0
- QImageは準備されただけで、何処にも描画されてない
 Canvas クラスと同様に paintEvent メソッドを実装しましょう。
----
次に、ファイルを選択したときの挙動ですが
画面中央に表示されているのは、MainWindowのpredict
ToolFrameのon_run()で呼び出しているのは、
ToolFrame内で生成されたPredictCanvas()と、それぞれ異なるものです。
メインウィンドウ側のpredict canvas のメソッドを呼び出すことで
問題自体は解決できますが、親ウィジェットを辿ってアクセスするのは、
クラスの利便性を損なうので、あまりお勧めしません。
Qtのシグナル/スロットを使った解消法を提案
- (1) ToolFrame でファイル選択時のシグナルを定義します
 fileSelected = pyqtSignal(str)
 `fileSelected = pyqtSignal(str)`
- (2) PredictCanvas 側で、ファイルを読み込むスロットを定義します
 @pyqtSlot ... def loadImage(self, filename)
 `@pyqtSlot` ... `def loadImage(self, filename)`
- (3) MainWindow で双方を接続する
 `tools.fileSelected.connect(predict.loadImage)`
- (4) シグナル発火
 ToolFrame.on_run メソッド内 で self.fileSelected.emit(filename)
 ToolFrame.on_run メソッド内 で `self.fileSelected.emit(filename)`
 
PyQt5 でのシグナル/スロットの使い方は
[PyQt5 signals_slots](https://doc.bccnsoft.com/docs/PyQt5/signals_slots.html) 等を参考に、コードの書き方は調べて下さい。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る