使用Tkinter进行时间相关的色移(Python 2.7)

时间:2013-10-21 21:30:22

标签: python python-2.7 tkinter

我想编写一个程序,在给定的时间段内将Tkinter窗口的背景从初始的十六进制颜色淡化为最终的十六进制颜色,同时显示其间的一些颜色。 (取消注释第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()

但这两个例子之间的关键区别是什么?

1 个答案:

答案 0 :(得分:1)

这一行

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

不符合您的想法。此行立即使用参数set_colorroot评估hex_color_t函数。然后它会得到结果(在这种情况下偶然为None)并调度要在time ms中评估的结果(不用说,评估None不影响颜色根窗口)。

这就解释了为什么你的窗口会立即改变颜色 - 你的代码会一个接一个地引起所有的颜色变化,然后执行一系列无意义的预定评估。

您可以通过以下方式解决此问题:

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

createColorChangeFunction是必要的,因此各种lambda函数都有自己的本地引用,而不是共享一个。

我测试了这个变化,并且有一个窗口从黑暗到浅蓝色慢慢消失。