モチベーション
身の回りのありとあらゆる便利パッケージにGUIがあったらな,と思うことが多いためやり方をメモします。
初回はひとまず
- リストの複数を選択
- matplotlibの図をリストの選択に応じて表示
ができるようにします。
サンプルを通した理解
わかりやすいサンプルコードを介して理解を深めるのが手っ取り早いです。 今回の目的には下記の内容が大部分で合致しているので参考にしました。
配置
構造としてはまずはQwidgetというキャンバスを用意して,QVboxlayoutというコンテナの中にグラフのプロットであったり,チェックボックスであったり具体的な要素を詰めていくという構造をとります。(理解がUpdateされ次第Updateします。)
超最低限に書くと下記のようになります。
# 初期化のサンプル class Test(QtWidgets): # QWidgetを継承 def __init__(self): super().__init__() # 継承元のInit vbox = QtWidgets.QVBoxLayout(self) #Vboxlayoutの定義。縦にオブジェクトを並べる。(QHboxなら横に) vbox.addWidget( QtWidgets.QListWidget() ) # リスト表示Widgetを追加。 vbox.addWidget( QtWidgets.QLabel(self) ) # ラベルWidgetを追加。(テキスト設定していないからこの段階では無) # ...このように追加していって self.setLayout(vbox) # VboxlayoutをWidgetにはめ込む
他にオブジェクトを配置する手法としては最後の部分はsetGeometryなどでゴリゴリ配置しても良さそうですし,
# 配置 self.setGeometry(0,0,900,600) self.FigureWidget.setGeometry(200,0,700,600) self.FileList.setGeometry(0,0,200,600)
配置をこりたい人は,Qt Designer というGUIがあるのでそれでレイアウトを作ったほうがいいと思います。
自分は今はSplitterという機能を使って画面を分割して配置するようにしています。また次回にメモします。
イベントの設定
配置したオブジェクトたちにはイベントが起きたときにどうするかという設定をすることができます。
# インデント略 self.listWidget = QtWidgets.QListWidget() self.listWidget.itemClicked.connect(self.printItemText) #クリックされたらprintItemText関数を呼ぶ # 呼ばれる側の関数 def printItemText(self): # 選択したアイテムを表示 items = self.listWidget.selectedItems() x = [] for i in range(len(items)): x.append(str(self.listWidget.selectedItems()[i].text())) print (x)
実行
Qtにおいては、QApplicationというクラスがメインのアプリケーションを定義するので, 最後に作ったWidgetクラスを表示する際には下記のようにします。
#アプリケーション本体のインスタンスを作る app = QtWidgets.QApplication(sys.argv) #アプリケーションのインスタンスを作る Test.show() #作ったWidgetを表示する app.exec() #アプリケーションのメッセージループを開始する
小ネタ
大体のオブジェクトは配置してから初期設定などをする必要があります。 そうするとaddWidgetでの配置が見づらくなるので関数化して一行で表せるようにしたほうがはかどります。
ラベルテキスト追加
ラベルオブジェクトを配置するならこうします。
def add_label(self,text): # ラベルを作る label1=QtWidgets.QLabel(self) label1.setText(text) label1.adjustSize() return label1
リストでの複数選択
QListWidgetでSelectionModeを設定すると複数選択可能にできます。
毎回リセットするなら ExtendedSelection,トグルするなら MultiSelectionがおすすめです。 下記のように書きます。
self.listWidget = QtWidgets.QListWidget() self.listWidget.setSelectionMode( #複数選択可能にする https://doc.qt.io/qt-5/qabstractitemview.html QtWidgets.QAbstractItemView.MultiSelection # QtWidgets.QAbstractItemView.ExtendedSelection )
参考: QAbstractItemView Class | Qt Widgets 5.15.5
リストで番号を選択してPlotするサンプル
ということでリストで番号を選択してPlotするサンプルを下記に載せます。
# -*- coding: utf-8 -*- """ Stackoverflowの文章より原型を拝借 QtのListwidgetで複数選択をしてPlotする。 """ from PyQt5 import QtWidgets, QtCore import matplotlib.pyplot as plt from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas class Test(QtWidgets.QDialog): def __init__(self, parent=None): super(Test, self).__init__(parent) self.layout = QtWidgets.QVBoxLayout() # リスト作成 self.listWidget = QtWidgets.QListWidget() self.listWidget.setSelectionMode( #複数選択可能にする QtWidgets.QAbstractItemView.MultiSelection ) self.listWidget.setGeometry(QtCore.QRect(10, 10, 211, 291)) for i in range(10): item = QtWidgets.QListWidgetItem("%i" % i) self.listWidget.addItem(item) self.listWidget.itemClicked.connect(self.printItemText) # Figureを作成 self.Figure = plt.figure() self.FigureCanvas = FigureCanvas(self.Figure) # FigureをFigureCanvasに追加 self.axis = self.Figure.add_subplot(1,1,1) # axを持っておく self.layout.addWidget(self.add_label("Ctrlを押しながらで複数選択")) self.layout.addWidget(self.listWidget) self.layout.addWidget(self.FigureCanvas) self.setLayout(self.layout) def add_label(self,text): # ラベルを作る label1=QtWidgets.QLabel(self) label1.setText(text) label1.adjustSize() return label1 def printItemText(self): # 選択したアイテムを表示 items = self.listWidget.selectedItems() x = [] for i in range(len(items)): x.append(int(self.listWidget.selectedItems()[i].text())) print(x) self.update_Figure(x) # Figure def update_Figure(self,x): self.axis.cla() # リセットを掛ける必要がある。 self.axis.plot(x,'-o') plt.grid(); plt.legend(["selected number"]) self.FigureCanvas.draw() if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) form = Test() form.show() sys.exit(app.exec_())