Подтвердить что ты не робот

Полоса прокрутки Tkinter для кадра

Моя цель - добавить вертикальную полосу прокрутки к рамке, в которой есть несколько меток. Полоса прокрутки должна автоматически включиться, как только метки внутри рамки превысят высоту рамки. После поиска я нашел этот полезный пост. Исходя из этого поста, я понимаю, что для достижения того, что я хочу (поправьте меня, если я ошибаюсь, я новичок), я должен сначала создать Frame, затем создать Canvas внутри этого фрейма и прикрепить полосу прокрутки к этому. рамка тоже. После этого создайте еще один фрейм и поместите его внутри холста в качестве объекта окна. Итак, я наконец придумаю это:

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. Я делаю это правильно? Есть ли лучший/более умный способ добиться результата, который дал мне этот код?
  2. Почему я должен использовать метод сетки? (Я попробовал метод place, но ни одна из меток не появилась на холсте.)
  3. Что такого особенного в использовании anchor='nw' при создании окна на холсте?

Пожалуйста, оставьте свой ответ простым, так как я новичок.

4b9b3361

Ответ 1

Я делаю это правильно? Есть ли лучший/более умный способ достичь результата, который мне дал этот код?

В общем, да, вы делаете все правильно. У Tkinter нет собственного прокручиваемого контейнера, кроме холста. Как вы можете видеть, это действительно не так сложно настроить. Как показывает ваш пример, для его работы требуется всего 5 или 6 строк кода - в зависимости от того, как вы подсчитываете строки.

Почему я должен использовать метод grid? (я попытался установить метод, но ни один из ярлыков не появился на холсте?)

Вы спрашиваете, почему вы должны использовать сетку. Нет необходимости использовать сетку. Место, сетка и упаковка могут использоваться. Это просто, что некоторые более естественно подходят для конкретных типов проблем. В этом случае похоже, что вы создаете фактическую сетку - строки и столбцы меток, поэтому сетка является естественным выбором.

Что такого особенного в использовании anchor = 'nw' при создании окна на холсте?

Якорь сообщает вам, какая часть окна расположена в координатах, которые вы даете. По умолчанию центр окна будет помещен в координату. В случае вашего кода выше вы хотите, чтобы верхний левый ( "северо-западный" ) угол находился в координате.

Ответ 2

Обратите внимание, что предлагаемый код действителен только с Python 2

Вот пример:

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 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 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()

У него еще нет колеса мыши, привязанного к полосе прокрутки, но это возможно. Однако прокрутка с помощью колеса может немного ухабироваться.

редактировать:

до 1)
Прокрутка кадров IMHO несколько сложна в Tkinter и, похоже, не много сделано. Кажется, нет элегантного способа сделать это.
Одна из проблем с вашим кодом заключается в том, что вам нужно вручную установить размер холста - то, что решает код примера, который я написал.

до 2)
Вы говорите о функции данных? Место работает и для меня. (В общем, я предпочитаю сетку).

до 3)
Ну, он позиционирует окно на холсте.

Одна вещь, которую я заметил, это то, что ваш пример обрабатывает прокрутку колеса мыши по умолчанию, а тот, который я опубликовал, не работает. Придется взглянуть на это некоторое время.

Ответ 3

Пожалуйста, посмотрите мой класс, который является прокручиваемым фреймом. Вертикальная полоса прокрутки привязана к событию <Mousewheel>. Итак, все, что вам нужно сделать, это создать фрейм, заполнить его виджетами так, как вам нравится, а затем сделать этот кадр дочерним элементом моего ScrolledWindow.scrollwindow. Не стесняйтесь спрашивать, что-то неясно.

Используется много от @Brayan Oakley ответы на близкие к этим вопросам

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 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 width to fit the inner frame
            self.canv.config(height = self.scrollwindow.winfo_reqheight())

Ответ 4

Мы можем добавить полосу прокрутки даже без использования Canvas. Я прочитал его во многих других сообщениях, мы не можем добавить вертикальную полосу прокрутки в рамку напрямую и т.д. Но после многих экспериментов выяснилось, как добавить вертикальную, а также горизонтальную полосу прокрутки:). Ниже приведен код, который используется для создания полосы прокрутки в treeView и фрейме.

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)

Ответ 5

Проверьте это GitHub репо: VerticalScrolledFrame

Это решило мои потребности.