2013-04-24 64 views
29

Mục tiêu của tôi là thêm thanh cuộn dọc vào một khung có một số nhãn trong đó. Thanh cuộn sẽ tự động được kích hoạt ngay sau khi các nhãn trong khung vượt quá chiều cao của khung. Sau khi tìm kiếm, tôi đã tìm thấy this bài đăng hữu ích. Dựa trên bài viết đó tôi hiểu rằng để đạt được những gì tôi muốn, (đúng tôi nếu tôi sai, tôi là người mới bắt đầu), tôi phải tạo một Frame trước, sau đó tạo Canvas bên trong khung đó và dán thanh cuộn vào đó cũng vậy. Sau đó, tạo một khung khác và đặt nó bên trong khung làm đối tượng cửa sổ. Vì vậy, cuối cùng tôi đưa ra với điều nàyThanh cuộn Tkinter của Python cho khung

from Tkinter import * 

def data(): 
    for i in range(50): 
     Label(frame,text=i).grid(row=i,column=0) 
     Label(frame,text="my text"+str(i)).grid(row=i,column=1) 
     Label(frame,text="..........").grid(row=i,column=2) 

def myfunction(event): 
    canvas.configure(scrollregion=canvas.bbox("all"),width=200,height=200) 

root=Tk() 
sizex = 800 
sizey = 600 
posx = 100 
posy = 100 
root.wm_geometry("%dx%d+%d+%d" % (sizex, sizey, posx, posy)) 

myframe=Frame(root,relief=GROOVE,width=50,height=100,bd=1) 
myframe.place(x=10,y=10) 

canvas=Canvas(myframe) 
frame=Frame(canvas) 
myscrollbar=Scrollbar(myframe,orient="vertical",command=canvas.yview) 
canvas.configure(yscrollcommand=myscrollbar.set) 

myscrollbar.pack(side="right",fill="y") 
canvas.pack(side="left") 
canvas.create_window((0,0),window=frame,anchor='nw') 
frame.bind("<Configure>",myfunction) 
data() 
root.mainloop() 
  1. Am Tôi làm việc đó phải không? Có cách nào tốt hơn/thông minh hơn để đạt được đầu ra mã này đã cho tôi?
  2. Tại sao tôi phải sử dụng phương pháp lưới? (Tôi đã thử phương pháp địa điểm, nhưng không có nhãn nào xuất hiện trên canvas.)
  3. Điều gì đặc biệt về việc sử dụng anchor = 'nw' khi tạo cửa sổ trên canvas?

Hãy giữ câu trả lời của bạn đơn giản như tôi mới bắt đầu. Cảm ơn bạn đã giúp đỡ.

+1

Bạn có nó ngược trong câu hỏi của bạn, mặc dù các mã có vẻ đúng ở cái nhìn đầu tiên. Bạn phải tạo một khung, nhúng vào khung hình, sau đó đính kèm thanh cuộn vào khung vẽ. –

+2

