显示 tkinter 上的所有项目 canvas

Show all items on the tkinter canvas

我在 tkinter 中有一个简单的程序,允许缩放 in/out 和平移 canvas。我正在尝试定义一个按钮,使我能够显示 canvas 上的所有项目。 代码如下:

##### Imports #####
import tkinter as tk
from tkinter import ttk

###################################################################
                         # FUNCTIONS #
###################################################################
# Defining zoom function -----------------------------------------------------------------------------------------------
def wheel(mainCanvas, event, arg):
    global x, y, delta, fontSize
    scale = 1.0

    if event.delta < 0:
        scale *= delta
        fontSize *=delta
    if event.delta > 0:
        scale /= delta
        fontSize /=delta

    # Rescaling canvas
    x = mainCanvas.canvasx(event.x)
    y = mainCanvas.canvasy(event.y)
    mainCanvas.scale('all', x, y, scale, scale)
    mainCanvas.configure(scrollregion=mainCanvas.bbox('all'))

    # Getting all the text item on the canvas
    for i in mainCanvas.find_withtag("text"):
        mainCanvas.itemconfigure(i, font=("Arial", int(fontSize)))
    print(fontSize)

# Defining pan function ------------------------------------------------------------------------------------------------
def move_from(mainCanvas, event, arg):
    global x, y
    mainCanvas.scan_mark(event.x, event.y)

def move_to(mainCanvas, event, arg):
    global x, y
    mainCanvas.scan_dragto(event.x, event.y, gain=1)

###################################################################
                           # MAIN #
###################################################################
def main():
    root = tk.Tk()
    root.title('Scroll and zoom')
    root.geometry("600x600")
    mainFrame = ttk.Frame(root).grid()

    vertBar = ttk.Scrollbar(root, orient='vertical')
    horiBar = ttk.Scrollbar(root, orient='horizontal')
    vertBar.grid(row=0, column=1, sticky='ns')
    horiBar.grid(row=1, column=0, sticky='we')

    mainCanvas = tk.Canvas(mainFrame, highlightthickness=0, xscrollcommand=horiBar.set, yscrollcommand=vertBar.set)
    mainCanvas.grid(row=0, column=0, sticky='nswe')

    # Binding scrollbars to the canvas and event binding to the canvas--------------------------------------------------
    vertBar.configure(command=mainCanvas.yview)
    horiBar.configure(command=mainCanvas.xview)
    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)

    global delta, fontSize
    delta = 0.9
    fontSize = 10

    mainCanvas.bind('<ButtonPress-1>', lambda event, arg=mainCanvas: move_from(mainCanvas, event, arg))
    mainCanvas.bind('<B1-Motion>', lambda event, arg=mainCanvas: move_to(mainCanvas, event, arg))
    mainCanvas.bind('<MouseWheel>', lambda event, arg=mainCanvas: wheel(mainCanvas, event, arg))

    # Drawing on the canvas and configuring canvas ---------------------------------------------------------------------
    x0 =100
    y0 = 100
    x1 = 200
    y1 = 200
    rect1 = mainCanvas.create_rectangle(x0, y0, x1, y1, outline='black', fill='grey', activefill='grey')
    rect2 = mainCanvas.create_rectangle(-x0*2, -y0*2, -x1*2, -y1*2, outline='black', fill='grey', activefill='grey')
    text = mainCanvas.create_text(100, 100, anchor='nw', text='Scroll to zoom', font=("Arial", int(fontSize)), tags='text', width=0)
    mainCanvas.configure(scrollregion=mainCanvas.bbox('all'))

    buttonShowAll = tk.Button(root, text='Show All')
    buttonShowAll.grid()

    root.mainloop()
###################################################################
                           # RUN #
###################################################################

def run():
    print('\nStart script')
    main()
    print('Finished script')

run()

我想要实现的是,在任何级别的缩放或平移位置,按钮 Show all 都可以显示 canvas 上的所有项目。如果没有 mainCanvas.delete('all')mainCanvas.destroy() 方法就可以实现这一目标。

您必须获得 bbox('all') 的项目大小和小部件的大小 Canvas 才能计算比例并缩放它

def show_all(mainCanvas):
    region = mainCanvas.bbox('all')
    
    old_width  = region[2] - region[0]
    old_height = region[3] - region[1]
    print('old:', old_width, old_height)
    
    new_width  = mainCanvas.winfo_width()
    new_height = mainCanvas.winfo_height()
    print('new:', new_width, new_height)

    scale = min(new_width/old_width, new_height/old_height)
    print('scale:', scale)
    
    centerx = (region[0] + region[2])/2
    centery = (region[1] + region[3])/2
    
    print('center:', centerx, centery)
    
    # rescale objects
    mainCanvas.scale('all', centerx, centery, scale, scale)

    mainCanvas.configure(scrollregion=mainCanvas.bbox('all'))

    # rescale font and text
    fontSize *= scale
    for i in mainCanvas.find_withtag("text"):
        mainCanvas.itemconfigure(i, font=("Arial", int(fontSize)))

    #TODO: center objects on canvas

完整的工作代码:

