2017-10-05 252 views
-1

我想第一次在ttk中做一些样式的事情。我刚刚的目标是在鼠标移过它们时突出显示某些样式按钮的背景颜色,但按钮有一些状态,并且在不同时刻会有不同的颜色,所以我试过了:所以我试过了:Python:根据当前颜色更改ttk按钮颜色?

按钮代码

from PIL.ImageTk import PhotoImage 
import tkinter.ttk as ttk 
from random import random 

class ImgButton(ttk.Button): 
    def __init__(self, master=None, **kw): 
     super().__init__(master, **kw) 
     self.img = kw.get('image') 

class DiceFrame(ttk.Frame): 
    def __init__(self, master, *args, **kwargs): 
     super().__init__(master, *args, **kwargs) 

     currentImg = PhotoImage(file='anyFileYouWant.jpg') 

     style = ttk.Style() 
     style.configure('Die.TButton', 
         background='red', 
         borderwidth=8, 
         ) 

     def active_color(self): 
      # Test code. Final goal is get the current color and modify it 
      return random.choice(['blue', 'yellow', 'black', 'purple', 'cyan', 'brown', 'orange']) 

     style.map('Die.TButton', 
        background=[('active', active_color), ]) 

     # Don't worry. ImgButton extends the regular ttk Button. Almost equal 
     button = ImgButton(master, image=currentImg, style="Die.TButton") 
     button.pack(side=tk.LEFT) 

if __name__ == "__main__": 
    root = tk.Tk() 
    DiceFrame(root).pack(side="top", fill="both", expand=True) 
    root.mainloop() 

它试图设置按钮上的随机背景颜色。

我的最终目标是获取当前按钮的颜色,并设置相同的颜色,但更轻。例如,如果按钮为红色,则当鼠标移过按钮时,将其设置为较浅的红色。如果它是黄色,浅黄色等...

这个尝试只是在按钮上显示奇怪的东西,你可以试验一下代码。所以我不知道如何设置一个返回有效颜色的函数。

+0

对不起。我添加了一些进口和一堂课,但我现在必须走了。我将在稍后完成源代码。 – madtyn

+0

@ j_4321刚刚完成 – madtyn

回答

0

我的最终解决方案是这样的:

所有关于色彩的行为被封装在按钮部件。

我使用处理程序控制事件,该处理程序使用较浅的颜色更改活动状态的背景颜色。

每当颜色改变时,它会通过我的函数完成,所以我用.generate_event()触发''事件,更改颜色并解除当前处理程序的高亮显示,然后绑定一个新处理程序以突出显示替换前者。

我做了一个附配,样式相关的方法和功能可重复使用的模块:

styleUtils

import tkinter as tk 
import tkinter.ttk as ttk 
import random as rnd 

style = None 


def random_color(): 
    """ 
    Returns a random color as a string 
    :return: a color 
    """ 
    def r(): 
     return rnd.randint(0, 0xffff) 
    return '#{:04x}{:04x}{:04x}'.format(r(), r(), r()) 

def get_style(master=None): 
    """ 
    Returns the style object instance for handling styles 
    :param master: the parent component 
    :return: the style 
    """ 
    global style 
    if not style: 
     style = ttk.Style(master) if master else ttk.Style() 

    return style 


def get_style_name(widget): 
    """ 
    Returns the the name of the current style applied on this widget 
    :param widget: the widget 
    :return: the name of the style 
    """ 
    # .config('style') call returns the tuple 
    # (option name, dbName, dbClass, default value, current value) 
    return widget.config('style')[-1] 


def get_background_color(widget): 
    """ 
    Returns a string representing the background color of the widget 
    :param widget: a widget 
    :return: the color of the widget 
    """ 
    global style 
    color = style.lookup(get_style_name(widget), 'background') 
    return color 


def highlighted_rgb(color_value): 
    """ 
    Returns a slightly modified rgb value 
    :param color_value: one of three possible rgb values 
    :return: one of three possible rgb values, but highlighted 
    """ 
    result = (color_value/65535) * 255 
    result += (255 - result)/2 
    return result 


def highlighted_color(widget, color): 
    """ 
    Returns a highlighted color from the original entered 
    :param color: a color 
    :return: a highlight color for the one entered 
    """ 
    c = widget.winfo_rgb(color) 
    r = highlighted_rgb(c[0]) 
    g = highlighted_rgb(c[1]) 
    b = highlighted_rgb(c[2]) 
    return ("#%2.2x%2.2x%2.2x" % (round(r), round(g), round(b))).upper() 


def change_highlight_style(event=None): 
    """ 
    Applies the highlight style for a color 
    :param event: the event of the styled widget 
    """ 
    global style 
    widget = event.widget 
    current_color = get_background_color(widget) 
    color = highlighted_color(event.widget, current_color) 
    style.map(get_style_name(widget), background=[('active', color)]) 

可能需要改变调用代码一点点去除现在不需要的代码,但是这会马上工作。

