Python:根据当前颜色更改 ttk 按钮颜色? [英] Python: Changing ttk button color depending on current color?

查看:47
本文介绍了Python:根据当前颜色更改 ttk 按钮颜色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我第一次尝试在 ttk 中使用样式做一些事情.我刚才的目标是在鼠标经过时突出显示一些样式按钮的背景颜色,但是按钮有一些状态并且在不同时刻会有不同的颜色,所以我尝试了这个:

I'm trying to do some things with styling in ttk for the first time. My goal just now is to highlight the background color of some styled buttons when the mouse goes over them, but the button has some states and will have different colors at different moments, so I tried this:

按钮代码

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

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

which attempts to set a random background color on the button.

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

My final goal is to get the current button's color and set that same color but lighter. For example, if the button is red, when the mouse goes over the button, set it with a lighter red. If it's yellow a lighter yellow, etc...

这个尝试只会在按钮上显示一些奇怪的东西,你可以用代码试验这些东西.所以我不知道如何在那里动态设置一个返回有效颜色的函数.

This attempt does nothing but show strange things on the button which you can experiment with the code. So I don't know how to dinamically set a function there which returns a valid color.

推荐答案

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

My final solution is this:

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

All the behaviour about color is encapsulated in the button widget.

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

I control the event with a handler which changes the background color for the active state with a lighter color.

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

Whenever the color changes, it does through a function of mine, so I trigger the '' event with .generate_event(), change the color and unbind the current handler for highlighting, and then bind a new handler for highlighting replacing the former.

我为样式相关的方法和函数制作了一个辅助的、可重用的模块:

I've made an auxiliar, reusable module for style-related methods and functions:

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

现在可能需要稍微更改调用代码以删除不必要的代码,但这会立即起作用.

It may be necessary to change the calling code a little bit to remove the unnecessary code now, but this will work straight away.

widgets.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()

这篇关于Python:根据当前颜色更改 ttk 按钮颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