2014-11-21 90 views
1

我想要放在一起的用戶界面必須提供一長串輸入選擇。我已將輸入字段放入帶有滾動條的框架中,並使用滾動條進行滾動。但是當用戶退出視口時,滾動條不會自動跟隨它。Python3 tk.Scrollbar和焦點

我遇到的另一個問題是窗口大小不適合內容;如果我在populate()之後呼叫self.frame.grid(),窗口會爲內容做一些奇怪的東西和大小,但是如果窗口大小調整或者內容行數超過屏幕高度,則滾動條不再起作用。我想要窗口是min(maxSizeForRows, screenHeight),固定寬度但不是高度。

我很感激任何幫助或指針得到這個工作。

import tkinter as tk 
import tkinter.ttk as ttk 

class Test(tk.Canvas): 
    def __init__(self, root): 
     super().__init__(root, borderwidth=0) 
     self.root = root 

     self.vsb = tk.Scrollbar(root, orient="vertical", command=self.yview) 
     self.configure(yscrollcommand=self.vsb.set) 
     self.vsb.pack(side="right", fill="y") 

     self.frame = tk.Frame(self) 
     self.create_window((4,4), window=self.frame, anchor="nw", tags="self.frame") 

     self.pack(side="left", fill="both", expand=True) 

     self.frame.bind("<Configure>", self.onFrameConfigure) 

     self.populate() 


    def onFrameConfigure(self, event): 
     self.configure(scrollregion=self.bbox("all")) 


    def addRow(self, label, ent1, ent2): 
     row = self.row 

     lab = tk.Label(self.frame, text=label) 
     lab.grid(row=row, column=0, sticky='W') 

     sv = tk.StringVar() 
     sv.set(ent1) 
     e1 = tk.Entry(self.frame, width=16, justify=tk.RIGHT, textvariable=sv) 
     e1.grid(row=row, column=1) 

     sv = tk.StringVar() 
     sv.set(ent2) 
     e2 = tk.Entry(self.frame, width=16, justify=tk.RIGHT, textvariable=sv) 
     e2.grid(row=row, column=2) 

     self.row += 1 


    def populate(self): 

     self.row = 0 
     for i in range(0, 10): 
      self.addRow("Greeting", "Hello", "World") 
      self.addRow("Parting", "Ciao", "Banana") 
      self.addRow("Food", "Pepperoni", "Pizza") 
      self.addRow("Drink", "Cold", "Beer") 
      self.addRow("Actor", "Liam", "Neeson") 
      self.addRow("Occupation", "Software", "Engineer") 
      self.addRow("Languages", "Python", "Perl") 
      self.addRow("Browsers", "Chrome", "Firefox") 
      self.addRow("Places", "Irvine", "London") 
      self.addRow("States", "Cali", "Texas") 


if __name__ == "__main__": 
    root = tk.Tk() 
    app = Test(root=root) 
    app.pack(side="top", fill="both", expand=True) 
    app.mainloop() 
+0

我最終通過在每個級別明確使用網格AND包​​來獲得許多我想要的行爲,但是作爲回報,我也得到了滾動條無法工作的行爲,而且事情變得極其緩慢並帶有許多可見的更新。 – kfsone 2014-11-26 01:34:56

+0

使用網格和包沒有幫助。如果您在同一個小部件上同時使用這兩個小部件,則只有您調用的最後一個小部件纔會起作用。 – 2014-11-26 22:40:06

回答

1

要使用標籤,以微件視區之外,你會需要這樣,當他們得到集中在畫布上適當滾動添加綁定到錄入組件解決問題。這隻需要一點數學。它看起來是這樣的:

def __init__(...): 
    ... 
    # this makes it possible to scroll one pixel at a time 
    self.configure(yscrollincrement=1) 
    ... 

def addRow(...): 
    ... 
    e1.bind("<FocusIn>", self.scroll_into_view) 
    e2.bind("<FocusIn>", self.scroll_into_view) 
    ... 

def scroll_into_view(self, event): 
    widget_top = event.widget.winfo_y() 
    widget_bottom = widget_top + event.widget.winfo_height() 
    canvas_top = self.canvasy(0) 
    canvas_bottom = canvas_top + self.winfo_height() 

    if widget_bottom > canvas_bottom: 
     # subtract 4, because the frame is at 4,4 rather than 0,0 
     delta = int(canvas_bottom - widget_bottom) - 4 
     self.yview_scroll(-delta, "units") 
    elif widget_top < canvas_top: 
     delta = int(widget_top - canvas_top) + 4 
     self.yview_scroll(delta, "units") 

我的數學可能是一點點了,而且有辦法避免硬編碼4那裏,我會離開,作爲一個練習留給讀者。

至於調整大小的問題,如果我理解正確,那麼您需要綁定在畫布的<Configure>事件上,以便在畫布大小發生更改時更改框架的寬度。這看起來是這樣的:

def __init__(...): 
    ... 
    self.bind("<Configure>", self.onCanvasConfigure) 
    ... 

def onCanvasConfigure(self, event): 
    # subtract 8 to account for a border/margin 
    self.itemconfigure('self.frame', width=self.winfo_width()-8) 

你可能需要調整常數以獲得恰到好處的行爲,但希望這點你在正確的方向。

+0

非常感謝;我放棄了(4,4)以保持簡單,我從其他地方的例子中選擇了它,我想我真的不需要它。我無法解決讓滾動條和/或調整大小無縫工作,所以我最終設置了一個強制的寬度和混合網格和包(這讓我很難受)。如果你有興趣看到實際的實現,http://bitbucket.org/kfsone/tradedangerous ...它在命令/ update_gui.py中。 – kfsone 2014-11-27 08:24:40

+0

@kfsone:調用'canvas.grid(...)'緊接着'canvas.pack(...)'什麼都不做 - 對'grid(...)'的調用被忽略。 「grid」,「pack」或「place」中的任何一個都可以在任何時候控制一個小部件,並且最後一個要獲勝。當畫布在我的答案中更改大小時,您也沒有設置框架寬度。您想在_interior_幀調整大小時設置滾動區域,並且您希望在_canvas_調整大小時設置幀的寬度。 – 2014-11-27 13:20:28