maya PySide レイアウトを作ってみよう

GUI作成

こんにちは!ビーバー@ゲーム業界歴約20年python勉強中 です。
maya python初心者の方のために、カンタン・わかりやすい解説サイトを作っています。

PySideでGUI作成を学習しようとすると、
突然クラスやら知らない用語が大量に出てきて、、、とても難しそうに感じますよね。

この記事は、「PySideでGUIをつくってみよう」のシリーズ記事で、
今回はレイアウトの作成方法について解説していきます。

このチュートリアルでわかること
  • ウィンドウにレイアウトを追加する方法
  • 縦にならべるレイアウトのつくりかた
  • 横にならべるレイアウトのつくりかた
  • 縦横レイアウトを組み合わせる方法

私がPySideを勉強しながらわかったことをまとめていくので、
初心者の方にも理解しやすい内容になっていると思います。

それではGO☆

※今回の内容は、こちらの書籍を参考に書いています。

※当サイトで紹介する商品は、アフィリエイトプログラムを利用しています。

このチュートリアルでやること

  • レイアウトを追加してみる
  • 横にならべるレイアウトをつくってみる
  • 縦にならべるレイアウトをつくってみる
  • 縦横レイアウトを組み合わせてみる

maya2020、PySide2を使う前提で解説していきます。

レイアウトを追加してみる

ウィンドウに、ボタンやテキストなどの要素を配置するには、レイアウトという機能を使います。
レイアウトには、要素をたてにならべる・よこにならべる・重ねて並べるなどがあります。

レイアウトは、空のウィジェットを作成して、その中に配置して使います。
ためしに、ウィンドウの中にレイアウトを配置し、レイアウトの中に
赤一色にぬられたウィジェットを表示してみましょう。

from PySide2.QtWidgets import QMainWindow,QWidget,QVBoxLayout

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        
        widget1 = QWidget()
        widget1.setStyleSheet("background-color:red")

        layout = QVBoxLayout()
        layout.addWidget(widget1)
   
        widget = QWidget()
        widget.setLayout(layout)

        self.setCentralWidget(widget)        

        
window = MainWindow()
window.show()

スクリプトを実行すると、下図のウィンドウができます。

ピヨちゃん
ピヨちゃん

おっ?!グレー枠の中に赤い四角がでた?

ハムちゃん
ハムちゃん

図で詳しく解説するね!

ウィンドウは、次のようにできています。

MainWindowwidgetが入っており、widgetの中にはレイアウトが入っています。
レイアウトには赤一色に塗ったwidget1が入っている構成です。

スクリプトを解説します。

1行目、PySideの機能をインポート。「QVBoxLayout」は縦にならべるレイアウトの機能です。

from PySide2.QtWidgets import QMainWindow,QWidget,QVBoxLayout

MainWindowを作るクラスを宣言します。

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

赤一色に塗ったwidget1を作成します。

        widget1 = QWidget()
        widget1.setStyleSheet("background-color:red")

レイアウトを作成し、widget1をレイアウトの中に入れます。

        layout = QVBoxLayout()
        layout.addWidget(widget1)

widgetを作り、レイアウトを入れます。また、widgetをウィンドウの中央に配置します。

        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)        

クラスの設計をもとに、MainWindowを表示します。

window = MainWindow()
window.show()
ハムちゃん
ハムちゃん

MainWindow > widget > layout > widget1 っていう関係だね!

QVBoxLayoutで縦のレイアウトをつくろう

それでは、要素がいくつか並んだ「縦のレイアウト」を作ってみましょう。
レイアウトに含めるwidget1~3を作って、QVBoxLayoutに追加します。
widget1~3の色は、赤、黄、青色にしてみます。

from PySide2.QtWidgets import QMainWindow,QWidget,QVBoxLayout

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        
        widget1 = QWidget()
        widget1.setStyleSheet("background-color:red")
        widget2 = QWidget()
        widget2.setStyleSheet("background-color:yellow")
        widget3 = QWidget()
        widget3.setStyleSheet("background-color:blue")

        layout = QVBoxLayout()
        layout.addWidget(widget1)
        layout.addWidget(widget2)
        layout.addWidget(widget3)        
   
        widget = QWidget()
        widget.setLayout(layout)

        self.setCentralWidget(widget)        

        
window = MainWindow()
window.show()

この通り、QVBoxLayoutは要素を縦にならべていくことができます。

ハムちゃん
ハムちゃん

QVBoxLayoutの「V」は、vertical、つまり垂直方向にならぶってことだよ!
並べ方は、widgetを追加するだけだからカンタンだね。

QHBoxLayoutで横のレイアウトをつくろう

レイアウトの横バージョンも作ってみましょう。
横方向に要素をならべるレイアウトは、「QHBoxLayout」を使います。

