初心者向け No.17

デジタル時計

現在時刻をリアルタイム表示するデジタル時計アプリ。after()と時刻取得の組み合わせを学びます。

🎯 難易度: ★☆☆ 📦 ライブラリ: tkinter(標準ライブラリ) ⏱️ 制作時間: 30〜90分

1. アプリ概要

現在時刻をリアルタイム表示するデジタル時計アプリ。after()と時刻取得の組み合わせを学びます。

このアプリはツールカテゴリに分類される実践的なGUIアプリです。使用ライブラリは tkinter(標準ライブラリ) で、難易度は ★☆☆ です。

このアプリは「ツール」カテゴリです。日々の作業を自動化する実用ツールは Python が最も得意とする領域です。短いコードで実用性のある成果物が作れる点が魅力です。tkinter(標準ライブラリ) を活かして実装するこの構造は、他のアプリにも応用が効きます。

コードを読む前に実行することをおすすめします。動いている挙動を先に把握しておくと、解説で出てくる関数や処理がどこに対応するかが頭に入りやすくなります。

応用のヒントは、機能を 1 つ増やす・見た目を整える・例外を一つでも丁寧に扱う、のいずれかから始めるのがおすすめです。

デジタル時計 実行画面(Windows)
実行画面(Windows)
デジタル時計 実行画面(Linux Mint)
実行画面(Linux Mint)

2. 機能一覧

  • after(1000, ...) による1000ミリ秒間隔の _tick() 呼び出し(画面の自動更新)
  • ウィンドウはタイトル「デジタル時計」・サイズ 420x280 で起動

3. 事前準備・環境

ℹ️
動作確認環境

Python 3.10 以上 / Windows 11(実機)で起動・基本操作を確認 / Linux Mint 22.3(仮想マシン)で起動・画面表示を確認(macOS は未検証)

Windows 11(実機)で起動と基本操作を確認しています(全機能の網羅テストではありません)。Linux Mint 22.3(仮想マシン)では起動と画面表示を確認しました。macOS は標準ライブラリの範囲で動作する想定ですが、未検証です。

  • Python 3.10 以上
  • OS: Windows 11(実機で起動・基本操作を確認)・Linux Mint 22.3(仮想マシンで起動・画面表示を確認)

4. 完全なソースコード

💡
コードのコピー方法

右上の「コピー」ボタンをクリックするとコードをクリップボードにコピーできます。

追加インストール不要(標準ライブラリのみ使用)
app17.py
import tkinter as tk
from datetime import datetime


class App17:
    """デジタル時計"""

    def __init__(self, root):
        self.root = root
        self.root.title("デジタル時計")
        self.root.geometry("420x280")
        self.root.configure(bg="#111")
        self.root.resizable(False, False)
        self._build_ui()
        self._tick()

    def _build_ui(self):
        # 時刻表示
        self.time_label = tk.Label(self.root, text="",
                                   font=("Courier New", 52, "bold"),
                                   bg="#111", fg="#00ff88")
        self.time_label.pack(expand=True, pady=(30, 0))

        # 日付表示
        self.date_label = tk.Label(self.root, text="",
                                   font=("Noto Sans JP", 16),
                                   bg="#111", fg="#aaa")
        self.date_label.pack(pady=(4, 0))

        # 曜日
        self.weekday_label = tk.Label(self.root, text="",
                                      font=("Noto Sans JP", 13),
                                      bg="#111", fg="#777")
        self.weekday_label.pack()

        # 秒ゲージ
        self.canvas = tk.Canvas(self.root, width=360, height=10,
                                bg="#222", highlightthickness=0)
        self.canvas.pack(pady=(16, 0))
        self.bar = self.canvas.create_rectangle(0, 0, 0, 10, fill="#00ff88", outline="")

    def _tick(self):
        now = datetime.now()
        self.time_label.config(text=now.strftime("%H:%M:%S"))
        self.date_label.config(text=now.strftime("%Y年%m月%d日"))
        weekdays = ["月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日", "日曜日"]
        self.weekday_label.config(text=weekdays[now.weekday()])
        # 秒ゲージ
        pct = now.second / 59
        self.canvas.coords(self.bar, 0, 0, int(360 * pct), 10)
        self.root.after(1000, self._tick)


