Tkinter 框架滚动条

2024-12-25 08:51:00
admin
原创
125
摘要:问题描述:我的目标是向包含多个标签的框架添加垂直滚动条。只要框架内的标签超过框架的高度,滚动条就会自动启用。经过搜索,我找到了这篇有用的文章。根据那篇文章,我明白为了实现我想要的,(如果我错了请纠正我,我是初学者)我必须Frame先创建一个,然后Canvas在该框架内创建一个并将滚动条也粘贴到该框架上。之后,...

问题描述:

我的目标是向包含多个标签的框架添加垂直滚动条。只要框架内的标签超过框架的高度,滚动条就会自动启用。经过搜索,我找到了这篇有用的文章。根据那篇文章,我明白为了实现我想要的,(如果我错了请纠正我,我是初学者)我必须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. 为什么必须使用网格方法?(我尝试了放置方法,但画布上没有出现任何标签。)

  3. anchor='nw'在画布上创建窗口时使用有什么特殊之处?

请保持你的回答简单,因为我是初学者。


解决方案 1:

这是改编自现已不存在的Tkinter Wiki上的VerticalScrolledFrame页面的示例代码,并且已经修改为在 Python 2.7 和 3+ 上运行。

try:  # Python 2
    import tkinter as tk
    import tkinter.ttk as ttk
    from tkinter.constants import *
except ImportError:  # Python 2
    import Tkinter as tk
    import ttk
    from tkinter.constants import *


# Based on
#   https://web.archive.org/web/20170514022131id_/http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame

class VerticalScrolledFrame(ttk.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):
        ttk.Frame.__init__(self, parent, *args, **kw)

        # Create a canvas object and a vertical scrollbar for scrolling it.
        vscrollbar = ttk.Scrollbar(self, orient=VERTICAL)
        vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
        canvas = tk.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 = ttk.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.Tk):
        def __init__(self, *args, **kwargs):
            root = tk.Tk.__init__(self, *args, **kwargs)

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

    app = SampleApp()
    app.mainloop()

目前还未将鼠标滚轮绑定到滚动条上,但这是可以实现的。不过,使用滚轮滚动可能会有点不顺畅。

编辑:

1)

在我看来,滚动框架在 Tkinter 中有点棘手,而且似乎很少使用。似乎没有优雅的方法来做到这一点。

您的代码的一个问题是您必须手动设置画布大小 - 这就是我发布的示例代码解决的问题。

2)

您说的是数据函数吗?Place 对我来说也很好用。(一般来说我更喜欢网格)。

至 3)

嗯,它将窗口定位在画布上。

我注意到的一件事是,您的示例默认处理鼠标滚轮滚动,而我发布的示例则不处理。有时间我得看看。

解决方案 2:

“我做对了吗?有没有更好/更聪明的方法来实现此代码给我的输出?”

总体来说,是的,你做得对。Tkinter 除了画布之外没有原生的可滚动容器。如你所见,设置起来并不难。如你的例子所示,只需要 5 或 6 行代码就可以让它工作——这取决于你如何计算行数。

“为什么我必须使用网格方法?(我尝试了放置方法,但画布上没有出现任何标签?)”

你问为什么必须使用网格。没有要求必须使用网格。Place、网格和pack都可以使用。只是有些更适合特定类型的问题。在这种情况下,你似乎正在创建一个实际的网格——标签的行和列——因此网格是自然的选择。

“在画布上创建窗口时使用anchor ='nw'有什么特别之处?”

锚点会告诉您窗口的哪一部分位于您指定的坐标处。默认情况下,窗口的中心将位于该坐标处。对于上述代码,您希望左上角(“西北”)位于该坐标处。

解决方案 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'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())

解决方案 4:

对于偶然发现这一点的任何人(就像在寻找我自己的要点时一样),我在https://gist.github.com/mp035/9f2027c3ef9172264532fcd6262f3b01上维护了一个专门用于此目的的要点 。它支持各种操作系统的滚轮,带有注释,并在文件中内置了演示。

解决方案 5:

我们甚至可以不使用 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)

解决方案 6:

不能 100% 确定此解决方案是否符合主题(因为它明确要求可滚动的 FRAME),但文本小部件基本上是一个可滚动的框架。来自文本小部件的文档:

“与画布小部件一样,文本小部件可以包含图像和任何其他 Tk 小部件(包括包含许多其他小部件的框架)。从某种意义上说,这允许文本小部件本身作为几何管理器工作。”

文本小部件非常易于使用,并且可以设置为可滚动。因此,我认为文本小部件是一个不错的选择,而不是使用可滚动框架之类的特殊类。

