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

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

ただいまの
回答率

87.35%

[pyqt5-python] レイアウトを構成できない:TypeError: argument 1 has unexpected type 'QVBoxLayout'

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,035

score 20

pyqt5で簡単なお絵描きツール作成をしています。

下図のようなレイアウトを目標としコーディングしましたが、

TypeError: addWidget(self, QWidget, stretch: int = 0, alignment: Union[Qt.Alignment, Qt.AlignmentFlag] = Qt.Alignment()): argument 1 has unexpected type 'QVBoxLayout'

というエラーが吐かれました。
QhboxlayoutにQvboxlayoutを代入していることが原因だと思われますが
検索してもこれと言った解決方法が見当たりませんでした。

原因と解決をご教授お願いしたいです。よろしくお願いいたします。

環境:Pyhton3 windows10
(コードが長すぎるため関係のないであろう箇所は割愛しています)

レイアウトイメージ

Traceback (most recent call last):
  File "paint.py", line 384, in <module>
    main()
  File "paint.py", line 377, in main
    ex = MainWindow()
  File "paint.py", line 31, in __init__
    self.setCentralWidget(self.initUI())
  File "paint.py", line 56, in initUI
    hbox.addWidget(layoutA)
TypeError: addWidget(self, QWidget, stretch: int = 0, alignment: Union[Qt.Alignment, Qt.AlignmentFlag] = Qt.Alignment()): argument 1 has unexpected type 'QVBoxLayout'
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPainter, QImage, QPen, qRgb
from PyQt5.QtCore import Qt, QPoint, QRect, QSize, QDir
from PyQt5.QtCore import pyqtSlot, pyqtSignal,Qt, QTimer
from PyQt5.QtGui import QIcon
from collections import deque
from PyQt5 import QtCore

import os
import time
import concurrent.futures
import threading
import torch
import datetime
from parameter import *
from data_loader import Data_Loader

import torch.nn as nn
from torch.autograd import Variable
from torchvision.utils import save_image

from sagan_models import Generator, Encoder
from utils import *


class MainWindow(QMainWindow):
  def __init__(self):
    super(MainWindow, self).__init__()
    self.setupUI()
    self.setCentralWidget(self.initUI())
    #クラスを呼び出す。

  def initUI(self):
        #self.fileName= './test/test/aa.png'
        self.predict_res_fileName= './result/fake.png'

        frame = QWidget(self)

        self.canvas = Canvas(frame)
        self.predict_canvas=PredictCanvas(frame)
        tools = ToolFrame(frame, canvas=self.canvas,predict_canvas=self.predict_canvas)

        layoutA = QVBoxLayout()
        layoutA.addWidget(self.predict_canvas)
        layoutA.addWidget(self.predict_canvas)
        layoutA.addWidget(self.predict_canvas)


        hbox = QHBoxLayout(frame)

        hbox.addWidget(self.canvas)


        hbox.addWidget(tools)

#------------------該当箇所---------------------------------------------
        hbox.addWidget(layoutA)
