2017-08-08 131 views
1

我目前正在掙扎使用滾動框架內的Tkinter畫布。通過滾動框架,我的意思是Gonzo給另一個線程(Python Tkinter scrollbar for frame)給出的框架 - 畫布結構。我已經適應了這個概念並添加了水平滾動條。現在,在內部框架的頂部,我想放置一個具有給定最小尺寸的畫布。在這個最小尺寸小於內部框架(或整個窗口)的情況下,沒有問題(因爲不需要滾動)。但是,如果我將窗口大小調整爲小於畫布的值(這是滾動條應該有用的條件),則畫布不會被縮小到所需的大小(在下面的示例中,不是寬度= 500px),而是在幀的較小尺寸(寬度= 400px)時被截斷。滾動條處於活動狀態,滾動仍處於500px的內部框架。滾動框架內的畫布

下面我給你一些關於代碼和問題的更多細節。

謝謝你的關注。我很感謝這個問題的任何幫助,也許我只是在做一些明顯錯誤的事情。

乾杯, C.

ScrollFrame類(存儲在scrollframe.py):

from Tkinter import * 

class ScrollFrame(Frame): 
    def __init__(self, parent, yscroll=True, xscroll=True, *args, **kw): 
     Frame.__init__(self, parent, *args, **kw) 
     self.canvas = Canvas(self, bd=0, highlightthickness=0) 
     if xscroll: 
      hscrollbar = Scrollbar(self, orient=HORIZONTAL) 
      hscrollbar.pack(fill=X, side=BOTTOM, expand=FALSE) 
      self.canvas.config(xscrollcommand=hscrollbar.set) 
      hscrollbar.config(command=self.canvas.xview) 
     if yscroll: 
      vscrollbar = Scrollbar(self, orient=VERTICAL) 
      vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE) 
      self.canvas.config(yscrollcommand=vscrollbar.set) 
      vscrollbar.config(command=self.canvas.yview) 
     self.canvas.pack(side=LEFT, fill=BOTH, expand=TRUE) 

     # reset the view 
     self.canvas.xview_moveto(0) 
     self.canvas.yview_moveto(0) 

     # create a frame inside the canvas which will be scrolled with it 
     self.interior = interior = Frame(self.canvas, bg="blue") 
     self.interior_id = self.canvas.create_window(0, 0, window=interior, anchor=NW) 

     # track changes to the canvas and frame width and sync them, 
     # also updating the scrollbar 
     def _configure_interior(event): 
      # update the scrollbars to match the size of the inner frame 
      size = (interior.winfo_reqwidth(), interior.winfo_reqheight()) 
      print "interior req: ",size,(interior.winfo_width(),interior.winfo_height()) 
      self.canvas.config(scrollregion="0 0 %s %s" % size) 
      if interior.winfo_reqwidth() != self.canvas.winfo_width() or interior.winfo_reqheight() != sel f.canvas.winfo_height(): 
       # update the canvas's width to fit the inner frame 
       self.canvas.config(width=interior.winfo_reqwidth(), height=interior.winfo_reqheight(),) 
     interior.bind('<Configure>', _configure_interior) 

     def _configure_canvas(event): 
      if interior.winfo_reqwidth() != self.canvas.winfo_width() or interior.winfo_reqheight() != sel f.canvas.winfo_height(): 
       # update the inner frame's width to fill the canvas 
       self.canvas.itemconfigure(self.interior_id, width=self.canvas.winfo_width(), height=self.c anvas.winfo_height()) 
     self.canvas.bind('<Configure>', _configure_canvas) 

的主要代碼: 從Tkinter的進口* 從scrollframe進口*

root = Tk() 
root.geometry("400x300") 

frame = Frame(root, bg="blue") 
frame.pack(expand=True, fill=BOTH) 

sf = ScrollFrame(frame, bg="yellow") 
sf.pack(expand=True, fill=BOTH) 

sf.interior.config(width=500, height=400) 
canvas = Canvas(sf.interior, width=500, height=400, bg="green") 
canvas.pack(expand=True, fill=BOTH, side="top") 

root.mainloop() 

運行時,看起來像這樣: 1. canvas at top left corner (not yet scrolled) 2. canvas at bottom right corner (after scrolling)

問題:綠色帆布應該是所需的尺寸(500/400),但它似乎是滾動條連接到(400/300)而不是內部的祖母框架的尺寸框架,它是滾動的(500/400),它是畫布的母框。

回答

1

_configure_canvas方法是問題的根源。它將self.interior框架的尺寸調整爲self.canvas的寬度,並且因爲canvas已經與選項expand=True, fill=BOTH一起打包,所以它被調整爲400x300。

另外,這個函數對於獲得一個滾動框不是必須的,唯一需要的是調整self.canvas滾動區域的大小,每次調整self.interior的大小。

這裏是修改後的代碼:

from Tkinter import * 

class ScrollFrame(Frame): 
    def __init__(self, parent, yscroll=True, xscroll=True, *args, **kw): 
     Frame.__init__(self, parent, *args, **kw) 
     self.canvas = Canvas(self, bd=0, highlightthickness=0) 
     if xscroll: 
      hscrollbar = Scrollbar(self, orient=HORIZONTAL) 
      hscrollbar.pack(fill=X, side=BOTTOM, expand=FALSE) 
      self.canvas.config(xscrollcommand=hscrollbar.set) 
      hscrollbar.config(command=self.canvas.xview) 
     if yscroll: 
      vscrollbar = Scrollbar(self, orient=VERTICAL) 
      vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE) 
      self.canvas.config(yscrollcommand=vscrollbar.set) 
      vscrollbar.config(command=self.canvas.yview) 
     self.canvas.pack(side=LEFT, fill=BOTH, expand=TRUE) 

     # reset the view 
     self.canvas.xview_moveto(0) 
     self.canvas.yview_moveto(0) 

     # create a frame inside the canvas which will be scrolled with it 
     self.interior = interior = Frame(self.canvas, bg="blue") 
     self.interior_id = self.canvas.create_window(0, 0, window=interior, anchor=NW) 

     # track changes to the frame width and update the scrollregion 
     def _configure_interior(event): 
      # update the scrollbars to match the size of the inner frame 
      self.canvas.config(scrollregion=self.canvas.bbox('all')) 
     interior.bind('<Configure>', _configure_interior) 

root = Tk() 
root.geometry("400x300") 

frame = Frame(root, bg="blue") 
frame.pack(expand=True, fill=BOTH) 

sf = ScrollFrame(frame, bg="yellow") 
sf.pack(expand=True, fill=BOTH) 

sf.interior.config(width=500, height=400) 
canvas = Canvas(sf.interior, width=500, height=400, bg="green") 
canvas.pack(expand=True, fill=BOTH, side="top") 

root.mainloop()