if __name__ == "__main__":
    root = tk.Tk()
    app = App17(root)
    root.mainloop()

5. コード解説

デジタル時計のコードを、実際に書かれている実装に沿って解説します。

クラス設計とコンストラクタ

App17 クラスにアプリの全機能をまとめています(メソッド3個・全57行)。__init__ ではタイトル「デジタル時計」とウィンドウサイズ 420x280 を設定します。そのあと _build_ui()_tick() の順に呼び出して初期状態を作ります。

※ 該当部分のコード本体は 「4. 完全なソースコード」 をご参照ください(重複表示を避けるため再掲を省略しています)。

ウィジェット構成

画面は tk.Label×3・tk.Canvas で構成しています。

※ 該当部分のコード本体は 「4. 完全なソースコード」 をご参照ください(重複表示を避けるため再掲を省略しています)。

after() による定期処理

_tick() の末尾で after(1000, ...) を呼び、1000ミリ秒後に自分自身の再実行を予約しています。tkinter では while ループで待つと画面が固まるため、この「予約の連鎖」で定期処理を作るのが定石です。

※ 該当部分のコード本体は 「4. 完全なソースコード」 をご参照ください(重複表示を避けるため再掲を省略しています)。

例外処理を書いていない理由

このコードには try-except による例外処理がありません。テキスト入力欄も操作ボタンもなく表示だけで完結し、ファイルやネットワークへのアクセスも無い設計のため、例外を投げうる処理(型変換・ファイル/通信)がそもそも無いからです。入力欄やファイル保存を追加する改造をするときは、例外処理もセットで検討しましょう。

※ 該当部分のコード本体は 「4. 完全なソースコード」 をご参照ください(重複表示を避けるため再掲を省略しています)。

6. ステップバイステップガイド

このアプリをゼロから自分で作る手順を解説します。コードをコピーするだけでなく、実際に手順を追って自分で書いてみましょう。

  1. 1
    ファイルを作成する

    新しいファイルを作成して app17.py と保存します。使うのは datetimetkinter だけなので、追加インストールは不要です。

  2. 2
    クラスの骨格を作る

    App17 クラスを定義し、__init__ と、末尾の root = tk.Tk()mainloop() の最小構成を書いて、まず空のウィンドウが出ることを確認します。

  3. 3
    ウィンドウを設定する

    title("デジタル時計")geometry("420x280")configure(bg="#111")resizable(False, False) をコンストラクタで設定します。

  4. 4
    画面部品を並べる

    _build_ui() の中で、tk.Label×3・tk.Canvas を作って配置します(掲載コードと同じ並び順で書くとレイアウトが一致します)。まず表示だけ確認しましょう。

  5. 5
    中心になるメソッドを実装する

    アプリの本体である _tick()(10行) を実装します。定期処理は after(1000, ...) で自分自身を予約し続ける形にします。

  6. 6
    動作確認する

    python app17.py で起動し、表示が自動で更新されることを確認します。

7. カスタマイズアイデア

基本機能を習得したら、以下のカスタマイズに挑戦してみましょう。少しずつ機能を追加することで、Pythonのスキルが飛躍的に向上します。

💡 ダークモードを追加する

bg色・fg色を辞書で管理し、ボタン1つでダークモード・ライトモードを切り替えられるようにしましょう。

💡 更新間隔を変えてみる

after(1000, ...) の 1000 が更新間隔(ミリ秒)です。大きくすると更新頻度が下がって CPU 負荷が軽くなり、小さくすると更新が細かくなります(表示の刻み幅より細かくしても見た目は変わりません)。数値を変えて違いを確かめてみましょう。

💡 結果をファイルに保存する

このコードに保存処理はないため、表示中の数値や結果はアプリを閉じると消えます。テキストファイルへ書き出して、次回起動時に読み込む機能を追加してみましょう。

8. よくある問題と解決法

❌ 文字のフォントが崩れる・見た目が違う

原因:このコードは font=("Noto Sans JP", ...) のようにフォント名を直接指定しています。環境にこのフォントが入っていないと、OS が代わりのフォントで表示するため、見本と見た目が変わることがあります。

解決法:動作には支障ありません。気になる場合は font 引数の名前を自分の OS に入っているフォントへ書き換えるか、font 引数を省略してください。

❌ 改造したら表示の更新が二重になった・速くなった

