2017-10-05 248 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