如何在 Tkinter 中制作颜色选择比例尺?

How do I make a color selection scale in Tkinter?

我正在尝试为 Tkinter 应用程序创建颜色选择范围。

我对 tkinter.colorchooser 模块或每个 RGB 通道的单独比例不感兴趣。我需要像 Photoshop 中的颜色滑块一样的单一比例尺。

我目前拥有的是一个垂直比例小部件,其 RGB 整数值从 0 (#000) 到 16777215 (#FFF)。问题是使用一系列 RGB 整数会导致非常奇怪的颜色序列——选择不会像下面的第一张图片那样从红色到粉红色再到蓝色等。

相反,我得到了第二张图片中的颜色序列。它压缩得很厉害,因为有 16777215 种不同的颜色被压缩到 300 个像素中。第三张图片是放大的。你可以看到它从黑色变成绿色,然后几乎从黑色变成绿色,等等



这是我的代码的相关部分:

MAXRGBINT = 16777215  # Corresponds to (255, 255, 255)
scale = ttk.Scale(slidframe, orient=VERTICAL, length=75,
                  from_=0, to=MAXRGBINT,
                  command=lambda _: set_color('sprite'))

基本上我想要一个比例小部件,它将按 "normal" 顺序显示颜色。我怎样才能用数值来做到这一点?

您可以使用 matplotlib 的预制颜色图(喷射、彩虹等)from matplotlib import cm,也可以创建您自己的颜色图,然后查看 rgb 值。您可以使用标准值通常以 256 个值 (last paragraph) 分隔的事实。如果这对你来说足够了,后者可能是最简单的。

这是你要问的吗?

你的问题是你对三维颜色使用一维尺度space。

对于您正在寻找的内容,我建议改用 HSL or HSV 颜色 space,并使用相关比例来操纵 Hue 参数。当您 需要 RGB 值时,您可以通过从 HSL/HSV 值转换来获取它们(我链接的维基百科页面解释了如何)。

回答有点晚,但我的解决方案是创建自定义 class。为了从用户那里获得颜色掩码(或过滤器),我在我的图像处理项目中多次使用它。 class...

import tkinter as tk
from PIL import Image, ImageDraw, ImageTk
import colorsys

class ColorRangeSelector:
    def __init__(self, root, x, y, w=255 , h=255 , bg='white', lineColor='black' , textColor = 'gray' , initial = [0,255] ):
        self.root=root
        self.x = x
        self.y = y
        self.w = w
        h=min(h, 255)
        self.h = h

        self.clicked_id = -1
        self.padding = 16
        self.canvas = tk.Canvas(self.root, width=w + 2 * self.padding, height=h + 2 * self.padding, bg=bg)
        self.result = initial.copy()

        image = Image.new("RGB", (w, h))
        draw = ImageDraw.Draw(image)

        w_adim= w/255
        for i in range(255):
            for j in range(255-h, 255):
                rgb = tuple(round(c * 255) for c in colorsys.hsv_to_rgb(i / 255, 1, j / 255))
                color= '#%02x%02x%02x' % rgb
                draw.rectangle( [i * w_adim , (j + h - 255) ,(i + 1) * w_adim , (j + h - 255) + 1 ], outline=None,fill=color)

        ph = ImageTk.PhotoImage(image)
        self.canvas.create_image(self.padding, self.padding, anchor='nw', image = ph)
        self.canvas.image = ph

        start_line = self.canvas.create_rectangle(initial[0]+ self.padding, self.padding,initial[0]+  self.padding+1, h+self.padding, width=0, fill=lineColor)
        start_select = self.canvas.create_rectangle(initial[0]+ self.padding/2, self.padding/2, initial[0]+ self.padding*3/2, self.padding, width=0, fill='black')
        start_text = self.canvas.create_text(initial[0]+ self.padding/2+7 ,self.padding/2+4,text='S',fill="white", font=('Helvetica 6 bold'))

        end_line = self.canvas.create_rectangle(initial[1]*w_adim-1+ self.padding, self.padding,initial[1]*w_adim+ self.padding, h+self.padding, width=0, fill=lineColor)
        end_select = self.canvas.create_rectangle(initial[1]*w_adim + self.padding/2, h+self.padding, initial[1]*w_adim+self.padding*3/2, h +self.padding*3/2, width=0,
                                                  fill='black')

        end_text = self.canvas.create_text(initial[1]*w_adim + self.padding/2+8, h+ self.padding+4, text='E', fill="white", font=('Helvetica 6 bold'))

        self.text = self.canvas.create_text(self.w/2 + self.padding, self.padding/2, text='[{:.2f},{:.2f}]'.format(self.result[0],self.result[1]), fill=textColor, font=('Helvetica 7 bold'))

        self.selectors = [start_select,start_line,start_text,end_select,end_line,end_text]

        self.canvas.bind( '<B1-Motion>', self.motion)
        self.canvas.bind('<ButtonRelease-1>', self.mouseReleased)
        self.canvas.place(x=x,y=y)

    def motion(self,event):
        if self.clicked_id and self.clicked_id < 0:
            self.clicked_id= self.getRectangle(event.x, event.y)
        if self.clicked_id:
            index = self.selectors.index(self.clicked_id)
            rect_y = self.padding/2
            if index>2:
                rect_y=self.h+self.padding

            line_id= self.selectors[index+1]
            text_id = self.selectors[index + 2]

            cur_x = event.x
            if event.x > self.w+self.padding:
                cur_x = self.w +self.padding
            if event.x < self.padding:
                cur_x = self.padding

            self.canvas.coords(line_id, cur_x, self.padding, cur_x + 1,self.h + self.padding)
            self.canvas.coords(self.clicked_id, cur_x-self.padding/2, rect_y, cur_x+self.padding/2, rect_y+self.padding/2)

            self.canvas.coords(text_id, cur_x, rect_y+4)

            self.result[int(index/3)] = (cur_x-self.padding)/self.w*255
            self.canvas.itemconfigure(self.text,text='[{:.2f},{:.2f}]'.format(self.result[0],self.result[1]))    

    def mouseReleased(self,event):
        self.clicked_id = -1

    def getRectangle(self,x, y):
        for i in range(2):
            sel = self.selectors[i*3]
            curr_xs, curr_ys, curr_xe, curr_ye = self.canvas.coords(sel)
            if (curr_xs <= x <= curr_xe) and (curr_ys <= y <= curr_ye):
                return sel

然后这样称呼它;

import tkinter as tk
from ColorRangeSelector import ColorRangeSelector

def getResults():
  label['text']= "FROM BUTTON:\ns1= {}\ns2={}\ns3={}".format(selector.result,selector2.result,selector3.result)

def getEventResults(self):
  label['text'] = "FROM EVENT ON ROOT:\ns1= {}\ns2={}\ns3={}".format(selector.result,selector2.result,selector3.result)

root = tk.Tk()
root.geometry("1000x500")

selector = ColorRangeSelector(root,10,70,900,30, bg='#ccc', lineColor='white', textColor='#222')
selector2 = ColorRangeSelector(root,50,150)
selector3 = ColorRangeSelector(root,400,150,510,100, initial=[70.5,203])

button = tk.Button(root, text ="Print Results", command = getResults)
label = tk.Label( root, text="")
button.place(x=0,y=0)
label.place(x=500,y=0)

root.bind( '<B1-Motion>', getEventResults)

root.mainloop()

结果:

只需将 [S]tart 和 [E]nd 滑块拖放到选择器 canvas 上 click here for screenshot