bản sao có thể có của [Thêm thanh cuộn vào lưới ô của các tiện ích trong Tkinter] (http://stackoverflow.com/questions/3085696/adding-a-scrollbar-to-a-grid-of-widgets-in-tkinter) –

+0

@TrevorBoydSmith Có rất nhiều thứ này là một bản sao tiềm năng, nhưng tôi đã bỏ phiếu để đóng bản sao này dưới dạng bản sao của một số khác có vẻ như có câu trả lời hay nhất: http://stackoverflow.com/questions/1873575/how-could -i-get-a-frame-with-a-scrollbar-in-tkinter – ArtOfWarfare

Trả lời

14

Tôi có làm đúng không? Có cách nào tốt hơn/thông minh hơn để đạt được kết quả mà mã này đã cung cấp cho tôi không?

Nói chung, có, bạn đang làm đúng. Tkinter không có vùng chứa có thể cuộn nào khác ngoài khung vẽ. Như bạn có thể thấy, nó thực sự không khó để thiết lập. Như ví dụ của bạn cho thấy, nó chỉ mất 5 hoặc 6 dòng mã để làm cho nó hoạt động - tùy thuộc vào cách bạn đếm các dòng.

Tại sao tôi phải sử dụng phương pháp lưới? (Tôi đã cố gắng phương pháp diễn ra, nhưng không ai trong số các nhãn xuất hiện trên vải?)

Bạn hỏi về lý do tại sao bạn phải sử dụng lưới điện.Không có yêu cầu sử dụng lưới điện. Nơi, lưới và gói tất cả có thể được sử dụng. Nó chỉ đơn giản là một số tự nhiên phù hợp hơn với các loại vấn đề cụ thể. Trong trường hợp này có vẻ như bạn đang tạo ra một lưới thực tế - hàng và cột nhãn - vì vậy lưới là sự lựa chọn tự nhiên.

Điều gì đặc biệt về việc sử dụng anchor = 'nw' khi tạo cửa sổ trên canvas?

Dấu neo cho bạn biết phần nào của cửa sổ được đặt ở tọa độ bạn đưa ra. Theo mặc định, trung tâm của cửa sổ sẽ được đặt ở tọa độ. Trong trường hợp mã của bạn ở trên, bạn muốn góc trên bên trái ("phía tây bắc") nằm ở tọa độ.

28

Xin lưu ý rằng mã đề xuất chỉ có giá trị với Python 2

Dưới đây là một ví dụ:

from Tkinter import * # from x import * is bad practice 
from ttk import * 

# http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame 

class VerticalScrolledFrame(Frame): 
    """A pure Tkinter scrollable frame that actually works! 
    * Use the 'interior' attribute to place widgets inside the scrollable frame 
    * Construct and pack/place/grid normally 
    * This frame only allows vertical scrolling 

    """ 
    def __init__(self, parent, *args, **kw): 
     Frame.__init__(self, parent, *args, **kw)    

     # create a canvas object and a vertical scrollbar for scrolling it 
     vscrollbar = Scrollbar(self, orient=VERTICAL) 
     vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE) 
     canvas = Canvas(self, bd=0, highlightthickness=0, 
         yscrollcommand=vscrollbar.set) 
     canvas.pack(side=LEFT, fill=BOTH, expand=TRUE) 
     vscrollbar.config(command=canvas.yview) 

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

     # create a frame inside the canvas which will be scrolled with it 
     self.interior = interior = Frame(canvas) 
     interior_id = 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()) 
      canvas.config(scrollregion="0 0 %s %s" % size) 
      if interior.winfo_reqwidth() != canvas.winfo_width(): 
       # update the canvas's width to fit the inner frame 
       canvas.config(width=interior.winfo_reqwidth()) 
     interior.bind('<Configure>', _configure_interior) 

     def _configure_canvas(event): 
      if interior.winfo_reqwidth() != canvas.winfo_width(): 
       # update the inner frame's width to fill the canvas 
       canvas.itemconfigure(interior_id, width=canvas.winfo_width()) 
     canvas.bind('<Configure>', _configure_canvas) 


if __name__ == "__main__": 

    class SampleApp(Tk): 
     def __init__(self, *args, **kwargs): 
      root = Tk.__init__(self, *args, **kwargs) 


      self.frame = VerticalScrolledFrame(root) 
      self.frame.pack() 
      self.label = Label(text="Shrink the window to activate the scrollbar.") 
      self.label.pack() 
      buttons = [] 
      for i in range(10): 
       buttons.append(Button(self.frame.interior, text="Button " + str(i))) 
       buttons[-1].pack() 

    app = SampleApp() 
    app.mainloop() 

Nó vẫn chưa có bánh xe chuột ràng buộc với thanh cuộn nhưng nó có thể . Tuy nhiên, việc cuộn bằng bánh xe có thể hơi gập ghềnh.

chỉnh sửa:

-1)
IMHO khung di chuyển là một chút khó khăn trong Tkinter và dường như không được thực hiện rất nhiều. Có vẻ như không có cách nào thanh lịch để làm điều đó.
Một vấn đề với mã của bạn là bạn phải đặt kích thước canvas theo cách thủ công - đó là mã ví dụ mà tôi đã đăng giải quyết.

đến 2)
Bạn đang nói về chức năng dữ liệu? Nơi làm việc cho tôi, quá. (Nói chung tôi thích lưới).

đến 3)
Vâng, nó đặt vị trí cửa sổ trên canvas.

Một điều tôi nhận thấy là ví dụ của bạn xử lý cuộn bánh xe chuột theo mặc định trong khi ví dụ tôi đăng không. Sẽ phải xem xét một thời gian.

