如何在 Tkinter 中选择颜色?
Posted
技术标签:
【中文标题】如何在 Tkinter 中选择颜色?【英文标题】:How to select a color in Tkinter? 【发布时间】:2022-01-23 20:39:28 【问题描述】:我有一个用 Python 编写的程序,它使用 Tkinter 创建一个可以绘制的窗口。每次左键单击鼠标时,都会在画布上画一个点。双击时,会生成一个多边形,填充您选择的颜色。当您右键单击一个框时,我找到了一种从框更改颜色的方法,但问题是所选颜色未保存,我无法使其替换前一个颜色。有谁知道如何解决这个问题?
import tkinter as tk
from tkinter import colorchooser
class Point():
def __init__(self, canvas, x, y):
self.x = x
self.y = y
canvas.create_oval(x-2, y-2, x+2, y+2, fill='white')
class Poly():
def __init__(self, canvas, board, p_list=[] ):
self.p_list = p_list
self.canvas = canvas
self.board = board
def draw_poly(self):
points = []
for p in self.p_list:
points.extend([p.x, p.y])
points.extend(points[:2])
self.canvas.create_polygon(points, fill=self.board.current_color, outline=self.board.current_color)
def add_point(self, p):
self.p_list.append(p)
if len(self.p_list)>1:
p1 = self.p_list[-1]
p2 = self.p_list[-2]
self.canvas.create_line(p1.x, p1.y, p2.x, p2.y, fill="white", width=2)
class Palette():
def __init__(self, frame, board, colors):
self.colors = colors
self.board = board
self.allColors = []
for color in self.colors:
f = tk.Frame(frame, bg='lightgrey', bd=3)
f.pack(expand=1, fill='both', side='left')
if self.board.current_color == color: f.config(bg='red')
self.allColors.append(f)
l = tk.Label(f, bg=color)
l.pack(expand=1, fill='both', padx=2, pady=2)
l.bind("<1>", self.set_color)
l.bind("<Button-3>", self.do_popup)
def do_popup(self, event):
clsheet = tk.colorchooser.askcolor()
self.current_color = clsheet[1]
def set_color(self, e):
self.board.current_color = e.widget['bg']
self.selected_color(e.widget.master)
def selected_color(self, colorFrame):
for f in self.allColors: f.config(bg = 'lightgrey')
colorFrame.config(bg="red")
class Board():
def __init__(self, root):
self.colors = ['#B4FE98', '#77E4D4', '#F4EEA9', '#F0BB62', '#FF5F7E', "#9A0680"]
self.root = root
self.current_color = self.colors[0]
self.f1 = tk.Frame(self.root)
self.f1.pack(expand=1, fill='both', padx=5)
self.f2 = tk.Frame(self.root)
self.f2.pack(expand=1, fill='both')
self.canvas = tk.Canvas(self.f2, bg="#000D6B", height=550)
self.canvas.pack(expand=1, fill='both', padx=5, pady=5)
self.pallette = Palette(self.f1, self, self.colors )
self.canvas.bind("<1>", self.draw_point)
self.canvas.bind("<Double-Button-1>", self.draw_poly)
self.poly = None
def draw_point(self, evnt):
if self.poly: self.poly.add_point(Point(self.canvas, evnt.x, evnt.y))
else: self.poly = Poly(self.canvas, self, [Point(self.canvas, evnt.x, evnt.y)])
def draw_poly(self, evnt):
if self.poly and len(self.poly.p_list) > 2:
self.poly.add_point(Point(self.canvas, evnt.x, evnt.y))
self.poly.draw_poly()
self.poly = None
else: self.draw_point(evnt)
#main program
root = tk.Tk()
root.title('my program')
root.geometry("600x700")
root.resizable(0,0)
Board(root)
tk.mainloop()
【问题讨论】:
你在哪里遇到麻烦 您的意思是在创建填充多边形后,您希望能够从菜单中选择颜色并替换填充颜色? 是的,我的问题是我可以从菜单中选择颜色,但是颜色不能代替填充颜色 AFAI可以看到,colorchooser
没有使用
如何在程序运行时“保存”其他任何内容?通过分配一个变量,对吧?然后在需要时检查该值?您似乎已经通过self.board.current_color
尝试这样做。如果您正在寻求调试帮助,那么您应该以反映这一点的方式提出问题。
【参考方案1】:
为了修复无法右键单击颜色的部分,我在脚本中更改了两件事:
-
您将框架小部件及其子小部件标签存储在
Palette.allColors
中。我使用partial
将所选颜色的索引交给了do_popup 事件。然后,您可以简单地遍历 Palette.allColors
中的所有小部件,如果事件中的索引与列表中的索引匹配,则访问子级并进一步访问其中的 !label
键并将背景颜色更改为所选颜色。
我匹配了Board.current_color
和Palette.current_color
大部分更改是在Palette.do_popup()
中进行的。可能不是最优雅的解决方案,但它看起来像你想要的那样工作。完整代码:
import tkinter as tk
from tkinter import colorchooser
from functools import partial
class Point():
def __init__(self, canvas, x, y):
self.x = x
self.y = y
canvas.create_oval(x - 2, y - 2, x + 2, y + 2, fill='white')
class Poly():
def __init__(self, canvas, board, p_list=[]):
self.p_list = p_list
self.canvas = canvas
self.board = board
def draw_poly(self):
points = []
for p in self.p_list:
points.extend([p.x, p.y])
points.extend(points[:2])
self.canvas.create_polygon(points, fill=self.board.current_color, outline=self.board.current_color)
def add_point(self, p):
self.p_list.append(p)
if len(self.p_list) > 1:
p1 = self.p_list[-1]
p2 = self.p_list[-2]
self.canvas.create_line(p1.x, p1.y, p2.x, p2.y, fill="white", width=2)
class Palette():
def __init__(self, frame, board, colors):
self.colors = colors
self.board = board
self.allColors = []
for idx, color in enumerate(self.colors):
f = tk.Frame(frame, bg='lightgrey', bd=3)
f.pack(expand=1, fill='both', side='left')
if self.board.current_color == color: f.config(bg='red')
self.allColors.append(f)
l = tk.Label(f, bg=color)
l.pack(expand=1, fill='both', padx=2, pady=2)
l.bind("<1>", self.set_color)
l.bind("<Button-3>", partial(self.do_popup, idx))
def do_popup(self, idx, event):
clsheet = tk.colorchooser.askcolor()
self.current_color = clsheet[1].upper()
print(f"You chose: self.current_color")
self.board.current_color = self.current_color # required?
self.selected_color(event.widget.master)
for frm_idx, frm in enumerate(self.allColors):
if frm_idx == idx:
frm.children["!label"].config(bg=self.current_color)
def set_color(self, e):
self.board.current_color = e.widget['bg']
self.selected_color(e.widget.master)
def selected_color(self, colorFrame):
for f in self.allColors: f.config(bg='lightgrey')
colorFrame.config(bg="red")
class Board():
def __init__(self, root):
self.colors = ['#B4FE98', '#77E4D4', '#F4EEA9', '#F0BB62', '#FF5F7E', "#9A0680"]
self.root = root
self.current_color = self.colors[0]
self.f1 = tk.Frame(self.root)
self.f1.pack(expand=1, fill='both', padx=5)
self.f2 = tk.Frame(self.root)
self.f2.pack(expand=1, fill='both')
self.canvas = tk.Canvas(self.f2, bg="#000D6B", height=550)
self.canvas.pack(expand=1, fill='both', padx=5, pady=5)
self.pallette = Palette(self.f1, self, self.colors)
self.canvas.bind("<1>", self.draw_point)
self.canvas.bind("<Double-Button-1>", self.draw_poly)
self.poly = None
def draw_point(self, evnt):
if self.poly:
self.poly.add_point(Point(self.canvas, evnt.x, evnt.y))
else:
self.poly = Poly(self.canvas, self, [Point(self.canvas, evnt.x, evnt.y)])
def draw_poly(self, evnt):
if self.poly and len(self.poly.p_list) > 2:
self.poly.add_point(Point(self.canvas, evnt.x, evnt.y))
self.poly.draw_poly()
self.poly = None
else:
self.draw_point(evnt)
# main program
root = tk.Tk()
root.title('my program')
root.geometry("600x700")
root.resizable(0, 0)
Board(root)
tk.mainloop()
【讨论】:
这并不能解决 OP 的问题。请参阅this comment:OP 希望在画布上绘制的所有内容在被选中时都更改为选定的颜色。即使您选择不同的颜色,此代码也会保留形状的颜色。 @SylvesterKruin Hm - 重新阅读后 - 你可能是对的。让我们看看OP有什么要说的 哦等等...我注意到您确实修复了右键单击颜色更改不起作用的问题(抱歉,我没有对此进行测试)。所以这是 OP 需要的一部分,我猜。如果您编辑答案,我可以取消投票。问题不清楚;我只是通过阅读问题下方的说明来弄清楚他们真正想要什么:-/。 @SylvesterKruin 没问题 - 感谢您指出,我希望我的答案在编辑后现在更清楚。 :) 事实上,你得到了支持,因为你确实回答了 OP 的 问题,即 “如何在Tkinter?”。并感谢您让答案更清楚地说明它正在修复什么!以上是关于如何在 Tkinter 中选择颜色?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Windows 下更改 Tkinter 中菜单的颜色?
如何在 tkinter.ttk Treeview 上完全更改背景颜色
如何自定义 tkinter/ttk 小部件和框架的边框颜色?