下面是我的代码,这是一个包含 100 个按钮的可滚动文本小部件的基本示例:

from tkinter import Tk, Button, Text,Scrollbar

class test:
    def __init__(self):
        self.win = Tk()
        text = Text(self.win, width=40, height=10, wrap = "none")
        ys = Scrollbar(self.win, orient = 'vertical', command = text.yview)
        text['yscrollcommand'] = ys.set
        text.grid(column = 0, row = 0, sticky = 'nwes')
        ys.grid(column = 1, row = 0, sticky = 'ns')
        for x in range(1,100):
            b = Button(text, text='Push Me')
            text.window_create("end", window=b)
            text.insert("end",'
')
        self.win.mainloop()

test = test()

这至少是我要用于可滚动框架的方法。不确定是否有比插入换行符更好的解决方案来使小部件垂直排列。但它有效。

解决方案 7:

Scrollbar使用时,必须Canvas

通过发送到Canvas xscrollcommand属性Scrollbar.set方法和

属性(xview) 方法进行配置。 滚动条移动后的方法以以下格式接收 *args:Scrollbar command如果
要将可滚动性实现到小部件,
必须创建接收区域和转换 scrollbar_region(元素可视和不可视)功能。
区域是“tuple(float, float)”,表示打开以查看所有元素的一部分。
此解决方案中显示的行为不理想(未使用 tk.Canvas)Canvas.yview

Canvas.yview

tuple('move_to', '<some_absolute_float_value_of_top_of_scrollbar_region>')

import tkinter as tk
from tkinter import ttk
    
class ItemizeFrame(ttk.Frame, list):
    def __init__(self, 
                *args, 
                scroll_upd_callback = lambda x: x,
                visible_els: int = 10,
                **kwargs):
        list.__init__(self)
        ttk.Frame.__init__(self, *args, **kwargs)
        
        ttk.Style().configure('Small.TButton', background='red', width=2, height=2, padx=3, pady=3)
        ttk.Style().configure('Sep.TFrame', padx=3, pady=3)
        
        self.scroll_upd_callback = scroll_upd_callback
        self.visible_els = visible_els
        self.visible_st_idx = 0
        self.pseudo_scroll_element_cursor_line = 0.5*1/visible_els
        
    def append(self, item: ttk.Widget, **kw):
        e = item(self, **kw)
        super().append(e)
        e.pack(fill='x')
        self._update_visible_els()
    
    def _update_visable_id_callback(self):
        for id_, entry_ in enumerate(self):
            entry_.set_id(id_)
            
    def pop(self, index=None):
        e = super().pop(index)
        e.destroy()
        self._update_visible_els()

    def __getitem__(self, idx) -> ttk.Widget:
        return list.__getitem__(self, idx)
        
    # indicators computing and application
    @property
    def visible_end_idx(self):
        return self.visible_st_idx + self.visible_els -1
    
    @property
    def visible_area_ratio(self) -> tuple[float, float]:
        total = len(self)
        st_val = 0.0
        end_val = 1.0
        if total > self.visible_els:
            end_val = 1.0 - (total-self.visible_end_idx)/total
            st_val = self.visible_st_idx / total
        st_val = st_val + self.pseudo_scroll_element_cursor_line
        end_val = end_val + self.pseudo_scroll_element_cursor_line
        return (st_val, end_val)
    
    def _update_scroll_widget(self):
        self.scroll_upd_callback(*self.visible_area_ratio)
        
    
    def set_yview(self, move_to_ratio):
        base_pseudo_ratio = 0.5*1/self.visible_els
        total = len(self)
        max_ratio = (total - self.visible_els)/total+base_pseudo_ratio
        if move_to_ratio < 0: 
            possible_st_el_pseudo_part = base_pseudo_ratio
            possible_st_el_idx = 0
        if max_ratio < move_to_ratio:
            possible_st_el_idx = total - self.visible_els
            possible_st_el_pseudo_part = base_pseudo_ratio
        else :
            el_idx_raw = move_to_ratio * total
            el_idx_round = round(el_idx_raw)
            el_idx_pseudo = (el_idx_raw - el_idx_round)*1/self.visible_els
            possible_st_el_idx = el_idx_round
            possible_st_el_pseudo_part = el_idx_pseudo
        self.visible_st_idx = possible_st_el_idx
        self.pseudo_scroll_element_cursor_line = possible_st_el_pseudo_part
        self._update_visible_els()
    
    def _update_visible_els(self):
        for el in self:
            el.pack_forget()
        for num, el in enumerate(self):
            if self.visible_st_idx <= num and num <= self.visible_end_idx:
                el.pack()
        self._update_scroll_widget()
    
class ScrollableFrame(ttk.Frame):
    def __init__(self, *args, **kwargs):
        kw = dict(width=400, height=300)
        kw.update(kwargs)
        super().__init__(*args, **kw)
        self.scroll = ttk.Scrollbar(self, command=self.on_scroll)
        self.scroll.pack(expand=True, fill='y', side='right')
        
        self.view = ItemizeFrame(
            self,
            scroll_upd_callback=self.scroll.set,
            **kwargs
        )
        self.view.pack(expand=True, fill='both')#, side='left')
    
    def on_scroll(self, *args, **kwargs):
        value_raw = float(args[1]) 
        self.view.set_yview(value_raw)
    
     

用例

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.frame = ScrollableFrame(self)
        self.frame.pack()
    
    def test_fill(self):
        for i in range(15):
            self.frame.view.append(ttk.Entry)
 
class Test:
    @staticmethod
    def v2():
        app = App()
        app.test_fill()
        app.mainloop()
       
Test.v2()

解决方案 8:

看了很多回答之后,我明白了:

import tkinter as tk
root = tk.Tk()
root.title("音樂編輯器")
root.geometry("600x480")

def onFrameConfigure(canvas):
    '''Reset the scroll region to encompass the inner frame'''
    canvas.configure(scrollregion=canvas.bbox("all"))
    '''When window size change, canvas size will change,
       use this line to change its item size (width).'''
    canvas.itemconfigure(wrapFrame, width=canvas.winfo_width())

canvas = tk.Canvas(root, highlightthickness=0)
frame = tk.Frame(canvas, background="#FFFFFF")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)

