2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🔽 全問解けたらあなたのオタクは神レベル!?

このアプリは、WordCloudで可視化した乃木坂46の歌詞画像を使って、
どの曲かを当てるクイズを楽しめるゲームです!

オタクでも難しい!
だからこそ…ガチオタ検定用にしました💜

🔽 環境構築

  • Python
  • Tkinter
  • WordCloudで生成した画像(PNG形式)

🔽 できること

  • WordCloud画像をランダム表示
  • 曲名を当てるクイズ形式
  • 答え表示・次の問題へ の操作が可能
  • 推し活っぽいパステル&丸ボタンUI

🔽 準備するもの

① WordCloud画像の作成

乃木坂46の歌詞CSVから、形態素解析 → WordCloud生成 → PNG画像として保存してください。

生成コードはこちらにまとめました👇

② クイズアプリ(Tkinter)

全体コードはこちら↓
python
import os
import random
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk

class SparkleCanvas(tk.Canvas):
    def __init__(self, master, width, height, count=30, **kwargs):
        super().__init__(master, width=width, height=height, bg="#ffe4e6", highlightthickness=0, **kwargs)
        self.width = width
        self.height = height
        self.count = count
        self.stars = []
        for _ in range(count):
            x = random.randint(0, width)
            y = random.randint(0, height)
            size = random.randint(3,6)
            star = self.create_oval(x, y, x+size, y+size, fill="#fffacd", outline="")
            self.stars.append((star, size, x, y, 1))
        self.animate()

    def animate(self):
        for i, (star, size, x, y, dir) in enumerate(self.stars):
            new_color = "#fffacd" if dir == 1 else "#fff1b6"
            self.itemconfig(star, fill=new_color)
            self.stars[i] = (star, size, x, y, -dir)
        self.after(500, self.animate)

class PuffyButton(tk.Canvas):
    def __init__(self, master, text, command=None, width=120, height=50,
                 bg="#ff77a9", fg="white", font=None, **kwargs):
        super().__init__(master, width=width, height=height, bg="#ffe4e6", highlightthickness=0, **kwargs)
        self.command = command
        self.bg = bg
        self.fg = fg
        self.font = font or ("Comic Sans MS", 14, "bold")
        self.text = text
        self.width = width
        self.height = height

        self.draw_button()
        self.bind("<Button-1>", lambda e: self.command() if self.command else None)
        self.bind("<Enter>", self.on_enter)
        self.bind("<Leave>", self.on_leave)
        self.is_hover = False

    def draw_button(self):
        self.delete("all")
        self.create_oval(5, 5, self.width-5, self.height-5, fill="#ff3d88", outline="")
        self.create_oval(0, 0, self.width-10, self.height-10, fill=self.bg, outline="")
        self.create_oval(0, 0, self.width-10, (self.height-10)//2, fill="#ffa1c9", outline="")
        self.create_text((self.width-10)//2, (self.height-10)//2, text=self.text, font=self.font, fill=self.fg)

    def on_enter(self, event):
        if not self.is_hover:
            self.is_hover = True
            self.bg = "#ff3d88"
            self.draw_button()

    def on_leave(self, event):
        if self.is_hover:
            self.is_hover = False
            self.bg = "#ff77a9"
            self.draw_button()

class QuizApp(tk.Tk):
    def __init__(self, image_folder="/ここ変更ーーーPATHの位置"):
        super().__init__()
        self.title("✨乃木坂曲クイズ✨")
        self.geometry("620x700")
        self.configure(bg="#ffe4e6")

        self.image_folder = image_folder
        self.image_files = [f for f in os.listdir(self.image_folder) if f.endswith(".png")]
        if not self.image_files:
            raise ValueError(f"{self.image_folder} にPNG画像がありません。")

        self.current_image_file = None
        self.current_answer = None

        self.sparkle_bg = SparkleCanvas(self, width=620, height=700)
        self.sparkle_bg.place(x=0, y=0)

        self.font_title = ("Comic Sans MS", 22, "bold")
        self.font_answer = ("Comic Sans MS", 18, "bold")

        self.title_label = tk.Label(self, text="✨乃木坂曲クイズ✨",
                                    font=self.font_title, fg="#d6336c", bg="#ffe4e6")
        self.title_label.pack(pady=15)

        self.image_label = ttk.Label(self)
        self.image_label.pack(pady=15)

        self.answer_label = tk.Label(self, text="", font=self.font_answer,
                                     fg="#d6336c", bg="#ffe4e6")
        self.answer_label.pack(pady=10)

        button_frame = tk.Frame(self, bg="#ffe4e6")
        button_frame.pack(pady=25)

        self.show_answer_button = PuffyButton(button_frame, text="答え", command=self.show_answer)
        self.show_answer_button.grid(row=0, column=0, padx=20)

        self.next_button = PuffyButton(button_frame, text="次へ", command=self.next_image)
        self.next_button.grid(row=0, column=1, padx=20)

        self.after(100, self.next_image)

    def next_image(self):
        self.answer_label.config(text="")
        self.current_image_file = random.choice(self.image_files)
        base_name = os.path.splitext(self.current_image_file)[0]
        self.current_answer = base_name.split("_", 1)[1] if "_" in base_name else base_name

        image_path = os.path.join(self.image_folder, self.current_image_file)
        img = Image.open(image_path)
        img.thumbnail((500, 400))

        self.photo = ImageTk.PhotoImage(img)
        self.image_label.config(image=self.photo)
        self.image_label.image = self.photo

    def show_answer(self):
        if self.current_answer:
            self.answer_label.config(text=f"答え:{self.current_answer}")

if __name__ == "__main__":
    app = QuizApp()
    app.mainloop()




🔽 クイズアプリの構造を解説

Q1 どのような構造か?

A: アプリの本体は以下のように、QuizApp というクラスで構成されています

class QuizApp(tk.Tk):
    def __init__(self, image_folder="..."):
        super().__init__()
        # ① 初期設定(タイトル、サイズ、背景色など)
        # ② WordCloud画像の読み込み
        # ③ 背景Canvas(SparkleCanvas)設置
        # ④ UIウィジェットの配置
        # ⑤ 最初の画像を表示

Tkinterのウィンドウを継承し、画像のランダム表示・ボタンによる操作・答えの表示などを行っています

Q2 なぜファイル名から曲名を抽出しているのか?

例えば以下のようなファイル名があるとします:

n46_インフルエンサー.png
n46_制服のマネキン.png

これらのファイルから「_以降」だけを抽出することで、正解の曲名が得られます

base_name = os.path.splitext(self.current_image_file)[0]
base_name.split("_", 1)[1]

os.path.splitext() → .png を除いたファイル名(例: n46_インフルエンサー)
.split("", 1)[1] → "" 以降の部分" → インフルエンサー
という風に処理しています

🔽 最後に

あなたの「乃木坂力」、このアプリで試してみてください〜

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?