小工具。PY(对于按钮的代码)

import os 
import tkinter as tk 
import tkinter.ttk as ttk 
from PIL.ImageTk import PhotoImage 

from user.myProject.view import styleUtils 

class ImgButton(ttk.Button): 
    """ 
    This has all the behaviour for a button which has an image 
    """ 
    def __init__(self, master=None, **kw): 
     super().__init__(master, **kw) 
     self._img = kw.get('image') 
     # TODO Replace this temporal test handler for testing highlight color 
     self.bind('<Button-1>', self.change_color) 

    def change_color(self, __=None): 
     """ 
     Changes the color of this widget randomly 
     :param __: the event, which is no needed 
     """ 
     import random as rnd 
     #Without this, nothing applies until the mouse leaves the widget 
     self.event_generate('<Leave>') 
     self.set_background_color(rnd.choice(['black', 'white', 'red', 'blue', 
               'cyan', 'purple', 'green', 'brown', 
               'gray', 'yellow', 'orange', 'cyan', 
               'pink', 'purple', 'violet'])) 
     self.event_generate('<Enter>') 

    def get_style_name(self): 
     """ 
     Returns the specific style name applied for this widget 
     :return: the style name as a string 
     """ 
     return styleUtils.get_style_name(self) 

    def set_background_color(self, color): 
     """ 
     Sets this widget's background color to that received as parameter 
     :param color: the color to be set 
     """ 
     styleUtils.get_style().configure(self.get_style_name(), background=color) 
     # If the color changes we don't want the current handler for the old color anymore 
     self.unbind('<Enter>') 
     # We replace the handler for the new color 
     self.bind('<Enter>', self.change_highlight_style) 

    def get_background_color(self): 
     """ 
     Returns a string representing the background color of the widget 
     :return: the color of the widget 
     """ 
     return styleUtils.get_style().lookup(self.get_style_name(), 'background') 

    def change_highlight_style(self, __=None): 
     """ 
     Applies the highlight style for a color 
     :param __: the event, which is no needed 
     """ 
     current_color = self.get_background_color() 
     # We get the highlight lighter color for the current color and set it for the 'active' state 
     color = styleUtils.highlighted_color(self, current_color) 
     styleUtils.get_style().map(self.get_style_name(), background=[('active', color)]) 

调用代码

import tkinter as tk 
import tkinter.ttk as ttk 

from widgets import ImgButton 


class DiceFrame(ttk.Frame): 
    def __init__(self, master, *args, **kwargs): 
     super().__init__(master, *args, **kwargs) 
     current_style = 'Die.TButton' 

     style = ttk.Style() 
     style.configure(current_style, 
         borderwidth=6, 
         ) 

     button = ImgButton(master, style=current_style) 
     button.pack(side=tk.LEFT) 


if __name__ == "__main__": 
    root = tk.Tk() 
    DiceFrame(root).pack(side="top", fill="both", expand=True) 
    root.mainloop() 
1

像你这样你不能给一个函数,而不是为活动背景颜色:

style.map('Die.TButton', background=[('active', active_color), ])

这就是为什么按钮有一个奇怪的行为,当它是积极的。

无论如何,你会想改变按钮背景每一次,你将必须配置“Die.TButton”的风格,让您可以在同一时间更改活动背景:

import tkinter as tk 
import tkinter.ttk as ttk 
import random 


def change_style(): 
    color = random.choice(['red', 'blue', 'yellow', 'dark gray', 'purple', 'cyan', 'brown', 'orange']) 
    style.configure('Die.TButton', background=color) 
    style.map('Die.TButton', background=[('active', active_color(color))]) 


def active_color(color): 
    c = root.winfo_rgb(color) 
    r = c[0]/65535 * 255 
    g = c[1]/65535 * 255 
    b = c[2]/65535 * 255 
    r += (255 - r)/2 
    g += (255 - g)/2 
    b += (255 - b)/2 
    return ("#%2.2x%2.2x%2.2x" % (round(r), round(g), round(b))).upper() 


root = tk.Tk() 

style = ttk.Style(root) 

button = ttk.Button(root, text='Test', style='Die.TButton') 
change_style() 
button.pack() 

ttk.Button(root, command=change_style, text='Change style').pack(padx=4, pady=10) 

root.mainloop() 

active_color使用winfo_rgb返回活动背景的较亮版本的颜色以获取该颜色的RGB代码。

+0

我刚读过它。我想我应该创建一个新的事件处理程序与'绑定()'将changeStyle绑定到'active'事件。我不应该吗? – madtyn

+0

@madtyn我不明白你在说什么事件。我对你的问题的理解是,在你的程序中的某一点,你改变了你的按钮的背景颜色,并且你希望活动颜色适应这种新颜色。 –

+0

是的,只要鼠标移过按钮。我几乎可以肯定,这是一个事件。如果你看看我的代码,我尝试了使用状态的map()函数,但是这些状态因事件而改变。我想它必须存在一个事件来改变状态为'active' – madtyn