【发布时间】:2021-07-16 15:11:38
【问题描述】:
我正在尝试使用鼠标滚轮控制多个画布宽度。我到目前为止是这样的:
import tkinter as tk
class App(tk.Frame):
row_amount = 3
def __init__(self, root):
super(App, self).__init__(root)
self.root = root
self.main_frame = tk.Frame(root)
self.main_frame.pack(expand=True, fill=tk.BOTH)
self.row_collection = RowCollection(root, self.main_frame)
for i in range(App.row_amount): self.row_collection.row()
window_height = App.row_amount * 100
window_width = root.winfo_screenwidth() - 30
root.geometry(f'{window_width}x{window_height}+0+0')
self.row_collection.right_frame.grid_columnconfigure(0, weight=1)
self.row_collection.left_frame.grid_columnconfigure(0, weight=1)
self.pack()
class RowCollection:
"""Collection of rows"""
def __init__(self, root, frame):
self.row_list = []
self.root = root
self.frame = frame
self.right_frame = tk.Frame(self.frame, bg='red')
self.right_frame.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.BOTH)
self.left_frame = tk.Frame(self.frame)
self.left_frame.pack(side=tk.LEFT, fill=tk.Y)
self.scrollbar = tk.Scrollbar(self.right_frame, orient=tk.HORIZONTAL)
self.scrollbar.config(command=self.scroll_x)
def row(self):
row = Row(self)
self.row_list.append(row)
return row
def scroll_x(self, *args):
for row in self.row_list:
row.canvas.xview(*args)
def zoomer(self, event=None):
print('zooming')
for row in self.row_list:
scale_factor = 0.1
curr_width = row.canvas.winfo_reqwidth()
print(f'event delta={event.delta}')
if event.delta > 0:
row.canvas.config(width=curr_width * (1 + scale_factor))
elif event.delta < 0:
row.canvas.config(width=curr_width * (1 - scale_factor))
row.canvas.configure(scrollregion=row.canvas.bbox('all'))
class Row:
"""Every row consists of a label on the left side and a canvas with a line on the right side"""
row_count = 0
label_width = 15
line_weight = 3
line_yoffset = 3
padx = 20
def __init__(self, collection):
self.frame = collection.frame
self.root = collection.root
self.collection = collection
self.canvas = None
self.label = None
self.text = f'Canvas {Row.row_count}'
self.height = 100
self.root.update()
self.label = tk.Label(self.collection.left_frame,
text=self.text,
height=1,
width=Row.label_width,
relief='raised')
self.label.grid(row=Row.row_count, column=0, sticky='ns')
# configure row size to match future canvas height
self.collection.left_frame.grid_rowconfigure(Row.row_count, minsize=self.height)
self.root.update()
self.canvas = tk.Canvas(self.collection.right_frame,
width=10000,
height=self.height,
bg='white',
highlightthickness=0)
self.canvas.grid(row=Row.row_count, column=0, sticky=tk.W)
self.root.update()
# draw line
self.line = self.canvas.create_rectangle(self.padx,
self.canvas.winfo_height() - Row.line_yoffset,
self.canvas.winfo_width() - self.padx,
self.canvas.winfo_height() - Row.line_yoffset + Row.line_weight,
fill='#000000', width=0, tags='line')
# config canvas
self.canvas.config(scrollregion=self.canvas.bbox('all'))
self.canvas.config(xscrollcommand=self.collection.scrollbar.set)
self.canvas.bind('<Configure>', lambda event: self.canvas.configure(scrollregion=self.canvas.bbox('all')))
self.canvas.bind('<MouseWheel>', self.collection.zoomer)
# Create point at canvas edge to prevent scrolling from removing padding
self.bounding_point = self.canvas.create_rectangle(0, 0, 0, 0, width=0)
self.bounding_point = self.canvas.create_rectangle(self.canvas.winfo_width(), self.canvas.winfo_width(),
self.canvas.winfo_width(), self.canvas.winfo_width(),
width=0)
Row.row_count += 1
self.collection.scrollbar.grid(row=Row.row_count, column=0, sticky='ew')
if __name__ == '__main__':
root = tk.Tk()
app = App(root)
root.mainloop()
画布本身在right_frame 内部,画布数量由row_amount 给出。 left_frame 包含每个画布的标签。画布应该可以很宽,所以我最初将宽度值设置为 10000。因此,它们开始部分可见,其余部分可通过滚动条访问。
我希望鼠标滚轮控制整个画布的大小(即当前可见的内容和可以使用滚动条查看的内容),类似于音频或视频编辑软件时间线。
现在,当我使用鼠标滚轮时,似乎调整大小的不是整个画布,而只是“可见”部分。将其调整到足够小,您可以开始在窗口右侧看到它的框架背景。
我在这里错过了什么?
【问题讨论】:
-
“应该允许画布非常宽,所以我最初设置的宽度值是 10000。” - 你有 10,000 像素宽的显示器吗?那将是令人印象深刻的!
-
确实会:)。但不幸的是,不,不是现在。我想要实现的是音频或视频编辑软件中的时间线。我正在尝试控制画布的宽度,以便稍后实现水平缩放功能。到目前为止,我对使用
scale的缩放方法没有运气,所以我想我可以更改画布宽度并重绘所有画布对象。它的效率非常低,但我并不期待有很多画布对象,所以我猜它会足够快以使其可用。 -
好的,所以“宽度”实际上并不是指画布的物理宽度。您正在谈论画布的可滚动区域。画布的宽度和可绘制区域无关。你知道你可以画出远远超出画布物理尺寸的东西吗?
-
是的!确切地说,可滚动区域。我想这就是我所说的“整个画布”。我不知道这个词指的是什么,对不起。如果我做对了,我的“可见画布”正是
width属性所指的,毕竟,因此是行为。 -
鉴于此,我的
zoomer函数应该更改scrollregion而不是width。对吗?
标签: python tkinter tkinter-canvas tkinter-layout