原因:_tick()after(1000, ...) で自分自身を予約し続ける構造です。予約を止めずにもう一度開始経路を通ると、予約の連鎖が2本になり、更新が倍速になります。

解決法:開始処理の前に動作中かどうかをフラグで判定してください。

❌ ウィンドウの大きさが画面に合わない

原因:geometry("420x280") の固定サイズで起動するためです。

解決法:この数値を書き換えて起動サイズを調整してください。

9. 練習問題

アプリの理解を深めるための練習問題です。気になるものから挑戦してみてください(課題3は定型の発展課題です)。

  1. 課題1:12時間表示に切り替えるボタンを付ける

    このアプリの時刻は %H:%M:%S の24時間表示だけです。押すたびに「午後 09:05:30」のような12時間表示と行き来できるボタンを足しましょう。

    期待結果:起動直後は 21:05:30 のまま。ボタンを1回押すと 午後 09:05:30 に変わり、もう一度押すと24時間表示へ戻る。

    合格条件

    • ボタンを押すたびに、2つの表示が入れ替わる
    • 12時間表示のとき、正午より前は「午前」・正午以降は「午後」と出る
    • 日付・曜日・秒ゲージは、これまでどおり毎秒動く

    ヒント①(どこを触るか): 触るのは3か所です。__init__()self._build_ui() の手前に self.use_12h = False を1行、_build_ui() の末尾にボタンを1つ、そして _tick()self.time_label.config(...) です。
    ヒント②(使うもの): ボタンは tk.Button(self.root, text="表示切替", command=self._toggle).pack(pady=(10, 0)) の1行で足せます。_toggle() では self.use_12h = not self.use_12h と反転させ、12時間表記は now.strftime("%I:%M:%S")、午前・午後は "午前" if now.hour < 12 else "午後" で作ります。
    つまずきやすい点: %p を使うと環境によって AMPM と英語で出るため、午前・午後は自分で組み立てるほうが確実です。_tick()after(1000, self._tick) で1秒ごとに動く作りなので、押した瞬間に切り替えたい場合は _toggle() の中でも表示を書き直します。

  2. 課題2:時刻をクリックしてコピーできるようにする

    表示された時刻をメモに残したいとき、いまは目で読んで打ち直すしかありません。時刻の数字をクリックしたら、その時点の時刻がクリップボードに入るようにしましょう。

    期待結果:時刻の数字をクリックしてメモ帳に貼り付けると、21:05:30 のようにクリックした瞬間の時刻が入る。

    合格条件

    • 時刻をクリックすると、その時点の時刻が貼り付けられる
    • クリックし直すと、貼り付く内容も新しい時刻に入れ替わる
    • クリックしても、時計と秒ゲージは止まらない

    ヒント①(どこを触るか): 触るのは2か所です。_build_ui()self.time_label.pack(...) の下に bind を1行足し、新しいメソッドを1つ作ります。_tick() は触りません。
    ヒント②(使うもの): self.time_label.bind("<Button-1>", self._copy_time) で結び付け、_copy_time() の中で self.root.clipboard_clear()self.root.clipboard_append(self.time_label.cget("text")) を呼びます。
    つまずきやすい点: bind はイベントを引数で渡すので、def _copy_time(self, event): と受け取る形にしてください。引数が足りないと TypeErrortakes 1 positional argument but 2 were given)で止まります。クリップボードは tkinter が握っているため、貼り付ける前にアプリを閉じると内容が消えます。

  3. 課題3:メソッドを1つ選んで改造する

    「5. コード解説」で取り上げたメソッドを1つ選び、動きを少し変える改造をしてみましょう。変更前と後の挙動を見比べると、そのメソッドの役割がはっきり分かります。

🚀
次に挑戦するアプリ

このアプリをマスターしたら、次のアプリにも挑戦してみましょう。

🐛
エラーが出て動かないときは

写経中に赤いエラー文が出たら、Pythonエラー一覧&解決法(英語メッセージ逆引き)で原因と直し方をすぐ確認できます。

📖
独学を1冊で体系化するなら

写経しながら「なぜこう書くのか」が気になり始めたら、入門書を1冊通して読むと断片的な知識がつながります。Python入門書のおすすめ2冊(当サイトの参考書ランキング総合1〜2位)で、独学者向けの最初の1冊を比較しています。