PyQt5 を使って足し算の計算ドリルを作ってみた


PyQt5 で QLabel のグループ化 - パソコン関連もろもろ
PyQt5 を使って Arduino とシリアル通信 - パソコン関連もろもろ
PyQt5 で python-vlc を扱う - パソコン関連もろもろ
上記で習得したスキルを使って子供のための計算ドリルを作ってみた。

Pythonスクリプト

import os
os.chdir(os.path.join(os.getcwd(), 'sound'))

import vlc
import time
import random

import sys
from PyQt5 import QtCore, QtSerialPort
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QImage, QPixmap

############################################
max_num = 5
############################################

ql_x_position = (170, 410, 650, 170, 410, 650, 170, 410, 650)
qr_x_position = (1130, 1370, 1610, 1130, 1370, 1610, 1130, 1370, 1610)
q_y_position = (80, 80, 80, 240, 240, 240, 400, 400, 400)
a_x_position = (25, 175, 325, 475, 625, 775, 925, 1075, 1225, 1375, 25, 175, 325, 475, 625, 775, 925, 1075, 1225, 1375)
a_y_position = (740, 740, 740, 740, 740, 740, 740, 740, 740, 740, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890)

player = vlc.MediaListPlayer()
mediaList = vlc.MediaList(['dummy.wav'])
player.set_media_list(mediaList)
player.play()

class Window(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.question = True
        self.q1 = 0
        self.q2 = 0
        self.answer = 0
        self.button_ready = True
        self.serial = QtSerialPort.QSerialPort(
            'COM5', baudRate=QtSerialPort.QSerialPort.Baud9600, 
            readyRead = self.receive)
        self.serial.open(QtCore.QIODevice.ReadWrite)
        time.sleep(1.5)

    def initUI(self):

        self.label_list_left = [QLabel(self) for i in range(9)]
        self.label_list_right = [QLabel(self) for i in range(9)]
        
        for i in range(9):
            self.label_list_left[i].setGeometry(QtCore.QRect(ql_x_position[i], q_y_position[i], 140, 140))
        
        for i in range(9):
            self.label_list_right[i].setGeometry(QtCore.QRect(qr_x_position[i], q_y_position[i], 140, 140))

        self.label_answer = [QLabel(self) for i in range(20)]

        self.question_left_pic = QLabel(self)
        self.question_left_pic.setGeometry(QtCore.QRect(390, 540, 180, 180))

        self.question_right_pic = QLabel(self)
        self.question_right_pic.setGeometry(QtCore.QRect(1350, 540, 180, 180))

        self.purasu_pic = QLabel(self)
        self.purasu_pic.setGeometry(QtCore.QRect(870, 540, 180, 180))

        self.label_answer_pic = QLabel(self)
        self.label_answer_pic.setGeometry(QtCore.QRect(1625, 800, 180, 180))


        for i in range(20):
            self.label_answer[i].setGeometry(QtCore.QRect(a_x_position[i], a_y_position[i], 160, 160))

    def receive(self):

        #ボタンが無効なら何もしない
        if self.button_ready == False:

            dummy = self.serial.readAll()

        else:

            dummy = self.serial.readAll()

            #ボタンを無効にする
            self.button_ready = False

            if self.question == True:
            
                # 画像の消去
                for i in range(9):
                    self.label_list_left[i].clear()
                    self.label_list_right[i].clear()

                for i in range(20):
                    self.label_answer[i].clear()

                self.question_left_pic.clear()
                self.question_right_pic.clear()
                self.purasu_pic.clear()
                self.label_answer_pic.clear()

                # 問題の作成
                self.q1 = random.randint(1, max_num)
                self.q2 = random.randint(1, max_num)
                self.answer = self.q1 + self.q2

                # 画像の表示
                for i in range(self.q1):
                    self.label_list_left[i].setPixmap(QPixmap.fromImage(image))

                for i in range(self.q2):
                    self.label_list_right[i].setPixmap(QPixmap.fromImage(image))

                self.question_left_pic.setPixmap(QPixmap.fromImage(num_image[self.q1]))
                self.question_right_pic.setPixmap(QPixmap.fromImage(num_image[self.q2]))
                self.purasu_pic.setPixmap(QPixmap.fromImage(purasu_image))
                # 音の再生
                sound_list = []
                sound_list.append(str(self.q1) + '.wav')
                sound_list.append('dummy_short.wav')
                sound_list.append('tasu.wav')
                sound_list.append('dummy_short.wav')
                sound_list.append(str(self.q2) + '.wav')

                mediaList = vlc.MediaList(sound_list)
                player.set_media_list(mediaList)
                player.play()

                loop = QtCore.QEventLoop()
                QtCore.QTimer.singleShot(3000, loop.quit)
                loop.exec_()

                self.question = False

            else:

                # 画像の移動
                count = 0
                for i in range(0, self.q1):
                    self.label_list_left[i].clear()
                    self.label_answer[count].setPixmap(QPixmap.fromImage(image))

                    self.label_answer_pic.setPixmap(QPixmap.fromImage(num_image[count+1]))
                    
                    mediaList = vlc.MediaList([str(count+1)+'.wav'])
                    player.set_media_list(mediaList)
                    player.play()

                    
                    loop = QtCore.QEventLoop()
                    QtCore.QTimer.singleShot(1000, loop.quit)
                    loop.exec_()

                    count += 1

                for i in range(0, self.q2):
                    self.label_list_right[i].clear()
                    self.label_answer[count].setPixmap(QPixmap.fromImage(image))

                    self.label_answer_pic.setPixmap(QPixmap.fromImage(num_image[count+1]))

                    mediaList = vlc.MediaList([str(count+1)+'.wav'])
                    player.set_media_list(mediaList)
                    player.play()

                    loop = QtCore.QEventLoop()
                    QtCore.QTimer.singleShot(1000, loop.quit)
                    loop.exec_()

                    count += 1

                sound_list = []
                sound_list.append('dummy_short.wav')
                sound_list.append('seikai.wav')
                sound_list.append('dummy_short.wav')
                sound_list.append(str(self.answer) + '.wav')

                mediaList = vlc.MediaList(sound_list)
                player.set_media_list(mediaList)
                player.play()

                loop = QtCore.QEventLoop()
                QtCore.QTimer.singleShot(3000, loop.quit)
                loop.exec_()

                self.question = True
            
            #ボタンを有効に戻す
            self.button_ready = True

    def keyPressEvent(self, e):

        # エスケープキーを押すと画面が閉じる
        if e.key() == QtCore.Qt.Key_Escape:
            self.close()

image = QImage('donut.png').scaled(140,140,QtCore.Qt.KeepAspectRatio) 
num_image = [QImage('%d.png'%i).scaled(180,180,QtCore.Qt.KeepAspectRatio) for i in range(19)]
purasu_image = QImage('purasu.png').scaled(180,180,QtCore.Qt.KeepAspectRatio)

app = QApplication(sys.argv)
ex =Window()

ex.showFullScreen()
sys.exit(app.exec_())

Arduinoスケッチ

const int buttonON = LOW;    // ボタンが押されているとピンの値はLOW
const int buttonOFF = HIGH;  // ボタンが押されていないとピンの値はHIGH

const int buttonPin = 2;

int buttonState;

void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == buttonON) {     // ボタンが押されていたら
    Serial.write(255);  
    delay(1500);
  } 
}