为什么Python的Tkinter画布无法滚动?

5
为什么无法使用苹果魔术鼠标的垂直和水平滑动/滚动来响应Python tkinter画布? 画布的滚动条正常工作(即当我在鼠标上水平滑动/滚动但不是垂直滑动/滚动时,水平滚动条有效;而当我垂直滑动/滚动时,垂直滚动条移动但不对任何水平滑动/滚动运动做出反应),但画布不会对鼠标的任何滑动/滚动做出反应。

以下是我的示例/测试代码:

from tkinter import *
import tkinter.ttk as ttk
from PIL import Image, ImageTk
root = Tk()

h = Scrollbar(root, orient=HORIZONTAL)
v = Scrollbar(root, orient=VERTICAL)
canvas = Canvas(root, scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set)
h['command'] = canvas.xview
v['command'] = canvas.yview
theImage = ImageTk.PhotoImage(Image.open('example.png')) #Assume a very large image
canvas.create_image(0,0,image=theImage, anchor='nw')
canvas.grid(column=0, row=0, sticky=(N,W,E,S))
h.grid(column=0, row=1, sticky=(W,E))
v.grid(column=1, row=0, sticky=(N,S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()

我对Python和tkinter都是一个完全的新手,但我觉得这应该非常简单和明显(或者至少可行)。然而,我已经找了很久,还是找不到答案(尽管我可能使用了错误的术语进行搜索)。
如何让画布对来自Magic Mouse的滚动/滑动输入做出反应,就像滚动条已经做到的那样?
编辑:我正在使用Python 3.4、Tkinter 8.5.18、Mac OS X 10.9.5和一个Apple Magic Mouse。
2个回答

4
假设魔术鼠标的滚动和滑动输入与标准触控板上的滚动区域类似,您需要绑定<MouseWheel><Shift-MouseWheel>事件。

先放代码,然后是一些注释。

from tkinter import *
import tkinter.ttk as ttk
from PIL import Image, ImageTk

def on_vertical(event):
    canvas.yview_scroll(-1 * event.delta, 'units')

def on_horizontal(event):
    canvas.xview_scroll(-1 * event.delta, 'units')

root = Tk()
h = Scrollbar(root, orient=HORIZONTAL)
v = Scrollbar(root, orient=VERTICAL)
canvas = Canvas(root, scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set)
h['command'] = canvas.xview
v['command'] = canvas.yview
theImage = ImageTk.PhotoImage(Image.open('img'))
canvas.create_image(0,0,image=theImage, anchor='nw')
canvas.grid(column=0, row=0, sticky=(N,W,E,S))

canvas.bind_all('<MouseWheel>', on_vertical)
canvas.bind_all('<Shift-MouseWheel>', on_horizontal)

h.grid(column=0, row=1, sticky=(W,E))
v.grid(column=1, row=0, sticky=(N,S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()

如您所见,只有两个更改。

  1. 有两个回调函数来处理滚动事件 on_verticalon_horizontal
  2. 画布的 <MouseWheel><Shift-MouseWheel> 事件分别绑定到 on_verticalon_horizontal

谢谢!你的解决方案有效,尽管最初增量方向是错误的。但是通过在回调函数中在事件增量前加上负号很容易解决这个问题。 - IntrepidArtisan
是的,很抱歉,我使用的是Windows系统,所以滚轮增量必须除以120并取反,当我去掉除法时,不小心也去掉了否定。我更新了代码来修复这个错误。很高兴它对你有用。 - theB
它在最新的High Sierra上无法工作。我收到了“UnicodeDecodeError”的错误。 - Piotr Wasilewicz

0
使用ntk Canvas创建一个可滚动的画布,默认情况下它适用于鼠标滚轮,但是如果你创建一个 ntk Scrollbar 小部件,并将其分配给画布,那么一切就准备就绪了。
ntk在tkinter之上工作,可以通过pip从pypi安装它。
pip install ntk

使用 NTK 小部件获得美观的设计。
from ntk import Tk, Canvas, Scrollbar

def main():
    root = Tk()

canvas = Canvas(root)

    root.mainloop()    

if __name__=='__main__':
    main()

这个画布可以通过鼠标滚轮进行滚动,但如果你想要设置一个带有滚动条的画布,你可以创建一个滚动条小部件,并将这个画布对象作为第二个参数传递。

scroll = Scrollbar(root, canvas)

你可以通过配置或在创建画布时传递参数来更改可滚动区域

canvas = Canvas(root, scrollregion=[0,0,100,50]) # [x1, y1, x2, y2]

或通过配置进行设置

canvas.config(scrollregion=[0,0,100,50])

欢迎来到简洁代码中的美丽设计,愉快编码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接