Tkinter语言 - 画布滚动/滚动区域解释-(非)限制区域



这引起了我的注意,你不能用scrollregion = (0,0,0,0)来限制视图,问题是为什么会这样?因为官方文档会指出这应该可以工作,并且不会抛出和badRegion错误。

scrollregion:

指定一个包含四个坐标的列表,分别描述left, top,对,矩形区域的底部坐标。这个区域是用于滚动的目的,被认为是的边界画布中的信息。每个坐标都可以是在坐标部分给出的表格中指定。

扫描dragto:

该命令计算其x和y参数之间的差异(通常是鼠标坐标)和x和y参数小部件的最后一个扫描标记命令。然后,它调整视图增益乘以坐标差,其中增益默认为10。控件中的鼠标移动事件控件,以产生高速拖动画布的效果透过窗户。返回值为空字符串。

例子:

import tkinter
master = tkinter.Tk()
c = tkinter.Canvas(
master, width=100, height=100, bg="yellow", scrollregion=(0,0,0,0))
c.pack()
c.create_rectangle(0,0,20,20, outline="black", fill='green')
def scroll_start(event=None):
c.scan_mark(event.x, event.y)
def scroll_move(event=None):
c.scan_dragto(event.x, event.y, gain=1)
master.bind("<ButtonPress-1>", scroll_start)
master.bind("<B1-Motion>", scroll_move)
print('try to adjust the view by dragging')
master.mainloop()

TL;DR:

确保滚动区域大于画布,否则你的画布将被锚定在滚动区域周围。对于无限世界使用confine=False


说明:

  • 滚动区域,是保证在视图中,而不是你的项目!
  • scrollregion应该定义一个矩形的可视空间

尝试下面的例子和自己决定这是一个bug还是一个特性,并采取相应的行动。


这个误解是基于一个错误的假设,即scrollregion可能比画布可见区域要小,虽然在文档中没有直接指出这一点,但您可以在画布的c实现中找到提示。从CANV_SCAN调用CavnasSetOringin的注释:

如果有必要调整原点,以保持尽可能多的视图中的画布。变量left, right等记录如何在粘贴之前,视图的每一边都有很多额外的空间。超出滚动区域。如果有一边伸出来超过了滚动区域,调整视图,使该边回到边缘滚动区域(但不要移动太多,以免另一侧粘住)现在)。

因此,可滚动区域的基本思想和隐含条件是滚动区域(应该总是)大于可见区域并且应该像这样:

sx1           vx1    ix1    ix2    vx2            sx2
|             |      |      |      |              | 
+-------------------------------------------------+
|                                                 |
|             +--------------------+              |
|             |                    |              |
|             |      +------+      |              |
|             |      | item |      |              |
|             |      +------+      |              |
|             |                    |              |
|             |    visible area    |              |
|             +--------------------+              |
|                                                 |
|                  scroll region                  |
+-------------------------------------------------+

然而,核心开发人员决定,无论出于何种原因,当滚动区域小于可见区域时,它是一个有效区域。我猜将scrollregion绑定到'<Configure>'命令而不会产生错误是很方便的。参见源代码中的注释:

需要下面的调用来重新居中画布if它是受限的,它的滚动区域小于窗口。

您还应该注意,所有这些只适用于confine=True:

的画布

指定一个布尔值,指示是否应该控件定义的区域之外允许设置画布的视图scrollRegion论点。默认为true,这意味着视图将被限制在滚动区域内。

例子:

scrollregion匹配画布大小的例子

'''
This is an example where the scrollregion matches the dimensions of the Canvas.
- No dragging of the canvas-"world" is performed
- Scrollregion works with scan_dragto as expected
'''
import tkinter
master = tkinter.Tk()
c = tkinter.Canvas(
master, width=100, height=100, bg="yellow", scrollregion=(0,0,100,100))
c.pack()
c.create_rectangle(0,0,20,20, outline="black", fill='green')
def scroll_start(event=None):
c.scan_mark(event.x, event.y)
def scroll_move(event=None):
c.scan_dragto(event.x, event.y, gain=1)
master.bind("<ButtonPress-1>", scroll_start)
master.bind("<B1-Motion>", scroll_move)
print('try to adjust the view by dragging')
master.mainloop()

Scrollregion小于Canvas并且restrict =True

'''
This is an example where the scrollregion is smaller than the Canvas.
- Dragging of the canvas-"world" is performed
- You can drag the world until the point of scrollregion is on the edge
Additional notes:
The Canvas is 100 pixels wide and 100 pixels heigh.
You can drag the canvas-"world" until the "scrollregion",
in this case more of an anchor point, is about to leave
the visible area of the canvas.
Therefore when dragging with the mouse to south east:
The canvas will stop move the canvas-"world" behind.
To make this visible I have drawn a red rectangle at -100,-100.
'''
import tkinter
master = tkinter.Tk()
c = tkinter.Canvas(
master, width=100, height=100, bg="yellow", scrollregion=(0,0,0,0))
c.pack()
c.create_rectangle(0,0,20,20, outline="black", fill='green')
c.create_rectangle(-100,-100,-80,-80, outline="black", fill='red')
def scroll_start(event=None):
c.scan_mark(event.x, event.y)
def scroll_move(event=None):
c.scan_dragto(event.x, event.y, gain=1)
master.bind("<ButtonPress-1>", scroll_start)
master.bind("<B1-Motion>", scroll_move)
print('drag south east as far as possible')
master.mainloop()

confine=False为例

'''
This is an example where confine is set to False.
- Dragging of the canvas-"world" is performed
- You can drag the world to "infinity" (at least no known bounderies.
Additional notes:
When the items leave the visible space they are unmapped!
https://github.com/tcltk/tk/blob/main/generic/tkCanvas.c#L3142
'''
import tkinter
master = tkinter.Tk()
c = tkinter.Canvas(
master, width=100, height=100, bg="yellow", scrollregion=(0,0,0,0),
confine=False)
c.pack()
c.create_rectangle(0,0,20,20, outline="black", fill='green')
c.create_rectangle(-100,-100,-80,-80, outline="black", fill='red')
def scroll_start(event=None):
c.scan_mark(event.x, event.y)
def scroll_move(event=None):
c.scan_dragto(event.x, event.y, gain=1)
master.bind("<ButtonPress-1>", scroll_start)
master.bind("<B1-Motion>", scroll_move)
master.mainloop()

scrollregion大于canvas和confine=True的例子

'''
confine=True by default, scrollregion restricts area that can be displayed.
For demonstration a green rectangle is in the middle and red ones in the corners
'''
import tkinter
master = tkinter.Tk()
c = tkinter.Canvas(
master, width=100, height=100, bg="yellow", scrollregion=(-100,-100,200,200))
c.pack()
#rectangle arround the middle
c.create_rectangle(-10,-10,10,10, outline="black", fill='green')
#rectangle in upper left corner of the View
c.create_rectangle(-100,-100,-80,-80, outline="black", fill='red')
#rectangle in upper right corner of the View
c.create_rectangle(180,-100,200,-80, outline="black", fill='red')
#rectangle in bottom left corner of the View
c.create_rectangle(-100,180,-80,200, outline="black", fill='red')
#rectangle in bottom right corner of the View
c.create_rectangle(180,180,200,200, outline="black", fill='red')

def scroll_start(event=None):
c.scan_mark(event.x, event.y)
def scroll_move(event=None):
c.scan_dragto(event.x, event.y, gain=1)
master.bind("<ButtonPress-1>", scroll_start)
master.bind("<B1-Motion>", scroll_move)
master.mainloop()

最新更新