+0

mặc dù bạn không trả lời câu hỏi của tôi, cảm ơn ví dụ của bạn.Nhưng tôi không muốn viết nhiều dòng mã chỉ cho một khung có cuộn thanh khi toàn bộ kịch bản của tôi là ngắn hơn ví dụ của bạn.Trong thực tế, mẫu mã của tôi sẽ làm các trick mặc dù tôi không có ý tưởng tại sao tôi không thể sử dụng phương pháp đặt. –

+1

@ChrisAung: Điều tuyệt vời về giải pháp này là nó có một lớp có thể tái sử dụng, 'VerticalScrolledFrame', mà bạn có thể sử dụng như là một thay thế cho bất kỳ' Khung' nào. Đi với mã trong giải pháp của bạn, bạn cần phải viết lại tất cả mã đó cho mỗi 'Khung hình' duy nhất mà bạn muốn có thể cuộn. Với mã này, nó gần như là một thay thế drop-in cho 'Frame'. Vì vậy, không ngần ngại sử dụng nó trên tài khoản của số dòng. Giải pháp của anh ta là nhiều mã hơn nếu bạn chỉ cần một khung cuộn đơn. Nếu bạn cần hai, cả hai kỹ thuật lấy một số tiền bằng nhau, và anh ta có thể duy trì được nhiều hơn (ít dư thừa hơn.) – ArtOfWarfare

+0

Tiếp tục từ trên cao: Nếu bạn cần nhiều hơn 2 khung cuộn, giải pháp của anh ta tốn ít mã hơn và dễ dàng hơn nhiều duy trì. Có nói tất cả những điều đó, tôi sẽ không sử dụng giải pháp này trên tài khoản của các caveats nó có. Ngoài ra, tôi không thích yêu cầu sử dụng '.interior' - tôi muốn có một giao diện làm cho' .interior' là một chi tiết triển khai thay vì làm cho nó một cái gì đó mà người sử dụng nó phải biết. – ArtOfWarfare

2

Chúng tôi có thể thêm thanh cuộn ngay cả khi không sử dụng Canvas. Tôi đã đọc nó trong nhiều bài khác, chúng tôi không thể thêm thanh cuộn dọc trong khung trực tiếp vv vv Nhưng sau khi thực hiện nhiều thử nghiệm tìm ra cách để thêm dọc cũng như thanh cuộn ngang :). Vui lòng tìm mã bên dưới được sử dụng để tạo thanh cuộn trong treeView và khung.

f = Tkinter.Frame(self.master,width=3) 
f.grid(row=2, column=0, columnspan=8, rowspan=10, pady=30, padx=30) 
f.config(width=5) 
self.tree = ttk.Treeview(f, selectmode="extended") 
scbHDirSel =tk.Scrollbar(f, orient=Tkinter.HORIZONTAL, command=self.tree.xview) 
scbVDirSel =tk.Scrollbar(f, orient=Tkinter.VERTICAL, command=self.tree.yview) 
self.tree.configure(yscrollcommand=scbVDirSel.set, xscrollcommand=scbHDirSel.set)   
self.tree["columns"] = (self.columnListOutput) 
self.tree.column("#0", width=40) 
self.tree.heading("#0", text='SrNo', anchor='w') 
self.tree.grid(row=2, column=0, sticky=Tkinter.NSEW,in_=f, columnspan=10, rowspan=10) 
scbVDirSel.grid(row=2, column=10, rowspan=10, sticky=Tkinter.NS, in_=f) 
scbHDirSel.grid(row=14, column=0, rowspan=2, sticky=Tkinter.EW,in_=f) 
f.rowconfigure(0, weight=1) 
f.columnconfigure(0, weight=1) 
+0

Tôi không hiểu những câu trả lời này 'sử dụng "Tkinter", "tk" và "ttk". Tôi chỉ mong đợi một tiền tố như vậy trong mỗi ví dụ, nhưng thứ ba có cả ba. Đưa cái gì? – 4dummies

7

Vui lòng xem lớp học của tôi là khung có thể cuộn. Thanh cuộn dọc cũng được liên kết với sự kiện <Mousewheel>. Vì vậy, tất cả những gì bạn phải làm là tạo ra một khung hình, điền vào nó với các vật dụng theo cách bạn thích, và sau đó làm cho khung này là một đứa trẻ của ScrolledWindow.scrollwindow của tôi. Hãy hỏi nếu có điều gì đó không rõ ràng.