#------------------該当箇所---------------------------------------------


        frame.setLayout(hbox)

        return frame

  def setupUI(self):
    menubar = self.menuBar()
    self.prevTime=0.0
    exitAct = QAction('&Exit', self)
    exitAct.setShortcut('Ctrl+Q')
    exitAct.triggered.connect(self.close)

    saveAct = QAction('&Save', self)
    saveAct.setShortcut('Ctrl+S')
    saveAct.triggered.connect(self.saveFile)

    fileMenu = menubar.addMenu('&File')
    #fileMenu.addAction(resetAct)
    #fileMenu.addAction(openAct)
    fileMenu.addAction(saveAct)
    fileMenu.addAction(exitAct)

    # 画像付き Pencolor selectするアクションオブジェクト作成
    selectEraserAction = QAction( QIcon('./sample/qicon/eraser.png'),'Eraser', self)
    selectEraserAction.triggered.connect(self.selectEraser)
    self.toolbar = self.addToolBar('Eraser')
    self.toolbar.addAction(selectEraserAction)

    # 画像付き Pencolor selectするアクションオブジェクト作成
    selectPenAction = QAction( QIcon('./sample/qicon/pen.png'),'Pen', self)
    selectPenAction.triggered.connect(self.selectPen)
    self.toolbar = self.addToolBar('Pen')
    self.toolbar.addAction(selectPenAction)

    # ツールバー作成
    selectwidthAction = QAction(QIcon('./sample/qicon/width.png'), 'Selecwidth', self)
    selectwidthAction.triggered.connect(self.selectWidth)
    self.toolbar = self.addToolBar('Width')
    self.toolbar.addAction(selectwidthAction)


    # ツールバー作成
    selectcolorAction = QAction(QIcon('./sample/qicon/select_color.png'), 'Selectcolor', self)
    selectcolorAction.triggered.connect(self.selectColor)
    self.toolbar = self.addToolBar('Width')
    self.toolbar.addAction(selectcolorAction)

    # ツールバー作成
    backAction = QAction( QIcon('./sample/qicon/undo.png'),'Back', self)
    backAction.setShortcut('Ctrl+Z')
    backAction.triggered.connect(self.on_back)
    self.toolbar = self.addToolBar('Undo')
    self.toolbar.addAction(backAction)

    # ツールバー作成
    clearAction = QAction( QIcon('./sample/qicon/clear.png'),'Clear', self)
    clearAction.setShortcut('Ctrl+B')
    clearAction.triggered.connect(self.on_reset)
    self.toolbar = self.addToolBar('Undo')
    self.toolbar.addAction(clearAction) 

  def on_back(self):
    print('PyQt5 button click')
    self.canvas.backImage()

  def on_reset(self):
    self.canvas.resetImage()

  def selectEraser(self):
    self.canvas.setPenColor(newColor=Qt.white)

  def selectPen(self):
    self.canvas.setPenWidth(newWidth=5)
    self.canvas.setPenColor(newColor=Qt.black)

  def selectColor(self):
    self.canvas.setPenWidth(newWidth=5)
    newColor = QColorDialog.getColor(self.canvas.penColor())
    self.canvas.setPenColor(newColor)

  def selectWidth(self):
    newWidth, ok = QInputDialog.getInt(
      self, "select",
      "select pen width: ", self.canvas.penWidth(), 1, 100, 1)
    if ok:
      self.canvas.setPenWidth(newWidth)



class ToolFrame(QWidget):
    def __init__(self, parent=None, canvas=None, predict_canvas=None):
        super().__init__(parent)
        self.predict = predict_canvas
        self.canvas = canvas 
        #self.tester=Tester()
        self.initUI()
        self.predict_res_filename="./result/fake.png"
        self.fileName='./test/test/aa.png'

    def initUI(self):
        button_predict = QPushButton('predict', self)
        button_predict.clicked.connect(self.on_run)

        button_apply = QPushButton('Apply', self)
        button_apply.clicked.connect(self.on_apply)

        vbox = QVBoxLayout(self)
        vbox.addStretch(1)
        vbox.addWidget(button_predict)
        vbox.addWidget(button_apply)

    @pyqtSlot()
    def on_run(self):
      #canvasのimageをセーブ
      self.canvas.saveImage()
      #上記のセーブしたimageをpredict_canvasに出力
      #self.tester.test_main()

      self.predict.PredictImage()