vsb.pack(side="right", fill="y")
canvas.pack(fill="both", expand=1, anchor="nw") #canvas size is relative to window size.
wrapFrame = canvas.create_window((0,0), window=frame, anchor="nw")

# When the window size change, it will call this function
canvas.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))

L1 = tk.Label(frame, text="音樂編輯器", bg="#556644", font=("",25))
L1.pack(anchor="n")

for i in range(100):
    input = tk.Entry(frame)
    input.pack()

root.mainloop()

通过改变画布和滚动条的位置和大小来指定可滚动框架的大小。

import tkinter as tk
root = tk.Tk()
root.title("音樂編輯器")
root.geometry("600x480")

def onFrameConfigure(canvas):
    '''Reset the scroll region to encompass the inner frame'''
    canvas.configure(scrollregion=canvas.bbox("all"))
    canvas.itemconfigure(wrapFrame, width=canvas.winfo_width())

canvas = tk.Canvas(root, highlightthickness=0)
frame = tk.Frame(canvas, background="#FFFFFF")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)

vsb.place(relx=0.9, y=0, relwidth=0.1, relheight=0.5)
canvas.place(x=0, y=0, relwidth=0.9, relheight=0.5)
wrapFrame = canvas.create_window((0,0), window=frame, anchor="nw")

canvas.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))

L1 = tk.Label(frame, text="音樂編輯器", bg="#556644", font=("",25))
L1.pack(anchor="n")

for i in range(100):
    input = tk.Entry(frame)
    input.pack()

root.mainloop()

通过将其写入 outerFrame 来指定可滚动框架的大小。

import tkinter as tk
root = tk.Tk()
root.title("音樂編輯器")
root.geometry("600x480")

def onFrameConfigure(canvas):
    '''Reset the scroll region to encompass the inner frame'''
    canvas.configure(scrollregion=canvas.bbox("all"))
    canvas.itemconfigure(wrapFrame, width=canvas.winfo_width())

outerFrame = tk.Frame(root)
canvas = tk.Canvas(outerFrame, highlightthickness=0)
frame = tk.Frame(canvas, background="#FFFFFF")
vsb = tk.Scrollbar(outerFrame, orient="vertical", command=canvas.yview)
canvas.config(yscrollcommand=vsb.set)

outerFrame.place(relx=0.25, rely=0.1, relwidth=0.5, relheight=0.5)
vsb.pack(side="right", fill="y")
canvas.pack(fill="both", expand=1, anchor="nw")
wrapFrame = canvas.create_window((0,0), window=frame, anchor="nw")

canvas.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))

L1 = tk.Label(frame, text="音樂編輯器", bg="#556644", font=("",25))
L1.pack(anchor="n")

for i in range(100):
    input = tk.Entry(frame)
    input.pack()

root.mainloop()

框架内的item可以使用pack或者grid(只能选一个),但是place不能单独使用,如果要使用place需要先用pack或者grid扩展布局(高度)。

import tkinter as tk
root = tk.Tk()
root.title("音樂編輯器")
root.geometry("600x480")

