はじめに
以前同じことをやりました。touch-sp.hatenablog.com
今回、Python 3.10から導入されたパターンマッチ(「match」「case」)を使ってスクリプトを書き換えました。
結果&考察
「PyYAML」でYAMLファイルを読み込むとデータが辞書型変数に格納されます。そして「match」「case」は辞書型変数に対しても使えます。つまり何が伝えたかったかというと、「PyYAML」とパターンマッチ(「match」「case」)の相性が良過ぎて幸せな気持ちになれるということです。幸せになる使い方
match settings_dict: case {'height': height, 'width': width}: self.setFixedSize(QSize(width, height))
解説すると、
「settings_dict」という辞書型変数に「'height'」というキーは存在しますか?
存在するならその値を「height」という変数に格納して下さい。
同様に
「settings_dict」という辞書型変数に「'width'」というキーは存在しますか?
存在するならその値を「width」という変数に格納して下さい。
そして
「height」と「width」がともに値をもつ場合に限り「setFixedSize」を実行して下さい。
このようになります。
どうですか、非常に簡潔にかけて幸せになりませんか?
ちなみに従来通りに書くとこのようになると思います。
height = settings_dict.get('height') width = settings_dict.get('width') if height is not None and width is not None: self.setFixedSize(QSize(width, height))
4行が3行になっただけですが私は非常に感動しました。みなさんはどうでしょう?
もう一つ例を示します。
従来通りに書く場合
orientation = settings_dict.get('orientation') if orientation == 'h': self.setOrientation(Qt.Orientation.Horizontal) elif orientation == 'v': self.setOrientation(Qt.Orientation.Vertical)
パターンマッチを使った場合
match settings_dict.get('orientation'): case 'h': self.setOrientation(Qt.Orientation.Horizontal) case 'v': self.setOrientation(Qt.Orientation.Vertical)
余計な変数を作らなくて済みます。
Pythonスクリプト
from PyQt6.QtCore import Qt, QSize from PyQt6.QtWidgets import QLabel, QPushButton, QSlider, QFrame from PyQt6.QtGui import QFont import yaml class Label(QLabel): def __init__(self, fname = "", settings = ""): super().__init__() if not fname == "": with open(fname, 'r') as f: yaml_data = yaml.load(f, Loader=yaml.SafeLoader) settings_dict = yaml_data.get(settings) if settings_dict is not None: match settings_dict: case {'height': height, 'width': width}: self.setFixedSize(QSize(width, height)) font = QFont() match settings_dict: case {'fontFamily': fontFamily}: font.setFamily(fontFamily) match settings_dict: case {'fontPoint': fontPoint}: font.setPointSize(fontPoint) match settings_dict: case {'fontBold': fontBold}: font.setBold(fontBold) self.setFont(font) match settings_dict: case {'text': text}: self.setText(text) match settings_dict.get('alignment'): case 'center': self.setAlignment(Qt.AlignmentFlag.AlignCenter) case 'right': self.setAlignment(Qt.AlignmentFlag.AlignRight) case 'left': self.setAlignment(Qt.AlignmentFlag.AlignLeft) match settings_dict: case {'linewidth': linewidth}: self.setLineWidth(linewidth) match settings_dict: case {'shape': 'box', 'shadow': 'plain'}: self.setFrameStyle(QFrame.Shape.Box.value | QFrame.Shadow.Plain.value) case {'shape': 'box', 'shadow': 'raised'}: self.setFrameStyle(QFrame.Shape.Box.value | QFrame.Shadow.Raised.value) case {'shape': 'box', 'shadow': 'sunken'}: self.setFrameStyle(QFrame.Shape.Box.value | QFrame.Shadow.Sunken.value) case {'shape': 'panel', 'shadow': 'plain'}: self.setFrameStyle(QFrame.Shape.Panel.value | QFrame.Shadow.Plain.value) case {'shape': 'panel', 'shadow': 'raised'}: self.setFrameStyle(QFrame.Shape.Panel.value | QFrame.Shadow.Raised.value) case {'shape': 'panel', 'shadow': 'sunken'}: self.setFrameStyle(QFrame.Shape.Panel.value | QFrame.Shadow.Sunken.value) color_list = [] match settings_dict: case {'color': color}: color_list.append('color: %s'%color) match settings_dict: case {'background-color': background_color}: color_list.append('background-color: %s'%background_color) if len(color_list) > 0: self.setStyleSheet(';'.join(color_list)) class PushButton(QPushButton): def __init__(self, fname = "", settings = ""): super().__init__() if not fname == "": with open(fname, 'r') as f: yaml_data = yaml.load(f, Loader=yaml.SafeLoader) settings_dict = yaml_data.get(settings) if settings_dict is not None: match settings_dict: case {'height': height, 'width': width}: self.setFixedSize(QSize(width, height)) font = QFont() match settings_dict: case {'fontFamily': fontFamily}: font.setFamily(fontFamily) match settings_dict: case {'fontPoint': fontPoint}: font.setPointSize(fontPoint) match settings_dict: case {'fontBold': fontBold}: font.setBold(fontBold) self.setFont(font) match settings_dict: case {'text': text}: self.setText(text) class Slider(QSlider): def __init__(self, fname = "", settings = ""): super().__init__() if not fname == "": with open(fname, 'r') as f: yaml_data = yaml.load(f, Loader=yaml.SafeLoader) settings_dict = yaml_data.get(settings) if settings_dict is not None: match settings_dict: case {'height': height, 'width': width}: self.setFixedSize(QSize(width, height)) match settings_dict.get('orientation'): case 'h': self.setOrientation(Qt.Orientation.Horizontal) case 'v': self.setOrientation(Qt.Orientation.Vertical) match settings_dict: case {'max': max}: self.setMaximum(max) match settings_dict: case {'min': min}: self.setMinimum(min) match settings_dict: case {'default': default}: self.setValue(default) match settings_dict.get('tickposition'): case 'both': self.setTickPosition(QSlider.TickPosition.TicksBothSides) case 'above': self.setTickPosition(QSlider.TickPosition.TicksAbove) case 'below': self.setTickPosition(QSlider.TickPosition.TicksBelow) case 'left': self.setTickPosition(QSlider.TickPosition.TicksLeft) case 'right': self.setTickPosition(QSlider.TickPosition.TicksRight)
使用例
上のPythonファイルを「constructGUI2.py」、設定を書き込んだYAMLファイルを「settings.yml」という名前で保存した場合の例を示します。Pythonファイル
from PyQt6.QtWidgets import QWidget, QApplication, QVBoxLayout from constructGUI2 import Label class Window(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.label_1 = Label('settings.yml', 'label_1') self.label_2 = Label('settings.yml', 'label_2') layout = QVBoxLayout() layout.addWidget(self.label_1) layout.addWidget(self.label_2) self.setLayout(layout) if __name__ == "__main__": app = QApplication([]) ex =Window() ex.show() app.exec()
YAMLファイル
label_1: width: 300 height: 100 alignment: center fontFamily: times fontPoint: 40 fontBold: True linewidth: 10 shape: panel #(box or panel) shadow: raised #(plain or raised or sunken) text: start label_2: width: 300 height: 100 alignment: center fontFamily: times fontPoint: 40 fontBold: True linewidth: 10 shape: panel #(box or panel) shadow: sunken #(plain or raised or sunken) text: end
このようなものができます。