sử dụng rất nhiều từ @ Brayan Oakley câu trả lời để đóng vào đó câu hỏi

class ScrolledWindow(tk.Frame): 
    """ 
    1. Master widget gets scrollbars and a canvas. Scrollbars are connected 
    to canvas scrollregion. 

    2. self.scrollwindow is created and inserted into canvas 

    Usage Guideline: 
    Assign any widgets as children of <ScrolledWindow instance>.scrollwindow 
    to get them inserted into canvas 

    __init__(self, parent, canv_w = 400, canv_h = 400, *args, **kwargs) 
    docstring: 
    Parent = master of scrolled window 
    canv_w - width of canvas 
    canv_h - height of canvas 

    """ 


    def __init__(self, parent, canv_w = 400, canv_h = 400, *args, **kwargs): 
     """Parent = master of scrolled window 
     canv_w - width of canvas 
     canv_h - height of canvas 

     """ 
     super().__init__(parent, *args, **kwargs) 

     self.parent = parent 

     # creating a scrollbars 
     self.xscrlbr = ttk.Scrollbar(self.parent, orient = 'horizontal') 
     self.xscrlbr.grid(column = 0, row = 1, sticky = 'ew', columnspan = 2)   
     self.yscrlbr = ttk.Scrollbar(self.parent) 
     self.yscrlbr.grid(column = 1, row = 0, sticky = 'ns')   
     # creating a canvas 
     self.canv = tk.Canvas(self.parent) 
     self.canv.config(relief = 'flat', 
         width = 10, 
         heigh = 10, bd = 2) 
     # placing a canvas into frame 
     self.canv.grid(column = 0, row = 0, sticky = 'nsew') 
     # accociating scrollbar comands to canvas scroling 
     self.xscrlbr.config(command = self.canv.xview) 
     self.yscrlbr.config(command = self.canv.yview) 

     # creating a frame to inserto to canvas 
     self.scrollwindow = ttk.Frame(self.parent) 

     self.canv.create_window(0, 0, window = self.scrollwindow, anchor = 'nw') 

     self.canv.config(xscrollcommand = self.xscrlbr.set, 
         yscrollcommand = self.yscrlbr.set, 
         scrollregion = (0, 0, 100, 100)) 

     self.yscrlbr.lift(self.scrollwindow)   
     self.xscrlbr.lift(self.scrollwindow) 
     self.scrollwindow.bind('<Configure>', self._configure_window) 
     self.scrollwindow.bind('<Enter>', self._bound_to_mousewheel) 
     self.scrollwindow.bind('<Leave>', self._unbound_to_mousewheel) 

     return 

    def _bound_to_mousewheel(self, event): 
     self.canv.bind_all("<MouseWheel>", self._on_mousewheel) 

    def _unbound_to_mousewheel(self, event): 
     self.canv.unbind_all("<MouseWheel>") 

    def _on_mousewheel(self, event): 
     self.canv.yview_scroll(int(-1*(event.delta/120)), "units") 

    def _configure_window(self, event): 
     # update the scrollbars to match the size of the inner frame 
     size = (self.scrollwindow.winfo_reqwidth(), self.scrollwindow.winfo_reqheight()) 
     self.canv.config(scrollregion='0 0 %s %s' % size) 
     if self.scrollwindow.winfo_reqwidth() != self.canv.winfo_width(): 
      # update the canvas's width to fit the inner frame 
      self.canv.config(width = self.scrollwindow.winfo_reqwidth()) 
     if self.scrollwindow.winfo_reqheight() != self.canv.winfo_height(): 
      # update the canvas's width to fit the inner frame 
      self.canv.config(height = self.scrollwindow.winfo_reqheight()) 
+1

lỗi nhỏ, dòng cuối cùng của bạn nên đọc 'self.canv.config (height = ...)' –

+0

@AdamSmith Cảm ơn, đã thêm sửa đổi –

+0

Ý bạn là gì, "làm cho khung này trở thành con của ScrolledWindow.scrollwindow" của tôi. Bạn có thể đưa ra một ví dụ không? – Jacob

Các vấn đề liên quan