[英]Tkinter - Canvas scrolling/scrollregion explained - (un-)restricted area
我注意到您不能使用例如scrollregion = (0,0,0,0)
來限制視圖,問題是為什么會這樣? 由於官方文檔表明這應該有效並且不會拋出badRegion
錯誤。
指定一個列表,其中包含四個坐標,描述矩形區域的左、上、右和下坐標。 該區域用於滾動目的,並被認為是 canvas 中信息的邊界。每個坐標都可以在下面的坐標部分中給出的任何 forms 中指定。
此命令計算其 x 和 y arguments(通常是鼠標坐標)與 x 和 y arguments 之間的差異,以用於小部件的最后一個掃描標記命令。 然后它通過增益乘以坐標差來調整視圖,其中增益默認為 10。此命令通常與小部件中的鼠標移動事件相關聯,以產生通過其 window 高速拖動 canvas 的效果。返回值是一個空字符串。
例子:
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()
確保滾動區域大於 canvas,否則您的 canvas 將被錨定在滾動區域周圍。 對於無限世界使用confine=False
要明確:
嘗試下面的示例並自行決定這是錯誤還是功能並采取相應措施。
誤解是基於滾動區域可能小於 canvas 可見區域的錯誤假設,雖然文檔中沒有直接指出這一點,但您會在 canvas 的 C 實現中找到提示CavnasSetOringin
的說明是從CANV_SCAN 調用:
如有必要,調整原點以在視圖中保留盡可能多的 canvas。 變量 left、right 等跟蹤視圖的每一側在超出滾動區域之前有多少額外空間。 如果一側伸出滾動區域的邊緣,請調整視圖以將該側帶回滾動區域的邊緣(但不要移動太多以至於另一側現在伸出)。
所以可滾動區域的基本思想和隱式條件是滾動區域(應該總是)大於可見區域並且應該看起來像這樣:
sx1 vx1 ix1 ix2 vx2 sx2
| | | | | |
+-------------------------------------------------+
| |
| +--------------------+ |
| | | |
| | +------+ | |
| | | item | | |
| | +------+ | |
| | | |
| | visible area | |
| +--------------------+ |
| |
| scroll region |
+-------------------------------------------------+
然而,核心開發人員決定,無論出於何種原因,當 scrollregion 小於可見區域時它是一個有效區域。 我猜想將scrollregion
綁定到'<Configure>'
命令會很方便,而不會出現錯誤。 見 源碼中的注釋:
如果 canvas 受到限制並且其滾動區域小於 window,則需要下面的調用才能使它重新居中。
您還應該知道,所有這些僅適用於 canvas where confine=True
:
指定一個 boolean 值,該值指示是否允許將畫布的視圖設置在由 scrollRegion 參數定義的區域之外。 默認為 true,這意味着視圖將被限制在滾動區域內。
滾動區域匹配大小為 canvas 的示例
'''
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 且 confine=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()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.