我不得不在 Linux 上添加 Button-4Button-5 并将 wheel() 更改为 运行 mousewheel

我更改了 mainFrame,因为您将 None 分配给了这个变量。

##### Imports #####
import tkinter as tk
from tkinter import ttk

###################################################################
                         # FUNCTIONS #
###################################################################
# Defining zoom function -----------------------------------------------------------------------------------------------

def wheel(mainCanvas, event, arg):
    global fontSize
    
    print('wheel', event, arg)    

    scale = 1.0

    if event.num == 5 or event.delta < 0:
        scale *= delta
        fontSize *=delta
    if  event.num == 4 or event.delta > 0:
        scale /= delta
        fontSize /=delta

    # Rescaling canvas
    x = mainCanvas.canvasx(event.x)
    y = mainCanvas.canvasy(event.y)
    mainCanvas.scale('all', x, y, scale, scale)
    mainCanvas.configure(scrollregion=mainCanvas.bbox('all'))

    # Getting all the text item on the canvas
    for i in mainCanvas.find_withtag("text"):
        mainCanvas.itemconfigure(i, font=("Arial", int(fontSize)))
#    print(fontSize)

# Defining pan function ------------------------------------------------------------------------------------------------

def move_from(mainCanvas, event, arg):
    print('move_from')
    mainCanvas.scan_mark(event.x, event.y)

def move_to(mainCanvas, event, arg):
    print('move_to')
    mainCanvas.scan_dragto(event.x, event.y, gain=1)

def show_all(mainCanvas):
    global fontSize
    
    region = mainCanvas.bbox('all')
    
    old_width  = region[2] - region[0]
    old_height = region[3] - region[1]
    print('old:', old_width, old_height)
    
    new_width  = mainCanvas.winfo_width()
    new_height = mainCanvas.winfo_height()
    print('new:', new_width, new_height)

    scale = min(new_width/old_width, new_height/old_height)
    print('scale:', scale)
    
    centerx = (region[0] + region[2])/2
    centery = (region[1] + region[3])/2
    
    print('center:', centerx, centery)
    
    # rescale objects
    mainCanvas.scale('all', centerx, centery, scale, scale)

    mainCanvas.configure(scrollregion=mainCanvas.bbox('all'))

    # rescale font and text
    fontSize *= scale
    for i in mainCanvas.find_withtag("text"):
        mainCanvas.itemconfigure(i, font=("Arial", int(fontSize)))

    #TODO: center objects on canvas
        
###################################################################
                           # MAIN #
###################################################################
def main():
    global delta, fontSize
    
    root = tk.Tk()
    root.title('Scroll and zoom')
    root.geometry("600x600")
    
    mainFrame = ttk.Frame(root)
    mainFrame.grid(row=0, column=0, sticky='news')
    root.grid_rowconfigure(0, weight=1)
    root.grid_columnconfigure(0, weight=1)

    vertBar = ttk.Scrollbar(root, orient='vertical')
    horiBar = ttk.Scrollbar(root, orient='horizontal')
    vertBar.grid(row=0, column=1, sticky='ns')
    horiBar.grid(row=1, column=0, sticky='we')

    mainCanvas = tk.Canvas(mainFrame, highlightthickness=0, xscrollcommand=horiBar.set, yscrollcommand=vertBar.set)
    mainCanvas.pack(fill='both', expand=True)

    # Binding scrollbars to the canvas and event binding to the canvas--------------------------------------------------
    vertBar.configure(command=mainCanvas.yview)
    horiBar.configure(command=mainCanvas.xview)

    delta = 0.9
    fontSize = 10

    mainCanvas.bind('<ButtonPress-1>', lambda event, arg=mainCanvas: move_from(mainCanvas, event, arg))
    mainCanvas.bind('<B1-Motion>', lambda event, arg=mainCanvas: move_to(mainCanvas, event, arg))
    mainCanvas.bind('<MouseWheel>', lambda event, arg=mainCanvas: wheel(mainCanvas, event, arg))
    mainCanvas.bind('<Button-5>', lambda event, arg=mainCanvas: wheel(mainCanvas, event, arg))
    mainCanvas.bind('<Button-4>', lambda event, arg=mainCanvas: wheel(mainCanvas, event, arg))
    
    # Drawing on the canvas and configuring canvas ---------------------------------------------------------------------
    x0 =100
    y0 = 100
    x1 = 200
    y1 = 200
    rect1 = mainCanvas.create_rectangle(x0, y0, x1, y1, outline='black', fill='grey', activefill='grey')
    rect2 = mainCanvas.create_rectangle(-x0*2, -y0*2, -x1*2, -y1*2, outline='black', fill='grey', activefill='grey')
    text = mainCanvas.create_text(100, 100, anchor='nw', text='Scroll to zoom', font=("Arial", int(fontSize)), tags='text', width=0)
    mainCanvas.configure(scrollregion=mainCanvas.bbox('all'))

    buttonShowAll = tk.Button(root, text='Show All', command=lambda:show_all(mainCanvas))
    buttonShowAll.grid()

    root.mainloop()
###################################################################
                           # RUN #
###################################################################

def run():
    print('\nStart script')
    main()
    print('Finished script')

run()