【PyQt6】各QWidgetの設定をYAMLファイルに記述する

はじめに

ボタンやラベルのサイズやフォントの設定をメインファイルに記述するとスクリプトが冗長になります。

別ファイル(YAMLファイル)に記述できるようにしました。

今回やること

以前に英単語暗記のためのアプリを作りました。こちらを新たに書き直しました。
touch-sp.hatenablog.com
まずは「constructGUI.py」というファイルを作成する必要があります。


これは指定されたYAMLファイルを読み込んで各QWidgetに設定を追加するためのスクリプトです。


とりあえずQLabelとQPushButtonの基本的な設定を追加できるようにしています。

from PyQt6.QtCore import Qt, QSize
from PyQt6.QtGui import QFont

import yaml

def construct(x, yaml_file, settings):

    with open(yaml_file, 'r') as f:
        yaml_data = yaml.load(f, Loader=yaml.SafeLoader)

    if settings in yaml_data.keys():

        settings_dict = yaml_data[settings]

        if settings_dict['type'] == 'QLabel':
            
            ##サイズの設定
            if ('height' in settings_dict.keys() and 'width' in settings_dict.keys()):

                h = settings_dict['height']
                w = settings_dict['width']

                x.setFixedSize(QSize(w, h))
            ##サイズの設定

            ##fontの設定
            font = QFont()

            if 'fontFamily' in settings_dict.keys():
                font.setFamily(settings_dict['fontFamily'])

            if 'fontPoint' in settings_dict.keys():
                font.setPointSize(settings_dict['fontPoint'])

            if 'fontBold' in settings_dict.keys():
                font.setBold(settings_dict['fontBold'])
                    
            x.setFont(font)
            ##fontの設定

            ##テキストの設定
            if 'text' in settings_dict.keys():
                x.setText(settings_dict['text'])
            ##テキストの設定

            ##アライメントの設定
            if 'alignment' in settings_dict.keys():

                alignment_str = settings_dict['alignment']

                if alignment_str == 'center':
                    x.setAlignment(Qt.AlignmentFlag.AlignCenter)
                
                elif alignment_str == 'right':
                    x.setAlignment(Qt.AlignmentFlag.AlignRight)

                elif alignment_str == 'right':
                    x.setAlignment(Qt.AlignmentFlag.AlignLeft)
            ##アライメントの設定
        
        elif settings_dict['type'] == 'QPushButton':
            
            ##サイズの設定
            if ('height' in settings_dict.keys() and 'width' in settings_dict.keys()):

                h = settings_dict['height']
                w = settings_dict['width']

                x.setFixedSize(QSize(w, h))
            ##サイズの設定

            ##fontの設定
            font = QFont()

            if 'fontFamily' in settings_dict.keys():
                font.setFamily(settings_dict['fontFamily'])

            if 'fontPoint' in settings_dict.keys():
                font.setPointSize(settings_dict['fontPoint'])

            if 'fontBold' in settings_dict.keys():
                font.setBold(settings_dict['fontBold'])
                    
            x.setFont(font)
            ##fontの設定

            ##テキストの設定
            if 'text' in settings_dict.keys():
                x.setText(settings_dict['text'])
            ##テキストの設定

    return x

実際のPythonスクリプトとYAMLファイル

YAMLファイル

「settings.yaml」という名前で保存して下さい。

label_1:
  type: QLabel
  alignment: center
  fontFamily: times
  fontPoint: 40
  fontBold: True

Pythonファイル

冒頭のコメントアウトされた部分は「constructGUI.py」をGitHubページからダウンロードするためのスクリプトになります。
最新のものがダウンロードされます。

'''
import os
from urllib.request import urlretrieve

url = 'https://raw.githubusercontent.com/dai-ichiro/pyqt6_yaml/main/constructGUI.py'
fname = os.path.basename(url)

if not os.path.isfile(fname):
    urlretrieve(url, fname)
'''

from PyQt6.QtWidgets import QWidget, QApplication, QLabel, QVBoxLayout
from PyQt6.QtCore import Qt, QSize
import pickle
import random
from constructGUI import construct

with open('words_dict.pkl', 'rb') as f:
    words_dict = pickle.load(f)

dict_keys = words_dict.keys()

class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.question = ''
        self.new_question = True
        
    def initUI(self):
        self.setWindowTitle("単語帳")
        self.setFixedSize(QSize(400, 200))

        self.label_q = construct(QLabel(), 'settings.yaml', 'label_1')
        self.label_a = construct(QLabel(), 'settings.yaml', 'label_1')
        
        layout = QVBoxLayout()
        layout.addWidget(self.label_q)
        layout.addWidget(self.label_a)
        
        self.setLayout(layout)
    
    def keyPressEvent(self, e):
        
        if e.key() == Qt.Key.Key_Return:
            if self.new_question == True:
                self.label_a.clear()
                self.question = random.choice(list(dict_keys))
                self.label_q.setText(self.question)
                self.new_question = False
            else:
                self.label_a.setText(', '.join(words_dict[self.question]))
                self.new_question = True

if __name__ == "__main__":
    app = QApplication([])
    ex =Window()
    ex.show()
    app.exec()

英単語アプリを使用する前に英単語データのダウンロードが必要です。

こちらのスクリプトでダウンロード可能です。

ダウンロードしてpickle保存してくれます。

import pandas as pd

url = 'https://touch-sp.hatenablog.com/entry/2021/03/07/234555'
dfs = pd.read_html(url, encoding='utf-8')
df = dfs[0]

df = df.drop_duplicates()

words_list = list(df['英単語'].unique())

words_dict = {}
for word in words_list:
    words_dict[word] = list(df[df['英単語']==word]['意味'])

import pickle

with open('words_dict.pkl', 'wb') as f:
    pickle.dump(words_dict, f)

動作画面


2022年4月19日追記(For Python 3.10)

Python 3.10を使ってスクリプトを書き換えました。
touch-sp.hatenablog.com