簡體   English   中英

Tkinter - Canvas scrolling/scrollregion explained - (un-)restricted area

[英]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


要明確:

  • 滾動區域保證在視圖中,而不是您的項目中!
  • scrollregion應該定義一個可視空間的矩形

嘗試下面的示例並自行決定這是錯誤還是功能並采取相應措施。


誤解是基於滾動區域可能小於 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM