【Python】マッチ棒クイズ開発 Part16

こんにちは、にわこまです。

今回は、縦に5つボタンを表示するレイアウトと正解不正解を表すポップアップ使用する図形を描画するクラスを作成します。

 

誤字脱字や分からない点がございましたらご連絡お願いいたします!

メールまたはTwitterのDMまで!!

 

 

 

スポンサードサーチ


縦に5つボタンを表示するレイアウト

実際にプレイする画面のレイアウトを以下に示します。このレイアウトには、問題文やマッチ棒を動かす範囲、回答ボタンなどを配置します。

  

今回作成する縦に5つボタンを表示するレイアウトは、上記の画像における薄い赤色の範囲のレイアウトです。

 

 

コードの提示

縦に5つボンタンを表示するレイアウトのソースコードを以下に示します。

import kivy
kivy.require("2.0.0")

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle, Ellipse
from kivy.graphics import Rotate
from kivy.graphics import Line
from kivy.graphics.context_instructions import PushMatrix, PopMatrix
from kivy.storage.jsonstore import JsonStore

from kivy.core.window import Window

import numpy as np
import random
import copy

class MatchStickWidget(Widget):
    # 省略

class MatchStickFrameWidget(Widget):
    # 省略

class PlayFieldWidget(FloatLayout):
    # 省略

class QuestionLabel(Label):
    # 省略

class ButtonBaseWidget(Button):
    # 省略

class ButtonsWidget(BoxLayout):
    def __init__(self, **kwargs):
        super(ButtonsWidget, self).__init__(**kwargs)
        self.orientation = "vertical"
        self.width_10Per = int(self.width * 0.1)
        self.height_5Per = int(self.height * 0.05)
        self.padding = [self.width_10Per, self.width_10Per]
        self.spacing = self.height_5Per
        self.btn_answer = ButtonBaseWidget(text="Answer")
        self.btn_reset  = ButtonBaseWidget(text="Reset")
        self.btn_seeans = ButtonBaseWidget(text="See")      # See the Answer
        self.btn_next   = ButtonBaseWidget(text="Next")
        self.btn_return = ButtonBaseWidget(text="Return")   # Return Title
        self.add_widget(self.btn_answer)
        self.add_widget(self.btn_reset)
        self.add_widget(self.btn_seeans)
        self.add_widget(self.btn_next)
        self.add_widget(self.btn_return)
        with self.canvas.before:
            Color(rgb=[1, 1, 1])
            self.bg_rect = Rectangle(pos=self.pos, size=self.size)
    def on_pos(self, *args):
        self.bg_rect.pos = self.pos
    def on_size(self, *args):
        self.bg_rect.size = self.size
        self.width_10Per = int(self.width * 0.1)
        self.height_5Per = int(self.height * 0.05)
        self.padding = [self.width_10Per, self.width_10Per]
        self.spacing = self.height_5Per

class RootWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        with self.canvas.before:
            Color(rgb=[1, 1, 1])
            self.bg_rect = Rectangle(pos=self.pos, size=self.size)
    def on_size(self, *args):
        self.bg_rect.size = self.size

class MatchStickQuizApp(App):
    def build(self):
        root = RootWidget()
        bw = ButtonsWidget()
        root.add_widget(bw)
        return root

if __name__ == '__main__':
    MatchStickQuizApp().run()
    pass

 

上記のコードは以下からダウンロードできます。

 

 

コードの解説

5行目の「import文」は、BoxLayoutをインポートしています。

  

 

37行目から65行目の「ButtonsWidget」は、縦に5つボタンを表示するレイアウトです。

 

38行目から57行目の「init関数」は、ButtonsWidgetを初期化しています。

 

39行目の「super関数」は、BoxLayoutのinit関数を実行しています。

 

40行目の「self.orientation」は、ウィジェットを追加する方法を設定しいています。「vertical」を代入しているため、縦方向に追加していきます。

 

41行目の「self.width_10Per」は、ButtonsWidgetの横幅の10%が代入される変数です。

 

42行目の「self.height_5Per」は、ButtonsWidgetの縦幅の5%が代入される変数です。

 

