minofoto and miscellaneous notes

ごく気まぐれに,書きたいことを適当に書いています。本当の話かもしれませんし,フィクションかもしれません。

Ruby/Tk でマルチスレッドプログラム

Ruby/Tk でウィンドウ上のオブジェクトを定期的に更新するデモプログラムを作ってみました。
独立したスレッドからオブジェクトをそれぞれ更新するようにしてみます。試しに時計を表示させてみます。

require 'tk'

# ウィジェットの作成
button = TkButton.new(text: "exit", command: proc {p "exit"; exit})
label1 = TkLabel.new(text: "", font: ['',24])
label2 = TkLabel.new(text: "", font: ['',24])
label3 = TkLabel.new(text: "")

label1.pack
label2.pack
label3.pack
button.pack

Tk.mainloop

これで枠組みだけできました。

こんどは時計表示を更新する関数を作成

# カレンダーを更新
def update_calendar(label)
    now = Time.new
    label.configure(text: sprintf("%04d 年 %02d 月 %02d 日", now.year, now.month, now.day))
end

# 時計を更新
def update_clock(label)
    now = Time.new
    label.configure(text: sprintf("%02d : %02d : %02d", now.hour, now.min, now.sec))
end

この関数を呼び出すために、Tk.mainloop の前に以下の記述を追加します。

update_calendar(label1)
update_clock(label2)

時間が表示されました。

今度はこの時計を定期的に更新します。上記の2行をこのように書き換えます。

# 要素ごとにスレッドを立てて更新する
Thread.new {
    while true
      update_calendar(label1)
      sleep(60)
    end
}
Thread.new {
    while true
      update_clock(label2)
      sleep(1)
    end
}

Thread.new {} で並列に実行されるサブスレッドを作成します。スレッドが実行するのは {} の中の while true ~ end の無限ループ。
カレンダー表示の更新の後、 sleep(60) で 60 秒間待つため、1分間に1回カレンダーは更新されますが、時計の方は 1秒に一回更新されるはずです。

全部のコードはこんな感じ

require 'tk'

# カレンダーを更新
def update_calendar(label)
    now = Time.new
    label.configure(text: sprintf("%04d 年 %02d 月 %02d 日", now.year, now.month, now.day))
end

# 時計を更新
def update_clock(label)
    now = Time.new
    label.configure(text: sprintf("%02d : %02d : %02d", now.hour, now.min, now.sec))
end

# ウィジェットの作成
button = TkButton.new(text: "exit", command: proc {p "exit"; exit})
label1 = TkLabel.new(text: "", font: ['',24])
label2 = TkLabel.new(text: "", font: ['',24])
label3 = TkLabel.new(text: "")

# ウィジェットの配置
label1.pack
label2.pack
label3.pack
button.pack

# 要素ごとにスレッドを立てて更新する
Thread.new {
    while true
        update_calendar(label1)
        sleep(60)
    end
}
Thread.new {
    while true
        update_clock(label2)
        sleep(1)
    end
}
Tk.mainloop

これで、時計を毎秒更新する一方、カレンダーは毎分更新するマルチスレッドプログラムができました。