def onFrameConfigure(canvas):
    '''Reset the scroll region to encompass the inner frame'''
    canvas.configure(scrollregion=canvas.bbox("all"))
    canvas.itemconfigure(wrapFrame, width=canvas.winfo_width())

canvas = tk.Canvas(root, highlightthickness=0)
frame = tk.Frame(canvas, background="#FFFFFF")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)

vsb.pack(side="right", fill="y")
canvas.pack(fill="both", expand=1, anchor="nw")
wrapFrame = canvas.create_window((0,0), window=frame, anchor="nw")

canvas.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))

L1 = tk.Label(frame, text="音樂編輯器", bg="#556644", font=("",25))
L1.pack(anchor="n")

for i in range(100):
    input = tk.Entry(frame)
    input.pack()

L1 = tk.Label(frame, text="我是Label")
L1.place(x=0, rely=0.5)
root.mainloop()

使用鼠标滚轮:

tkinter:将鼠标滚轮绑定到滚动条

import tkinter as tk
root = tk.Tk()
root.title("音樂編輯器")
root.geometry("600x480")

def onFrameConfigure(canvas):
    canvas.configure(scrollregion=canvas.bbox("all"))
    canvas.itemconfigure(wrapFrame, width=canvas.winfo_width())

def on_mouse_wheel(event, scale=3):
    #only care event.delta is - or +, scroll down or up
    if event.delta<0:
        canvas.yview_scroll(scale, "units")
    else:
        canvas.yview_scroll(-scale, "units")

canvas = tk.Canvas(root, highlightthickness=0)
frame = tk.Frame(canvas, background="#FFFFFF")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)

vsb.pack(side="right", fill="y")
canvas.pack(fill="both", expand=1, anchor="nw")
wrapFrame = canvas.create_window((0,0), window=frame, anchor="nw")

canvas.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
canvas.bind("<Enter>", lambda event: canvas.bind_all("<MouseWheel>", on_mouse_wheel)) # on mouse enter
canvas.bind("<Leave>", lambda event: canvas.unbind_all("<MouseWheel>")) # on mouse leave

L1 = tk.Label(frame, text="音樂編輯器", bg="#556644", font=("",25))
L1.pack(anchor="n")

for i in range(100):
    input = tk.Entry(frame)
    input.pack()

root.mainloop()

导出至班级:

import tkinter as tk
root = tk.Tk()
root.title("音樂編輯器")
root.geometry("600x480")

class scrollFrame():
    def __init__(self, **options):
        outerFrame = tk.Frame(root)
        canvas = tk.Canvas(outerFrame, highlightthickness=0)
        vsb = tk.Scrollbar(outerFrame, orient="vertical", command=canvas.yview)
        vsb.pack(side="right", fill="y")
        canvas.pack(fill="both", expand=1, anchor="nw")
        frame = tk.Frame(canvas, **options)
        wrapFrameId = canvas.create_window((0,0), window=frame, anchor="nw")
        canvas.config(yscrollcommand=vsb.set)
        canvas.bind("<Configure>", lambda event: self.onFrameConfigure())
        canvas.bind("<Enter>", lambda event: canvas.bind_all("<MouseWheel>", self.on_mouse_wheel)) # on mouse enter
        canvas.bind("<Leave>", lambda event: canvas.unbind_all("<MouseWheel>")) # on mouse leave
        self.outerFrame, self.canvas, self.vsb, self.frame, self.wrapFrameId = outerFrame, canvas, vsb, frame, wrapFrameId 
    def onFrameConfigure(self):
        canvas = self.canvas
        '''Reset the scroll region to encompass the inner frame'''
        canvas.configure(scrollregion=canvas.bbox("all"))
        canvas.itemconfigure(self.wrapFrameId, width=canvas.winfo_width())
    def on_mouse_wheel(self, event, scale=3):
        canvas = self.canvas
        #only care event.delta is - or +, scroll down or up
        if event.delta<0:
            canvas.yview_scroll(scale, "units")
        else:
            canvas.yview_scroll(-scale, "units")

frame = scrollFrame(background="#FFFFFF")
frame.outerFrame.place(relx=0.15, rely=0.1, relwidth=0.7, relheight=0.8)

L1 = tk.Label(frame.frame, text="音樂編輯器", bg="#556644", font=("",25))
L1.pack(anchor="n")

for i in range(100):
    input = tk.Entry(frame.frame)
    input.pack()

root.mainloop()

根据:

https ://stackoverflow.com/a/3092341/19470749

https://stackoverflow.com/a/16198198/19470749

https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/create_window.html

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用