43行目の「self.padding」は、ButtonsWidgetの外側の余白を設定しています。縦横それぞれself.width_10Per分の余白が設定されています。

余白は以下の画像における薄い青色の範囲です。縦と横で若干範囲が異なりますが、イメージとして読み取ってください。

 

44行目の「self.spacing」は、子ウィジェット同士の間に余白を設定しています。子ウィジェットと子ウィジェットの間にはself.height_5Per分の余白が設定されています。

余白は以下の画像における薄い青色の範囲です。

  

45行目の「self.btn_answer」は、「答える」ボタンを表すオブジェクトが代入される変数です。ButtonBaseWidgetのtextにAnswerを設定してオブジェクトを生成しています。

 

46行目の「self.btn_reset」は、「リセット」ボタンを表すオブジェクトが代入される変数です。ButtonBaseWidgetのtextにResetを設定してオブジェクトを生成しています。

 

47行目の「self.btn_seeans」は、「答えを見る」ボタンを表すオブジェクトが代入される変数です。ButtonBaseWidgetのtextにSeeを設定してオブジェクトを生成しています。

 

48行目の「self.btn_next」は、「次へ」ボタンを表すオブジェクトが代入される変数です。ButtonBaseWidgetのtextにNextを設定してオブジェクトを生成しています。

 

49行目の「self.btn_return」は、「タイトルへ戻る」ボタンを表すオブジェクトが代入される変数です。ButtonBaseWidgetのtextにReturnを設定してオブジェクトを生成しています。

 

50行目から54行目の「add_widget関数」は、先ほど生成したボタンを順番に追加しています。

 

55行目の「with文」は、self.canvas.beforeオブジェクトを扱うための文です。

 

56行目の「Color」は、後述するRectangleオブジェクトの色を設定しています。[1, 1, 1]は、白色を表しています。

 

57行目の「self.bg_rect」は、背景色を設定するRectangleオブジェクトが代入される変数です。RectangleのposにはButtonsWidgetのpos、sizeにはButtonsWidgetのsizeを設定しています。

 

58行目と59行目の「on_pos関数」は、posが変化したときに実行される関数です。

 

59行目では、self.bg_rect.posを更新しています。

  

60行目から65行目の「on_size関数」は、sizeが変化したときに実行される関数です。

61行目では、self.bg_rect.sizeを更新しています。

62行目では、self.width_10Perを更新しています。

63行目では、self.height_5Perを更新しています。

64行目では、self.paddingを更新しています。

65行目では、self.spacingを更新しています。

 

 

動作確認

コードを保存したら、コマンドプロンプトを開きファイルを保存したフォルダまで移動します。移動したら、以下のコマンドを入力し実行します。

python matchstickquiz.py

 

以下のように表示されれば動作確認完了です。

 

 

スポンサードサーチ


ポップアップで使用する図形

正解不正解を表すポップアップで使用するマルとバツの図形を描画するクラスを作成します。

 

同じクラスにマルとバツを描画させ、透明度を変化させることでどちらかしか描画されないように処理します。

  

 

コードの提示

マルとバツを描画するクラスのソースコードを以下に示します。

import kivy
kivy.require("2.0.0")

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle, Ellipse
from kivy.graphics import Rotate
from kivy.graphics import Line
from kivy.graphics.context_instructions import PushMatrix, PopMatrix
from kivy.storage.jsonstore import JsonStore

from kivy.core.window import Window

import numpy as np
import random
import copy

class MatchStickWidget(Widget):
    # 省略

class MatchStickFrameWidget(Widget):
    # 省略

class PlayFieldWidget(FloatLayout):
    # 省略

class QuestionLabel(Label):
    # 省略

class ButtonBaseWidget(Button):
    # 省略

class ButtonsWidget(BoxLayout):
    # 省略

