我有如下 GUI,如下图所示。我想在所有刻度上绘制一个透明矩形,而不是黑框,覆盖刻度的值1、0和-1。
有没有办法让 Tkinter 画布透明?如果这不是正确的方法,我可以尝试哪些替代方法?我分享了我使用的示例代码。这可以用来重现这个 GUI。
from tkinter import *
import itertools
root = Tk()
root.geometry('840x420')
root.title('Test Window')
variables = {"var1", "var2", "var3", "var4"}
pair_list = list(itertools.combinations(list(variables), 2))
pair_result_dictionary = dict.fromkeys(pair_list)
my_canvas = Canvas()
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
my_scrollbar = Scrollbar(root, orient=tk.VERTICAL, command=my_canvas.yview)
my_scrollbar.pack(side=RIGHT, fill=Y)
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))
second_frame = Frame(my_canvas)
my_canvas.create_window((0, 0), window=second_frame, anchor="nw")
i = 0
heading_label = Label(second_frame, text="Test Window", font=('Arial',16))
heading_label.grid(column=0, row=0, sticky=tk.NW, columnspan=2, padx=(52, 0), pady=(20, 10))
for pair in pair_list:
sample_scale = tk.Scale(second_frame, from_=9, to=-9, length=600, orient=tk.HORIZONTAL, font=('Arial', 15),
tickinterval=1,resolution=1)
label_left = tk.Label(second_frame, text=pair[0], font=('Arial', 15))
label_left.grid(column=0, row=2 + i, sticky=tk.W, padx=(52, 0), pady=5)
sample_scale.set(((sample_scale['from'] - sample_scale['to']) / 2) + sample_scale['to'])
sample_scale.grid(column=1, row=2 + i, sticky=tk.W, padx=(5, 0), pady=5)
label_right = tk.Label(second_frame, text=pair[1], font=('Arial', 15))
label_right.grid(column=2, row=2 + i, sticky=tk.W, padx=(5, 5), pady=5)
i = i + 100
rectangle_holder_canvas = tk.Canvas(second_frame, width=100, height=70, bd=0, background='#000000')
rectangle_holder_canvas.grid(column=1, row=2, sticky=tk.S, padx=(0, 0), pady=0)
rec = rectangle_holder_canvas.create_rectangle(3, 3, 100, 70, outline='blue', fill='')
rectangle_holder_canvas.tag_raise(rec, 'all')
root.mainloop()
如果我使用以下代码行,它会使整个正方形透明,并且会看到主窗口下方的内容,遗憾的是这不是我想要的。
root.wm_attributes("-transparentcolor", 'grey')
rectangle_holder_canvas = tk.Canvas(second_frame, width=100, height=70, bd=0, bg="grey")
感谢您对如何实现这一目标的想法和时间。
我读到了,
"tag_raise" method does not affect canvas window items. To change a window item's stacking order, use a lower or lift method on the window.
。所以我尝试通过设置 my_canvas
在 second_frame.lower()
上绘制一个矩形,如下代码所示。然后我只看到矩形,但看不到第二帧上的刻度或标签。
my_canvas.create_window((0, 0), window=second_frame.lower(), anchor=CENTER)
rec = my_canvas.create_rectangle(50, 50, 200, 200, outline='blue', fill='blue')
你的问题没有简单的答案。
画布对象的组织分为两组。 普通图形对象如矩形、多边形等按顺序堆叠 他们的创作过程,第一个对象在背景中,最后一个对象 在前台。这些对象的堆叠顺序可以通过以下方式更改
canvas.lift
、canvas.lower
、canvas.tag_raise
和 canvas.tag_lower
。
第二组是画布窗口对象,它们是使用 始终位于图形对象上方的固定堆叠顺序。 因此不可能将普通图形对象放置在窗口上方 物体。
这似乎会让你的目标变得不可能,但是(至少) 一种解决方案。
以下代码通过使用
Toplevel
窗口来实现您的目标,该窗口是
位于画布上方。此窗口使用 wm_attributes("-transparentcolor", color)
和 overrideredirect(1)
,它还设置 wm_attributes("-topmost", True)
。
然后通过“配置”将主窗口和顶部窗口绑定在一起 绑定,以便移动主窗口将自动移动顶部窗口。
这会产生您正在寻找的效果,尽管它可能不适合您的需求。
我使用了放置在画布窗口对象中的
Scale
对象之一来模拟
您的代码片段。
import tkinter as tk
color = "red"
class transParent(tk.Tk):
def __init__(self):
super().__init__()
self.withdraw()
self.columnconfigure(0, weight = 1)
wide, high = 606, 106
self.geometry(f"{wide}x{high}+20+20")
self.canvas = tk.Canvas(
self, background = color, highlightthickness = 0, borderwidth = 0)
self.canvas.grid(sticky = tk.NSEW)
self.s_scale = tk.Scale(
self.canvas, from_ = 9, to = -9, length = 600,
orient = tk.HORIZONTAL, font = "Arial 15",
takefocus = 1, tickinterval = 1, resolution = 1)
self.s_scale.set(0)
self.s_scale.grid(
column = 0, row = 0, sticky = tk.W, padx = 5, pady = 5)
self.sample_window = self.canvas.create_window(
0, 0, window = self.s_scale, anchor = tk.NW)
self.deiconify()
self.wait_visibility()
# build transparency toplevel : width, height, borderwidth
w, h, bw = 100, 100, 4
self.top = tk.Toplevel(
self, padx = 0, pady = 0, background = color,
highlightthickness = 0, relief = "solid", borderwidth = bw)
self.X, self.Y = self.winfo_x, self.winfo_y
self.top.geometry(f"{w}x{h}+{self.X()}+{self.Y()}")
self.top.wm_attributes("-transparentcolor", color)
self.top.overrideredirect(1)
self.top.wm_attributes("-topmost", True)
# estimate top position > trial & error?
self.xx, self.yy = int(wide / 2 - w / 2.4), int(high / 3.4)
# primary bindings
self.bind("<Configure>", self.moveit)
self.top.event_add(
"<<HOOD>>", "<Button-1>", "<Button-2>", "<Button-3>")
self.top.bind("<<HOOD>>", self.focal)
self.focus_force()
def moveit(self, ev):
self.top.geometry(f"+{self.X()+self.xx}+{self.Y()+self.yy}")
self.top.lift()
def focal(self, ev):
self.s_scale.focus_set()
if __name__ == "__main__":
app = transParent()
app.mainloop()
要在 Tkinter Scale 小部件上绘制矩形,您需要使用 Canvas 小部件。以下是实现此目标的分步指南:
创建一个 Tkinter 窗口。 添加一个缩放小部件。 创建一个 Canvas 小部件。 在 Canvas 小部件上绘制一个矩形并将其放置在 Scale 小部件上。 以下是演示这些步骤的示例代码:
import tkinter as tk
# Create the main window
root = tk.Tk()
root.title("Rectangle over Scale")
# Create a Scale widget
scale = tk.Scale(root, from_=0, to=100, orient=tk.HORIZONTAL)
scale.pack(pady=20)
# Create a Canvas widget
canvas = tk.Canvas(root, width=400, height=100)
canvas.pack()
# Coordinates for the rectangle (x1, y1, x2, y2)
x1, y1 = 50, 20
x2, y2 = 350, 80
# Draw the rectangle on the Canvas
rectangle = canvas.create_rectangle(x1, y1, x2, y2, fill="blue", stipple="gray25")
# Function to update rectangle position based on the scale value
def update_rectangle(val):
new_x2 = x1 + (int(val) / 100) * (350 - 50)
canvas.coords(rectangle, x1, y1, new_x2, y2)
# Bind the scale widget to update the rectangle on value change
scale.config(command=update_rectangle)
# Run the Tkinter main loop
root.mainloop()
说明: Tkinter 窗口:根是 Tkinter 主窗口。 比例小部件:创建水平比例并将其打包到窗口中。 Canvas Widget:创建具有指定宽度和高度的画布。 矩形:使用create_rectangle 在画布上绘制矩形。 更新函数: update_rectangle 函数根据 Scale 的值调整矩形的宽度。 绑定:将 Scale 小部件的命令选项设置为 update_rectangle 函数,确保当 Scale 值发生变化时矩形会更新。 通过执行以下步骤,您可以在 Tkinter 中的 Scale 小部件顶部覆盖一个矩形,并根据 Scale 的值动态调整其大小或位置。