from PySide2.QtWidgets import QMainWindow,QWidget,QHBoxLayout

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        
        widget1 = QWidget()
        widget1.setStyleSheet("background-color:red")
        widget2 = QWidget()
        widget2.setStyleSheet("background-color:yellow")
        widget3 = QWidget()
        widget3.setStyleSheet("background-color:blue")

        layout = QHBoxLayout()
        layout.addWidget(widget1)
        layout.addWidget(widget2)
        layout.addWidget(widget3)        
   
        widget = QWidget()
        widget.setLayout(layout)

        self.setCentralWidget(widget)        

        
window = MainWindow()
window.show()

縦にならべるレイアウトの、「QV」を、「QH」に変えただけです。

ピヨちゃん
ピヨちゃん

QHBoxLayoutの「H」は、horizontality 水平ってことだね!

レイアウトを組み合わせて使おう

レイアウトは、横レイアウトの中に縦レイアウトを入れ子にする、など
くみあわせて使うことができます。

例えば、図のようなウィンドウ。。

縦横レイアウトを作ったときと同様の書き方をしても良いのですが、
widgetの数が増えてくるとスクリプトが煩雑になりがちです。

from PySide2.QtWidgets import QMainWindow,QWidget,QHBoxLayout,QVBoxLayout

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        
        widget1a = QWidget()
        widget1a.setStyleSheet("background-color:red")
        widget1b = QWidget()
        widget1b.setStyleSheet("background-color:orange")
        
        widget2 = QWidget()
        widget2.setStyleSheet("background-color:yellow")

        widget3a = QWidget()
        widget3a.setStyleSheet("background-color:blue")
        widget3b = QWidget()
        widget3b.setStyleSheet("background-color:green")

        leftLayout = QVBoxLayout()
        leftLayout.addWidget(widget1a)     
        leftLayout.addWidget(widget1b)   
        
        centralLayout = QVBoxLayout()
        centralLayout.addWidget(widget2)   
        
        rightLayout = QVBoxLayout()
        rightLayout.addWidget(widget3a)     
        rightLayout.addWidget(widget3b)
            
        leftWidget = QWidget()
        leftWidget.setLayout(leftLayout)

        centralWidget = QWidget()
        centralWidget.setLayout(centralLayout)
        
        rightWidget = QWidget()
        rightWidget.setLayout(rightLayout)
        
        
        allLayout = QHBoxLayout()
        
        allLayout.addWidget(leftWidget)
        allLayout.addWidget(centralWidget)
        allLayout.addWidget(rightWidget)   
              
   
        wholeWidget = QWidget()
        wholeWidget.setLayout(allLayout)

        self.setCentralWidget(wholeWidget)        

        
window = MainWindow()
window.show()

同じような記述を何度もしなくてよいように、
「widgetを作って、指定の色にぬる」という機能を1行で呼び出せるようにまとめてみましょう。

今回は、ColorWidgetというサブクラスを作って、
ColorWidget(“色名”)の1行で、色のついたwidgetを作れるようにしてみます。

from PySide2.QtWidgets import QWidget,QMainWindow,QVBoxLayout,QHBoxLayout

class ColorWidget(QWidget):
    def __init__(self, color):
        super(ColorWidget, self).__init__()
        self.setAutoFillBackground(True)

        palette = self.palette()
        palette.setColor(self.backgroundRole(), color)
        self.setPalette(palette)

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        wholeLayout = QHBoxLayout()
        leftLayout = QVBoxLayout()
        centralLayout = QVBoxLayout()
        rightLayout = QVBoxLayout()

        widget1 = ColorWidget("red")
        widget2 = ColorWidget("orange")
        widget3 = ColorWidget("yellow")
        widget4 = ColorWidget("blue")
        widget5 = ColorWidget("green")
        
        wholeLayout.addLayout(leftLayout)
        wholeLayout.addLayout(centralLayout)
        wholeLayout.addLayout(rightLayout)
        
        leftLayout.addWidget(widget1)
        leftLayout.addWidget(widget2)
        centralLayout.addWidget(widget3)
        rightLayout.addWidget(widget4)       
        rightLayout.addWidget(widget5)
       
        wholeWidget = QWidget()
        wholeWidget.setLayout(wholeLayout)
        self.setCentralWidget(wholeWidget)

window = MainWindow()
window.show()

1~10行目でサブクラスColorWidgetを宣言し、
12行目以降で入れ子レイアウトのMainWindowを宣言しています。

MainWindowクラスで作成されるウィンドウの構造は、図のようになります。

レイアウトの入れ子構造を作っている部分を見ていきましょう。
MainWindowのクラスでは、16~25行目でレイアウトと色付きwidgetをまとめて作成しています。

        wholeLayout = QHBoxLayout()
        leftLayout = QVBoxLayout()
        centralLayout = QVBoxLayout()
        rightLayout = QVBoxLayout()

        widget1 = ColorWidget("red")
        widget2 = ColorWidget("orange")
        widget3 = ColorWidget("yellow")
        widget4 = ColorWidget("blue")
        widget5 = ColorWidget("green")

