Python Tkinter:使用鼠标滚轮进行画布滚动

Python Tkinter:使用鼠标滚轮进行画布滚动,python,canvas,tkinter,treeview,mouseevent,Python,Canvas,Tkinter,Treeview,Mouseevent,我在画布中创建了一棵树,还允许鼠标滚轮上下滚动 但是,如果树内容未超过画布大小,如何防止滚动?(通过展开,树内容可能会超过画布大小) 请运行以下代码: from Tkinter import Tk, Frame, BOTH, Canvas from xml.dom.minidom import parseString from idlelib.TreeWidget import TreeItem, TreeNode class DomTreeItem(TreeItem): def __i

我在画布中创建了一棵树,还允许鼠标滚轮上下滚动

但是,如果树内容未超过画布大小,如何防止滚动?(通过展开,树内容可能会超过画布大小)

请运行以下代码:

from Tkinter import Tk, Frame, BOTH, Canvas
from xml.dom.minidom import parseString
from idlelib.TreeWidget import TreeItem, TreeNode

class DomTreeItem(TreeItem):
   def __init__(self, node):
      self.node = node
   def GetText(self):
      node = self.node
      if node.nodeType == node.ELEMENT_NODE:
         return node.nodeName
      elif node.nodeType == node.TEXT_NODE:
         return node.nodeValue
   def IsExpandable(self):
      node = self.node
      return node.hasChildNodes()
   def GetSubList(self):
      parent = self.node
      children = parent.childNodes
      prelist = [DomTreeItem(node) for node in children]
      itemlist = [item for item in prelist if item.GetText().strip()]
      return itemlist

data = '''
<top>
 <b>
  <c>d</c>
  <c>e</c>
 </b>
 <b>
  <c><c><c><c><c>f</c></c></c></c></c>
  <c><c><c><c><c>f</c></c></c></c></c>
  <c><c><c><c><c>f</c></c></c></c></c>
 </b>
</top>
'''

class Application(Frame):
   def __init__(self, parent):
      Frame.__init__(self, parent, background = "white")
      parent.configure(bg = "black")
      self.pack(fill = BOTH, expand = True, padx = 20, pady = 20)      
      self.parent = parent

      self.parent.geometry('%dx%d+%d+%d' % (700, 700, 0, 0))

      self.canvas = Canvas(self, bg = "white", bd = 10, highlightbackground = "black")
      self.canvas.grid(column = 0, row = 0, rowspan = 2)
      dom = parseString(data)
      item = DomTreeItem(dom.documentElement)
      node = TreeNode(self.canvas, None, item)
      node.update()
      node.expand()

      self.parent.bind("<MouseWheel>", self.mouse_wheel) # Windows mouse wheel event
      self.parent.bind("<Button-4>", self.mouse_wheel) # Linux mouse wheel event (Up)
      self.parent.bind("<Button-5>", self.mouse_wheel) # Linux mouse wheel event (Down)

   def mouse_wheel(self, event):
      """ Mouse wheel as scroll bar """
      direction = 0
      # respond to Linux or Windows wheel event
      if event.num == 5 or event.delta == -120:
         direction = 1
      if event.num == 4 or event.delta == 120:
         direction = -1
      self.canvas.yview_scroll(direction, "units")

def main():
   root = Tk()
   Application(root)
   root.mainloop()

if __name__ == '__main__':
   main()  
从Tkinter导入Tk、框架、两者、画布
从xml.dom.minidom导入解析字符串
从idlelib.TreeWidget导入TreeItem,TreeNode
类DomTreeItem(TreeItem):
定义初始化(自身,节点):
self.node=节点
def GetText(self):
node=self.node
如果node.nodeType==node.ELEMENT\u node:
返回node.nodeName
elif node.nodeType==node.TEXT\u节点:
返回node.nodeValue
def可扩展(自):
node=self.node
return node.hasChildNodes()
def GetSubList(自身):
父节点=self.node
children=parent.childNodes
prelist=[DomTreeItem(节点)表示子节点中的节点]
itemlist=[如果item.GetText().strip(),则预列表中的项对应于项]
返回项目列表
数据=“”
D
E
F
F
F
'''
课程申请(框架):
定义初始化(自身,父级):
帧。uuu init_uuuuuuuuuuuuu(自、父、背景=“白色”)
配置(bg=“黑色”)
self.pack(fill=BOTH,expand=True,padx=20,pady=20)
self.parent=parent
self.parent.geometry(“%dx%d+%d+%d%”(700700,0,0))
self.canvas=canvas(self,bg=“白色”,bd=10,highlightbackground=“黑色”)
self.canvas.grid(列=0,行=0,行跨度=2)
dom=parseString(数据)
item=DomTreeItem(dom.documentElement)
node=TreeNode(self.canvas,None,item)
node.update()
node.expand()
self.parent.bind(“,self.mouse_wheel)#Windows鼠标滚轮事件
self.parent.bind(“,self.mouse_wheel)#Linux鼠标滚轮事件(Up)
self.parent.bind(“,self.mouse_wheel)#Linux鼠标滚轮事件(向下)
def鼠标滚轮(自身、事件):
“”“鼠标滚轮作为滚动条”“”
方向=0
#响应Linux或Windows控制盘事件
如果event.num==5或event.delta==120:
方向=1
如果event.num==4或event.delta==120:
方向=-1
self.canvas.yview\u滚动条(方向,“单位”)
def main():
root=Tk()
应用程序(根)
root.mainloop()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()

我对树很不熟悉,但它看起来只是一堆标签。您可以测量它们的高度,并将它们与画布的高度进行比较,以确定是否需要滚动。这有点草率,但对我来说很有效:

if self.canvas.winfo_reqheight() < len(self.canvas.winfo_children()) * self.canvas.winfo_children()[0].winfo_reqheight():
    self.canvas.yview_scroll(direction, "units")
else:
    pass
如果self.canvas.winfo_reqheight()
编辑:如果这太混乱,下面是伪代码:

if CANVAS_HEIGHT < NUMBER_OF_LABELS * LABEL_HEIGHT:
    scroll
如果画布高度<标签数量*标签高度:
纸卷

您可以使用画布的
bbox
方法检索画布上绘制项目的实际高度
bbox
返回定义矩形的元组。您可以将其与画布小部件的高度进行比较

  height = self.canvas.winfo_height()
  _,_,_,items_height = self.canvas.bbox(Tkinter.ALL)
  if (items_height < height):
     direction = 0
height=self.canvas.winfo_height()
_,u,u,items\u height=self.canvas.bbox(Tkinter.ALL)
如果(项目高度<高度):
方向=0

我扩展了所有内容,因此需要滚动,但一旦我折叠了所有内容,它就不应该滚动。所以问题在扩展之前是固定的,但在扩展之后返回。我正在处理一个小的扩展列表,我没有考虑到这一点。如果我有什么想法,我会考虑一下,然后修改我的答案。谢谢。顺便说一下,在我的实际代码中,我在框架中定位画布时使用了sticky='NSWE'。因此,不确定显示的大小是否与canvas.winfo_reqheight()不同,我认为问题来自子列表的长度。当节点扩展时,它会增长,但当它们崩溃时,它们不会从列表中删除。是的,我也意识到了这一点,只是不知道如何处理这个问题。