class Canvas(QWidget):
  def __init__(self, parent = None):
    super(Canvas, self).__init__(parent)

    self.myPenWidth = 2
    self.myPenColor = Qt.black
    self.image = QImage()
    self.check = False
    self.check_write = False
    self.back = deque(maxlen = 10)
    self.image = QImage(255, 255, QImage.Format_RGB32)
    self.image.fill(qRgb(255, 255, 255))
    self.filename='./test/test/aa.png'
    self.predict_res_filename='./result/fake.png'

  def mousePressEvent(self, event):
    if event.button() == Qt.LeftButton:
      self.check_write = True
      self.back.append(self.resizeImage(self.image, self.image.size()))
      self.lastPos = event.pos()
      self.check = True

  def mouseMoveEvent(self, event):
    if event.buttons() and Qt.LeftButton and self.check:
      self.drawLine(event.pos())

  def mouseReleaseEvent(self, event):
    if event.button() == Qt.LeftButton and self.check:
      self.drawLine(event.pos()) 
      self.check = False
      self.check_write = False

  def drawLine(self, endPos):
    painter = QPainter(self.image)
    painter.setPen(
      QPen(self.myPenColor, self.myPenWidth, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
    )
    painter.drawLine(self.lastPos, endPos)
    self.update()
    self.lastPos = QPoint(endPos)

  def paintEvent(self, event):
    painter = QPainter(self)
    rect = event.rect()
    painter.drawImage(rect, self.image, rect)

  def resizeImage(self, image, newSize):
    changeImage = QImage(newSize, QImage.Format_RGB32)
    changeImage.fill(qRgb(255, 255, 255))
    painter = QPainter(changeImage)
    painter.drawImage(QPoint(0, 0), image)
    return changeImage

class PredictCanvas(QWidget):
  def __init__(self, parent = None):
    super(PredictCanvas, self).__init__(parent)

    self.image_predict = QImage()
    self.image_predict = QImage(255, 255, QImage.Format_RGB32)
    self.image_predict.fill(qRgb(255*0.9, 255*0.9, 255*0.9))
    self.predict_res_filename='./result/fake.png'

  def PredictImage(self):
    image = QImage()
    if not image.load('./result/fake.png'):

      return False

    self.image_predict = image
    print("pre_canvas")
    self.update()
    return True

  def paintEvent(self, event):
    painter = QPainter(self)
    rect = event.rect()
    painter.drawImage(rect, self.image_predict, rect)

def main():
  app = QApplication(sys.argv)
  ex = MainWindow()
  ex.setWindowTitle('Paint Tools')
  ex.setGeometry(50, 50, 1500, 1000)
  ex.show()
  sys.exit(app.exec_())

if __name__ == '__main__':
  main()
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

レイアウトの配置には addLayout を使います

hbox.addLayout(layoutA)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/05 18:08

    解決しました。毎回ありがとうございます。
    もう一つ質問したいのですが
    layoutA = QVBoxLayout()
    layoutA.addWidget(self.predict_canvas)
    layoutA.addWidget(self.predict_canvas)
    layoutA.addWidget(self.predict_canvas)
    の部分を
       layoutA = QGridLayout()
    layoutA.addWidget(self.predict_canvas,0,0)
    layoutA.addWidget(self.predict_canvas,0,1)
    layoutA.addWidget(self.predict_canvas,1,0)
    layoutA.addWidget(self.predict_canvas,1,1)
    として実行したところ、predict_canvasが一枚しか表示されませんでした。
    おそらく重なっているのでしょうが、何故なのでしょうか・・・
    ご教授頂けると幸いです

    キャンセル

  • 2020/06/05 18:20

    これは、同じウィジェットを複数回配置してるという事ですか?
    もし複数枚のキャンバスを表示させたい場合、個別に複数作る必要があります。

    キャンセル

  • 2020/06/05 18:23 編集

    その前に確認ですが、試したことはなかった。
    QVBoxLayout では3枚のキャンバスが表示されてたのでしょうか?

    訂正: その前の addWidget(layout) でエラーになってたのですね。
    回答は上の通りです。

    キャンセル

  • 2020/06/05 21:59 編集

    addlayoutとして修正したところ、QvBoxでは縦に三枚表示できました。

    また、最終的には異なるcanvasを9枚程度表示させようと考えています。
    なので、試験段階として上記のQGridLayout()を試しました。

    異なるcanvasなら、格子状に配置できるのであれば問題なさそうです。
    まだまだ足りていない部分が多いので、色々勉強してみます。ご回答ありがとうございました。

    キャンセル

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

  • ただいまの回答率 87.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る