子供にお手伝いをしてもらう動機付けに、ポイントカードシステムを導入してみませんか?この記事では、PythonのSQLite3
とtkinter
を使って、子供がお手伝いをしてポイントを貯め、それを商品と交換できるシステムの作成方法を紹介します。
このコードは、Python(バージョン3.x)と標準ライブラリだけで動作します。WindowsやMacにPythonがインストールされていれば、すぐに試せます。おすすめのエディタは「VS Code」です。
完成イメージ
子供が使う画面では、自分のポイントを確認したり、貯まったポイントで商品と交換します。
親御さんが使う画面では、子供をシステムに登録したり、ポイントを付与したり、交換可能な商品を登録します。

システム概要
このシステムは3つの主要なテーブル(ユーザー、ポイント、商品)を持つデータベースを作成します。それぞれのテーブルで、子供の情報、ポイントの履歴、そして商品情報を管理します。
- users:子供の名前と生年月日で識別し、ユーザー情報を管理。
- points:どのお手伝いでポイントが付与されたか、その理由とともに記録。
- products:商品名と交換に必要なポイントを管理。
1. 必要なライブラリ
import sqlite3
import tkinter as tk
from tkinter import messagebox
- sqlite3: データベースを作成・管理するためのライブラリです。
- tkinter: GUI(グラフィカル・ユーザー・インターフェース)を作成するためのライブラリです。
- messagebox: tkinterの中のツールで、メッセージを表示するために使います。
2. データベースの初期設定
まず、ユーザー、ポイント、商品を管理するデータベースを設定します。このコードは、必要なテーブルを作成する初期設定です。
def setup_database():
conn = sqlite3.connect('points.db')
c = conn.cursor()
# ユーザーテーブルの作成
c.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
birthdate TEXT
)
''')
# ポイントテーブルの作成
c.execute('''
CREATE TABLE IF NOT EXISTS points (
user_id INTEGER,
points INTEGER,
reason TEXT,
FOREIGN KEY(user_id) REFERENCES users(id)
)
''')
# 商品テーブルの作成
c.execute('''
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY,
name TEXT,
required_points INTEGER
)
''')
conn.commit()
conn.close()
- usersテーブル: 子供の名前と生年月日を記録。
- pointsテーブル: ポイントの履歴と理由を記録。
- productsテーブル: 商品名と交換に必要なポイント数を記録。
3. ユーザー登録と削除
次に、子供(ユーザー)をシステムに登録したり、削除する機能を実装します。
ユーザー登録
pythonコードをコピーするdef register_user(name, birthdate):
conn = sqlite3.connect('points.db')
c = conn.cursor()
try:
c.execute('INSERT INTO users (name, birthdate) VALUES (?, ?)', (name, birthdate))
conn.commit()
messagebox.showinfo("成功", "ユーザー登録完了")
except sqlite3.IntegrityError:
messagebox.showerror("エラー", "このユーザーは既に登録されています")
conn.close()
ユーザー削除
def delete_user(name, birthdate):
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('SELECT id FROM users WHERE name = ? AND birthdate = ?', (name, birthdate))
user = c.fetchone()
if user:
c.execute('DELETE FROM points WHERE user_id = ?', (user[0],))
c.execute('DELETE FROM users WHERE id = ?', (user[0],))
conn.commit()
messagebox.showinfo("成功", "ユーザー削除完了")
else:
messagebox.showerror("エラー", "ユーザーが見つかりません")
conn.close()
- register_user(): 子供を名前と生年月日で登録します。
- delete_user(): 子供を削除し、関連するポイントデータも削除します。
4. ポイントの付与と確認
ポイントを付与する機能
pythonコードをコピーするdef add_points(name, birthdate, points, reason):
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('SELECT id FROM users WHERE name = ? AND birthdate = ?', (name, birthdate))
user = c.fetchone()
if user:
c.execute('INSERT INTO points (user_id, points, reason) VALUES (?, ?, ?)', (user[0], points, reason))
conn.commit()
messagebox.showinfo("成功", f"{points}ポイント追加しました(理由: {reason})")
else:
messagebox.showerror("エラー", "ユーザーが見つかりません")
conn.close()
ポイント確認機能
pythonコードをコピーするdef check_points(name, birthdate):
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('SELECT id FROM users WHERE name = ? AND birthdate = ?', (name, birthdate))
user = c.fetchone()
if user:
c.execute('SELECT SUM(points) FROM points WHERE user_id = ?', (user[0],))
total_points = c.fetchone()[0]
if total_points is None:
total_points = 0
c.execute('SELECT points, reason FROM points WHERE user_id = ?', (user[0],))
history = c.fetchall()
result = f"現在のポイント: {total_points}\n\n【ポイント履歴】\n"
for entry in history:
result += f"ポイント: {entry[0]}, 理由: {entry[1]}\n"
messagebox.showinfo("ポイント確認", result)
else:
messagebox.showerror("エラー", "ユーザーが見つかりません")
conn.close()
- add_points(): 子供にポイントを付与し、その理由を記録します。
- check_points(): 子供の現在のポイントと過去のポイント履歴を確認できます。
5. 商品登録と商品交換
商品を登録する機能
def register_product(name, required_points):
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('INSERT INTO products (name, required_points) VALUES (?, ?)', (name, required_points))
conn.commit()
messagebox.showinfo("成功", f"商品 {name} が登録されました(必要ポイント: {required_points})")
conn.close()
商品とポイントを交換する機能
def use_points_for_product(name, birthdate, product_id):
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('SELECT id FROM users WHERE name = ? AND birthdate = ?', (name, birthdate))
user = c.fetchone()
if not user:
messagebox.showerror("エラー", "ユーザーが見つかりません")
conn.close()
return
c.execute('SELECT required_points FROM products WHERE id = ?', (product_id,))
product = c.fetchone()
if not product:
messagebox.showerror("エラー", "商品が見つかりません")
conn.close()
return
c.execute('SELECT SUM(points) FROM points WHERE user_id = ?', (user[0],))
total_points = c.fetchone()[0]
if total_points is None:
total_points = 0
if total_points >= product[0]:
c.execute('INSERT INTO points (user_id, points, reason) VALUES (?, ?, ?)', (user[0], -product[0], '商品交換'))
conn.commit()
messagebox.showinfo("成功", "商品と交換しました!")
else:
messagebox.showerror("エラー", "ポイントが不足しています")
conn.close()
- register_product(): 商品を登録し、交換に必要なポイントを指定します。
- use_points_for_product(): 子供が貯めたポイントを使って商品と交換します。
6. tkinterを使ったGUI
ユーザー画面
子供がポイントを確認し、商品と交換するための画面です。
pythonコードをコピーするdef create_user_gui():
user_window = tk.Toplevel()
user_window.title("ユーザー画面")
tk.Label(user_window, text="名前").grid(row=0, column=0)
name_entry = tk.Entry(user_window)
name_entry.grid(row=0, column=1)
tk.Label(user_window, text="生年月日 (YYYY-MM-DD)").grid(row=1, column=0)
birthdate_entry = tk.Entry(user_window)
birthdate_entry.grid(row=1, column=1)
tk.Button(user_window, text="ポイント確認", command=lambda: check_points(name_entry.get(), birthdate_entry.get())).grid(row=2, column=0, columnspan=2)
tk.Label(user_window, text="商品ID").grid(row=3, column=0)
product_entry = tk.Entry(user_window)
product_entry.grid(row=3, column=1)
tk.Button(user_window, text="商品と交換", command=lambda: use_points_for_product(name_entry.get(), birthdate_entry.get(), int(product_entry.get()))).grid(row=4, column=0, columnspan=2)
お店画面
親御さんが子供を登録したり、ポイントを付与したり、商品を登録するための画面です。
def create_shop_gui():
shop_window = tk.Toplevel()
shop_window.title("お店画面")
tk.Label(shop_window, text="名前").grid(row=0, column=0)
name_entry = tk.Entry(shop_window)
name_entry.grid(row=0, column=1)
tk.Label(shop_window, text="生年月日 (YYYY-MM-DD)").grid(row=1, column=0)
birthdate_entry = tk.Entry(shop_window)
birthdate_entry.grid(row=1, column=1)
tk.Label(shop_window, text="ポイント数").grid(row=2, column=0)
points_entry = tk.Entry(shop_window)
points_entry.grid(row=2, column=1)
tk.Label(shop_window, text="理由").grid(row=3, column=0)
reason_entry = tk.Entry(shop_window)
reason_entry.grid(row=3, column=1)
tk.Button(shop_window, text="ユーザー登録", command=lambda: register_user(name_entry.get(), birthdate_entry.get())).grid(row=4, column=0, columnspan=2)
tk.Button(shop_window, text="ユーザー削除", command=lambda: delete_user(name_entry.get(), birthdate_entry.get())).grid(row=5, column=0, columnspan=2)
tk.Button(shop_window, text="ポイント付与", command=lambda: add_points(name_entry.get(), birthdate_entry.get(), int(points_entry.get()), reason_entry.get())).grid(row=6, column=0, columnspan=2)
tk.Label(shop_window, text="商品名").grid(row=7, column=0)
product_name_entry = tk.Entry(shop_window)
product_name_entry.grid(row=7, column=1)
tk.Label(shop_window, text="必要ポイント").grid(row=8, column=0)
product_points_entry = tk.Entry(shop_window)
product_points_entry.grid(row=8, column=1)
tk.Button(shop_window, text="商品登録", command=lambda: register_product(product_name_entry.get(), int(product_points_entry.get()))).grid(row=9, column=0, columnspan=2)
7. メイン画面と起動
最後に、メイン画面から「ユーザー画面」か「お店画面」を選択できるようにします。
def create_main_gui():
root = tk.Tk()
root.title("お手伝いポイントカードシステム")
tk.Button(root, text="ユーザー画面", command=create_user_gui).pack(pady=10)
tk.Button(root, text="お店画面", command=create_shop_gui).pack(pady=10)
root.mainloop()
# データベースの初期設定を行い、システムを起動します
setup_database()
create_main_gui()
すべてのコード
以下に、すべてのコードを一つにまとめたものを示します。これをコピー&ペーストして使ってください。
import sqlite3
import tkinter as tk
from tkinter import messagebox, ttk
# データベース初期設定
def setup_database():
conn = sqlite3.connect('points.db')
c = conn.cursor()
# ユーザーテーブル
c.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
birthdate TEXT
)
''')
# ポイントテーブル
c.execute('''
CREATE TABLE IF NOT EXISTS points (
user_id INTEGER,
points INTEGER,
reason TEXT,
date TEXT,
FOREIGN KEY(user_id) REFERENCES users(id)
)
''')
# 商品テーブル
c.execute('''
CREATE TABLE IF NOT EXISTS products (
id INTEGER PRIMARY KEY,
name TEXT,
required_points INTEGER
)
''')
conn.commit()
conn.close()
# ユーザー登録
def register_user(name, birthdate):
conn = sqlite3.connect('points.db')
c = conn.cursor()
try:
c.execute('INSERT INTO users (name, birthdate) VALUES (?, ?)', (name, birthdate))
conn.commit()
messagebox.showinfo("成功", "ユーザー登録完了")
except sqlite3.IntegrityError:
messagebox.showerror("エラー", "このユーザーは既に登録されています")
conn.close()
# ユーザー削除
def delete_user(name, birthdate):
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('SELECT id FROM users WHERE name = ? AND birthdate = ?', (name, birthdate))
user = c.fetchone()
if user:
c.execute('DELETE FROM points WHERE user_id = ?', (user[0],))
c.execute('DELETE FROM users WHERE id = ?', (user[0],))
conn.commit()
messagebox.showinfo("成功", "ユーザー削除完了")
else:
messagebox.showerror("エラー", "ユーザーが見つかりません")
conn.close()
# 商品登録
def register_product(name, required_points):
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('INSERT INTO products (name, required_points) VALUES (?, ?)', (name, required_points))
conn.commit()
messagebox.showinfo("成功", f"商品 {name} が登録されました(必要ポイント: {required_points})")
conn.close()
# ポイント確認(ユーザー画面)
def check_points(name, birthdate):
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('SELECT id FROM users WHERE name = ? AND birthdate = ?', (name, birthdate))
user = c.fetchone()
if user:
# 合計ポイント
c.execute('SELECT SUM(points) FROM points WHERE user_id = ?', (user[0],))
total_points = c.fetchone()[0]
if total_points is None:
total_points = 0
# ポイント履歴
c.execute('SELECT date, reason, points FROM points WHERE user_id = ?', (user[0],))
history = c.fetchall()
return total_points, history
else:
messagebox.showerror("エラー", "ユーザーが見つかりません")
conn.close()
return 0, []
# 商品と交換
def exchange_product(name, birthdate, product_id):
conn = sqlite3.connect('points.db')
c = conn.cursor()
# ユーザーID取得
c.execute('SELECT id FROM users WHERE name = ? AND birthdate = ?', (name, birthdate))
user = c.fetchone()
if not user:
messagebox.showerror("エラー", "ユーザーが見つかりません")
conn.close()
return
# 商品情報取得
c.execute('SELECT required_points FROM products WHERE id = ?', (product_id,))
product = c.fetchone()
if not product:
messagebox.showerror("エラー", "商品が見つかりません")
conn.close()
return
# 合計ポイント確認
c.execute('SELECT SUM(points) FROM points WHERE user_id = ?', (user[0],))
total_points = c.fetchone()[0]
if total_points is None:
total_points = 0
if total_points >= product[0]:
# ポイント減算
c.execute('INSERT INTO points (user_id, points, reason, date) VALUES (?, ?, ?, date("now"))', (user[0], -product[0], '商品交換'))
conn.commit()
messagebox.showinfo("成功", "商品と交換しました!")
else:
messagebox.showerror("エラー", "ポイントが不足しています")
conn.close()
# 商品リスト取得
def get_products():
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('SELECT id, name, required_points FROM products')
products = c.fetchall()
conn.close()
return products
# ユーザーリスト取得
def get_users():
conn = sqlite3.connect('points.db')
c = conn.cursor()
c.execute('SELECT id, name, birthdate FROM users')
users = c.fetchall()
conn.close()
return users
# ユーザー画面
def create_user_gui():
user_window = tk.Toplevel()
user_window.title("ユーザー画面")
user_window.geometry("600x400")
tk.Label(user_window, text="名前").grid(row=0, column=0)
name_entry = tk.Entry(user_window)
name_entry.grid(row=0, column=1)
tk.Label(user_window, text="生年月日 (YYYY-MM-DD)").grid(row=1, column=0)
birthdate_entry = tk.Entry(user_window)
birthdate_entry.grid(row=1, column=1)
# 現在の合計ポイントと履歴を表示
def show_points():
total_points, history = check_points(name_entry.get(), birthdate_entry.get())
total_points_label.config(text=f"合計ポイント: {total_points}")
for row in history_tree.get_children():
history_tree.delete(row)
for h in history:
history_tree.insert("", "end", values=h)
tk.Button(user_window, text="ポイント確認", command=show_points).grid(row=2, column=0, columnspan=2)
total_points_label = tk.Label(user_window, text="合計ポイント: 0")
total_points_label.grid(row=3, column=0, columnspan=2)
# ポイント履歴テーブル
history_tree = ttk.Treeview(user_window, columns=("date", "reason", "points"), show="headings")
history_tree.heading("date", text="日付")
history_tree.heading("reason", text="商品/理由")
history_tree.heading("points", text="ポイント")
history_tree.grid(row=4, column=0, columnspan=2)
# 商品交換ボタン
def show_product_list():
product_window = tk.Toplevel()
product_window.title("商品一覧")
product_window.geometry("400x300")
product_tree = ttk.Treeview(product_window, columns=("name", "required_points"), show="headings")
product_tree.heading("name", text="商品名")
product_tree.heading("required_points", text="必要ポイント")
product_tree.pack(fill=tk.BOTH, expand=True)
for p in get_products():
product_tree.insert("", "end", values=(p[1], p[2]))
def exchange():
selected_item = product_tree.selection()
if selected_item:
product_name = product_tree.item(selected_item)["values"][0]
product_id = None
for p in get_products():
if p[1] == product_name:
product_id = p[0]
break
if product_id:
exchange_product(name_entry.get(), birthdate_entry.get(), product_id)
tk.Button(product_window, text="商品と交換", command=exchange).pack(pady=10)
tk.Button(user_window, text="商品と交換", command=show_product_list).grid(row=5, column=0, columnspan=2)
# お店画面
def create_shop_gui():
shop_window = tk.Toplevel()
shop_window.title("お店画面")
shop_window.geometry("600x400")
def user_registration():
registration_window = tk.Toplevel()
registration_window.title("ユーザー登録")
tk.Label(registration_window, text="名前").grid(row=0, column=0)
name_entry = tk.Entry(registration_window)
name_entry.grid(row=0, column=1)
tk.Label(registration_window, text="生年月日 (YYYY-MM-DD)").grid(row=1, column=0)
birthdate_entry = tk.Entry(registration_window)
birthdate_entry.grid(row=1, column=1)
tk.Button(registration_window, text="登録", command=lambda: register_user(name_entry.get(), birthdate_entry.get())).grid(row=2, column=0, columnspan=2)
def user_deletion():
deletion_window = tk.Toplevel()
deletion_window.title("ユーザー削除")
tk.Label(deletion_window, text="名前").grid(row=0, column=0)
name_entry = tk.Entry(deletion_window)
name_entry.grid(row=0, column=1)
tk.Label(deletion_window, text="生年月日 (YYYY-MM-DD)").grid(row=1, column=0)
birthdate_entry = tk.Entry(deletion_window)
birthdate_entry.grid(row=1, column=1)
tk.Button(deletion_window, text="削除", command=lambda: delete_user(name_entry.get(), birthdate_entry.get())).grid(row=2, column=0, columnspan=2)
def product_registration():
product_window = tk.Toplevel()
product_window.title("商品登録")
tk.Label(product_window, text="商品名").grid(row=0, column=0)
product_name_entry = tk.Entry(product_window)
product_name_entry.grid(row=0, column=1)
tk.Label(product_window, text="必要ポイント").grid(row=1, column=0)
product_points_entry = tk.Entry(product_window)
product_points_entry.grid(row=1, column=1)
tk.Button(product_window, text="登録", command=lambda: register_product(product_name_entry.get(), int(product_points_entry.get()))).grid(row=2, column=0, columnspan=2)
def show_overview():
overview_window = tk.Toplevel()
overview_window.title("ユーザー・商品確認")
overview_window.geometry("800x400")
# ユーザーリスト
user_tree = ttk.Treeview(overview_window, columns=("name", "birthdate"), show="headings")
user_tree.heading("name", text="ユーザー名")
user_tree.heading("birthdate", text="生年月日")
user_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
for u in get_users():
user_tree.insert("", "end", values=(u[1], u[2]))
# 商品リスト
product_tree = ttk.Treeview(overview_window, columns=("name", "required_points"), show="headings")
product_tree.heading("name", text="商品名")
product_tree.heading("required_points", text="必要ポイント")
product_tree.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
for p in get_products():
product_tree.insert("", "end", values=(p[1], p[2]))
tk.Button(shop_window, text="ユーザー登録", command=user_registration).grid(row=0, column=0, columnspan=2, pady=10)
tk.Button(shop_window, text="ユーザー削除", command=user_deletion).grid(row=1, column=0, columnspan=2, pady=10)
tk.Button(shop_window, text="商品登録", command=product_registration).grid(row=2, column=0, columnspan=2, pady=10)
tk.Button(shop_window, text="確認", command=show_overview).grid(row=3, column=0, columnspan=2, pady=10)
# メイン画面
def create_main_gui():
root = tk.Tk()
root.title("お手伝いポイントカードシステム")
root.geometry("400x200")
tk.Button(root, text="ユーザー画面", command=create_user_gui, height=3, width=20).pack(pady=10)
tk.Button(root, text="お店画面", command=create_shop_gui, height=3, width=20).pack(pady=10)
root.mainloop()
# データベース初期設定とメインGUI起動
setup_database()
create_main_gui()

楽天ブックス
¥4,400 (2025/04/03 11:35時点 | 楽天市場調べ)

コメント