Python:根据当前颜色更改ttk按钮颜色?

时间:2017-10-05 10:27:22

标签: python-3.x tkinter ttk

我第一次尝试在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()

尝试在按钮上设置随机背景颜色。

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

此尝试只会在按钮上显示奇怪的内容,您可以尝试使用代码。因此,我不知道如何在其中设置一个返回有效颜色的函数。

3 个答案:

答案 0 :(得分: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代码。

答案 1 :(得分:0)

我的最终解决方案是:

关于颜色的所有行为都封装在按钮小部件中。

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

每当颜色发生变化时,它都会通过我的功能,因此我会触发“''使用.generate_event()的事件,更改颜色并取消绑定当前处理程序以突出显示,然后绑定一个新的处理程序以突出显示替换前者。

我为样式相关的方法和功能制作了一个辅助的,可重复使用的模块:

<强> styleUtils

<!DOCTYPE html>
<html>
<head>
<body>
  <canvas id="Photo" width="200" height="230" style="border:1px solid #000000;">
  Your browser does not support the HTML5 canvas tag.
  </canvas>
  <script>
    var canvas = document.getElementById("Photo");
    var ctx = canvas.getContext("2d");
    ctx.font = "30px Arial";
    ctx.fillText("Photo Here",20,110);
  </script>
  <canvas id="About" width="500" height="230" style="border:1px solid #000000;">
  Your browser does not support the HTML5 canvas tag.
  </canvas><br>
  <script>
    var canvas = document.getElementById("About");
    var ctx = canvas.getContext("2d");
    ctx.font = "30px Arial";
    ctx.fillText("About Page",150,110);
  </script>
  <canvas id="Real_Name" width="200" height="30" style="border:1px solid #000000;">
  Your browser does not support the HTML5 canvas tag.
  </canvas>
  <script>
    var canvas = document.getElementById("Real_Name");
    var ctx = canvas.getContext("2d");
    ctx.font = "15px Arial";
    ctx.fillText("Real Name",60,20);
  </script><br>
  <canvas id="Role" width="200" height="30" style="border:1px solid #000000;">
  Your browser does not support the HTML5 canvas tag.
  </canvas>
  <script>
    var canvas = document.getElementById("Role");
    var ctx = canvas.getContext("2d");
    ctx.font = "15px Arial";
    ctx.fillText("Role",81,20);
  </script><br>
  <canvas id="WhatsApp" width="200" height="30" style="border:1px solid #000000;">
  Your browser does not support the HTML5 canvas tag.
  </canvas><br>
  <script>
    var canvas = document.getElementById("WhatsApp");
    var ctx = canvas.getContext("2d");
    ctx.font = "15px Arial";
    ctx.fillText("WhatsApp",60,20);
  </script>
  <canvas id="Email" width="200" height="30" style="border:1px solid #000000;">
  Your browser does not support the HTML5 canvas tag.
  </canvas>
  <script>
    var canvas = document.getElementById("Email");
    var ctx = canvas.getContext("2d");
    ctx.font = "15px Arial";
    ctx.fillText("Email",77,20);
  </script>

</body>
</html>

可能需要稍微更改调用代码以删除不必要的代码,但这将立即生效。

widgets.py(按钮代码)

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)])

致电代码

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)])

答案 2 :(得分:0)

ttk按钮外观由主题(3D / Color-alt /经典/默认,Color-clam)驱动。如果未设置/其他设置,则按钮将保持为平/灰色,并且设置不会更改任何内容。 要使ttk TButton改变颜色,可以使用map来实现。 3D外观需要borderwidth。只有Classic会使用高光形成外圈。下方s.map的背景逻辑:活动和按下(黄色)、!活动(绿色),活动和!按下(青色)。救济可以单独定义。无需修改这些按钮方面的功能。但是,highlightcolor必须使用s.configure更新。该框架只能调用一个主题。

import tkinter as tk
from tkinter import ttk
root=tk.Tk();
s = ttk.Style(); 
s.theme_use('classic');
s.configure('zc.TButton',borderwidth='20')
s.configure('zc.TButton',highlightthickness='10')
s.configure('zc.TButton',highlightcolor='pink')
s.map('zc.TButton',background=[('active', 'pressed', 'yellow'),('!active','green'), ('active','!pressed', 'cyan')])
s.map('zc.TButton',relief=[('pressed','sunken'),('!pressed','raised')]);
calc_button=ttk.Button(root, text="classic", style='zc.TButton');
calc_button.grid(column=0,row=0,sticky='nsew');
root.mainloop()