0

一定の期間、 Tkinterウィンドウの背景を最初の 16 進数の色から最後の 16 進数の色にフェードさせ、その間にいくつかの色を表示するプログラムを書きたいと思います。(行 99 のコメントを外すとprint time, hex_color_t、明確でない場合は、私の意味が明確になるはずです。)

コードは次のとおりです。

from Tkinter import *
from ttk import *
import re

class InvalidColor(Exception):
    pass

def color_to_hex(color):
    MIN_COLOR = 0
    MAX_COLOR = 255
    try:
        if color >= MIN_COLOR and color <= MAX_COLOR:
            try:
                hex_str = hex(color)[2:]
            except TypeError:
                raise InvalidColor
            if len(hex_str) < 2:
                hex_str = "0" + hex_str
            return hex_str
        else:
            raise InvalidColor
    except InvalidColor:
        return "00"

def rgb_to_hex((red, green, blue), upper = True):
    r = color_to_hex(red)
    g = color_to_hex(green)
    b = color_to_hex(blue)
    hex_str = "#%s%s%s" % (r, g, b)
    if upper:
        hex_str = hex_str.upper()
    return hex_str

def hex_to_rgb(hex_value):
    hex_pattern = re.compile(r"^(#)?(?P<r>[a-f0-9]{2})(?P<g>[a-f0-9]{2})(?P<b>[a-f0-9]{2})$", re.IGNORECASE)

    match = hex_pattern.match(hex_value)

    HEX_PREFIX = "0x"
    BASE = 16

    if match:
        # could be more DRY-ish, but whatever
        r = int(HEX_PREFIX + match.group("r"), BASE)
        g = int(HEX_PREFIX + match.group("g"), BASE)
        b = int(HEX_PREFIX + match.group("b"), BASE)
    else:
        raise InvalidColor

    return (r, g, b)

#print rgb_to_hex((255, 0, 0))
#print type(hex_to_rgb(rgb_to_hex((107,142,35))))
#print hex_to_rgb("4B0082")


root = Tk()

initial_color_hex = "#0000ff" # blue
final_color_hex = "#44ccff" # light blue

STOP_TIME_MS = 2000
STEP_TIME_MS = 50

"""
def final_color(*args, **kwargs):
    root.configure(background = final_color_hex)
"""

def set_color(root, hex_color, *args, **kwargs):
    root.configure(background = hex_color)

def linear_fade(root,
         hex_start_color,
         hex_stop_color,
         stop_time_ms = STOP_TIME_MS,
         step_time_ms = STEP_TIME_MS,
         delay_ms = 0):

    root.configure(background = hex_start_color)
    (r0, g0, b0) = hex_to_rgb(hex_start_color)
    (rf, gf, bf) = hex_to_rgb(hex_stop_color)

    delta_r = rf-r0
    delta_g = gf-g0
    delta_b = bf-b0

    #print delta_r, delta_g, delta_b

    for time in range(delay_ms, stop_time_ms+1, step_time_ms):
        rt = r0 + (delta_r * time // stop_time_ms)
        gt = g0 + (delta_g * time // stop_time_ms)
        bt = b0 + (delta_b * time // stop_time_ms)
        #print (rt, gt, bt)
        hex_color_t = rgb_to_hex((rt,gt,bt))
        #print time, hex_color_t
        root.after(time, set_color(root, hex_color_t))

root.configure(background = initial_color_hex)
#root.after(1000, final_color)

root.geometry("400x400")

linear_fade(root, initial_color_hex, final_color_hex)

root.mainloop()

これまでのところ、ウィンドウを作成せずにループを通過しているように見えるforので、遅延してから背景として最終的な色になります。

もっと最小限の実用的な例に行くべきだと思います。私は試した:

from Tkinter import *

root = Tk()

initial_color_hex = "#0000ff" # blue
final_color_hex = "#44ccff" # light blue

def set_color(hex_color, *args, **kwargs):
    root.configure(background = hex_color)

root.configure(background = initial_color_hex)
root.after(1000, set_color(final_color_hex))

root.geometry("400x400")

root.mainloop()

しかし、私はまだ同じ問題に遭遇します。私はどこかでうまくいくものを見つけました:

try:
    import tkinter
except ImportError:
    import Tkinter as tkinter

root = tkinter.Tk()

def grey(*args,**kwargs):
    root.configure(background = "grey")

def bthing():
    root.configure(background = "red")
    root.after(1000, grey)

tkinter.Button(text = "OK", command = bthing).pack()

root.configure(background = "grey")
root.geometry("400x400")

root.mainloop()

しかし、これら 2 つの例の決定的な違いは何でしょうか?

4

1 に答える 1

1

この行

root.after(time, set_color(root, hex_color_t))

あなたが思っていることをしません。この行は、引数およびを使用して関数をすぐに評価します。次に、結果を取得し (偶然にもこの場合です)、結果をミリ秒単位で評価するようにスケジュールします (言うまでもなく、評価はルート ウィンドウの色には影響しません)。 set_colorroothex_color_tNonetimeNone

これは、ウィンドウの色がすぐに変わる理由を説明しています。コードは、すべての色を次々と即座に変更し、一連の無意味なスケジュールされた評価を実行します。

これを行うことでこれを修正できます:

def createColorChangeFunction(hcolor):
    return lambda:set_color(root, hcolor)
root.after(time, createColorChangeFunction(hex_color_t))

これcreateColorChangeFunctionは、さまざまなラムダ関数が 16 進数の色を共有するのではなく、独自のローカル参照を持つために必要です。

この変更をテストしたところ、ウィンドウが暗い青色から明るい青色にゆっくりとフェードアウトしました。

于 2013-10-21T22:37:09.287 に答える