class ResultWidget(Widget):
    def __init__(self, **kwargs):
        super(ResultWidget, self).__init__(**kwargs)
        self.half_y = int(self.height / 2)
        with self.canvas.before:
            self.cc = Color(rgb=[0.86, 0.08, 0.23])                                         # cc = circle color / crimson
            self.cline = Line(width=7, circle=[self.center_x, self.center_y, self.half_y])  #  cline = circle line
            self.xc = Color(rgb=[0, 0, 1])                                                  # xc = x color / bule
            # xline1 = lb -> rt / xline2 = lt -> rb
            self.xline1 = Line(width=7, cap="none", points=[self.center_x-self.half_y, self.y, self.center_x+self.half_y, self.y+self.height])
            self.xline2 = Line(width=7, cap="none", points=[self.center_x-self.half_y, self.center_y+self.half_y,
                                                            self.center_x+self.half_y, self.center_y-self.half_y])
    def on_size(self, *args):
        self.half_y = int(self.height / 2)
        self.cline.circle = [self.center_x, self.center_y, self.half_y]
        self.xline1.points = [self.center_x-self.half_y, self.y, self.center_x+self.half_y, self.y+self.height]
        self.xline2.points = [self.center_x-self.half_y, self.center_y+self.half_y,
                              self.center_x+self.half_y, self.center_y-self.half_y]

class RootWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        with self.canvas.before:
            Color(rgb=[1, 1, 1])
            self.bg_rect = Rectangle(pos=self.pos, size=self.size)
    def on_size(self, *args):
        self.bg_rect.size = self.size

class MatchStickQuizApp(App):
    def build(self):
        root = RootWidget()
        rw = ResultWidget()
        root.add_widget(rw)
        return root

if __name__ == '__main__':
    MatchStickQuizApp().run()
    pass

 

上記のコードは以下からダウンロードできます。

 

 

コードの解説

40行目から57行目の「ResultWidgetクラス」は、マルとバツを描画するクラスです。

 

41行目から51行目の「init関数」は、ResultWidgetクラスを初期化しています。

 

42行目の「super関数」は、Widgetクラスのinit関数を実行しています。

 

43行目の「self.half_y」は、ResultWidgetクラスの縦幅の半分の値が代入される変数です。

 

44行目の「with文」は、self.canvas.beforeオブジェクトを扱うための文です。

 

45行目の「self.cc」は、マルの色を設定するColorオブジェクトが代入される変数です。クリムゾンカラーが設定されています。

 

46行目の「self.cline」は、マルを表すオブジェクトが代入される変数です。線の太さを7、描画位置を中心、マルの半径をself.half_yに設定しています。

 

47行目の「self.xc」は、バツの色を設定するColorオブジェクトが代入される変数です。青色が設定されています。

 

49行目の「self.xline1」は、バツの左下から右上に伸びる線を表すオブジェクトが代入される変数です。線の太さを7、中心に描画されるように描画位置を設定しています。

 

50行目と51行目の「self.xline2」は、バツの左上から右下に伸びる線を表すオブジェクトが代入される変数です。線の太さを7、中心に描画されるように描画位置を設定しています。

  

52行目から57行目の「on_size関数」は、sizeが変化したときに実行される関数です。

53行目では、self.half_yを更新しています。

54行目では、self.cline.circleを更新しています。つまり描画位置を更新しています。

55行目では、self.xline1.pointsを更新しています。つまり描画位置を更新しています。

56行目と57行目では、self.xline2.pointsを更新しています。つまり描画位置を更新しています。

 

 

動作確認

コードを保存したら、コマンドプロンプトを開きファイルを保存したフォルダまで移動します。移動したら、以下のコマンドを入力し実行します。

python matchstickquiz.py

  

以下のように表示されれば動作確認完了です。ResultWidgetでは透明度の設定を行っていないため、マルとバツが同時に描画されています。

  

 

スポンサードサーチ


まとめ

今回は、縦に5つボタンを表示するレイアウトと正解不正解を表すポップアップで使用するマルとバツを描画するクラスを作成しました。

単に設定したり、描画するだけであったため簡単だったと思います。

 

次回Part17では、正解不正解を表示するポップアップとPlayFieldWidgetやQuestionLabel、ButtonsWidgetを使って実際にプレイするレイアウトを作成します。

 

 

 

最後までお読みいただきありがとうございます。


スポンサードサーチ