27~29行目で、全体のレイアウト(wholeLayout)に、左・右・真ん中のレイアウトを追加し

        wholeLayout.addLayout(leftLayout)
        wholeLayout.addLayout(centralLayout)
        wholeLayout.addLayout(rightLayout)

31~35行目で、左・右・真ん中のレイアウトに色付きウィジェットを追加しています。

        leftLayout.addWidget(widget1)
        leftLayout.addWidget(widget2)
        centralLayout.addWidget(widget3)
        rightLayout.addWidget(widget4)       
        rightLayout.addWidget(widget5)

最後に、全体のレイアウト(wholeLayout)を入れる wholeWidget を作成し、
wholeWidgetをウィンドウ中央に配置して完成です!

        wholeWidget = QWidget()
        wholeWidget.setLayout(wholeLayout)
        self.setCentralWidget(wholeWidget)
ピヨちゃん
ピヨちゃん

スクリプトが読みやすくなったね。これがサブクラスの威力か~!

ハムちゃん
ハムちゃん

ずいぶんわかりやすくなったでしょう?
次は、機能を切り離したColorWidgetクラスについて詳しく見ていこう!

機能をサブクラスにまとめる

「widgetを作って、指定の色にぬる」という機能をまとめた、ColorWidgetクラスを解説します。
ColorWidgetクラスはwidgetを作るクラスなので、QWidgetの機能を引き継いで作ります。

from PySide2.QtWidgets import QWidget

class ColorWidget(QWidget):
    def __init__(self, color):
        super(ColorWidget, self).__init__()
        self.setAutoFillBackground(True)

        palette = self.palette()
        palette.setColor(self.backgroundRole(), color)
        self.setPalette(palette)

1行目、QWidgetの機能をインポートし、
3行目、QWidgetを継承するColorWidgetクラスを宣言します。

from PySide2.QtWidgets import QWidget

class ColorWidget(QWidget):

次に、新しいウィジェットを作るときに、自由に色の指定ができるように
コンストラクタの第2引数にcolor変数を入れます。

    def __init__(self, color):

super()関数は、QWidgetの機能を引き継ぐためのおまじないです。
setAutoFillBackgroundでは、ウィジェット作る際に背景色をぬりつぶす、という指定をしています。

        super(ColorWidget, self).__init__()
        self.setAutoFillBackground(True)

そのあと、paletteという変数に
これから作るウィジェットの「色制御をする機能」を代入して、

        palette = self.palette()

paletteのなかの「色制御をする機能」に対して、
「color変数で指定した色にぬりつぶす」ように指定しています。

        palette.setColor(self.backgroundRole(), color)

最後に、指定の色にぬりつぶした情報をウィジェットにセットしています。

        self.setPalette(palette)

以上の10行で、「widgetを作って、指定の色にぬる」ColorWidgetクラスが完成です。

ColorWidgetクラスを、MainWindowクラスから呼び出して使ってみましょう。
スクリプトを単純にするために、レイアウトをもたないウィジェットだけのウィンドウを作成します。

from PySide2.QtWidgets import QWidget,QMainWindow

class ColorWidget(QWidget):
    def __init__(self, color):
        super(ColorWidget, self).__init__()
        self.setAutoFillBackground(True)

        palette = self.palette()
        palette.setColor(self.backgroundRole(), color)
        self.setPalette(palette)

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow,self).__init__()
        
        widget = ColorWidget("lightblue")
        self.setCentralWidget(widget)
        
window = MainWindow()
window.show()

単色でぬられたウィジェットだけが入った、MainWindowが作成できました!

ピヨちゃん
ピヨちゃん

この例みたいに、ぬりつぶしエリアにグレーの枠がないのは、
レイアウトがないからだね。

まとめ

今回は、PySideのレイアウト機能を解説しました。
ポイントをおさらいしましょう。

レイアウトの作成
  • レイアウトは空のwidgetに入れて使う
  • 縦にならべるレイアウトは、QVBoxLayout
  • 横に並べるレイアウトはQHBoxLayoutを使う
  • レイアウトは、入れ子にして組み合わせることもできる
  • 特定の機能をサブクラスにまとめると便利

PySideには、このほかにもグリッド上にならべるレイアウトや、
重ねるレイアウト(たぶきりかえのようなもの)もあります。

興味を持たれた方は、下記の書籍も読んでみてください。
サンプルで読めるページ数も多く、解説とても分かりやすいです。

また、このサイトのGUI作成ページでは、
初心者向けのチュートリアル&学習情報をまとめていますので、ぜひ見てみてくださいね!

maya pythonでGUIを作ろう!

maya pythonでGUIを作る方法をもっと知りたい方はこちら。

cmdsで作る方法・PySideの紹介・PySideのかんたんなチュートリアルをまとめています。
PySideを使うときに必要になる、「クラス」についても徹底解説!

コメント

タイトルとURLをコピーしました