Python Tkinter整个窗口的滚动条

5
有没有一种方法可以在不将所有内容放入框架的情况下为整个窗口添加滚动条?我已经使用.grid设置好了所有内容,不喜欢用框架包裹所有内容的想法。
root = Tk()
root.maxsize(900,600)

circus()#calls the function to set up everything

root.mainloop()

可能是重复问题:https://dev59.com/JHI-5IYBdhLWcg3wc4Cw - sPaz
6个回答

6

如何在tkinter中为整个窗口添加滚动条?

以下是适用于Python 3的答案...


from tkinter import *

from tkinter import ttk



root = Tk()

root.title('Full Window Scrolling X Y Scrollbar Example')

root.geometry("1350x400")



# Create A Main frame

main_frame = Frame(root)

main_frame.pack(fill=BOTH,expand=1)



# Create Frame for X Scrollbar

sec = Frame(main_frame)

sec.pack(fill=X,side=BOTTOM)



# Create A Canvas

my_canvas = Canvas(main_frame)

my_canvas.pack(side=LEFT,fill=BOTH,expand=1)



# Add A Scrollbars to Canvas

x_scrollbar = ttk.Scrollbar(sec,orient=HORIZONTAL,command=my_canvas.xview)

x_scrollbar.pack(side=BOTTOM,fill=X)

y_scrollbar = ttk.Scrollbar(main_frame,orient=VERTICAL,command=my_canvas.yview)
y_scrollbar.pack(side=RIGHT,fill=Y)



# Configure the canvas

my_canvas.configure(xscrollcommand=x_scrollbar.set)

my_canvas.configure(yscrollcommand=y_scrollbar.set)

my_canvas.bind("<Configure>",lambda e: my_canvas.config(scrollregion= my_canvas.bbox(ALL))) 



# Create Another Frame INSIDE the Canvas

second_frame = Frame(my_canvas)



# Add that New Frame a Window In The Canvas

my_canvas.create_window((0,0),window= second_frame, anchor="nw")





for thing in range(100):

    Button(second_frame ,text=f"Button  {thing}").grid(row=5,column=thing,pady=10,padx=10)



for thing in range(100):

    Button(second_frame ,text=f"Button  {thing}").grid(row=thing,column=5,pady=10,padx=10)



root.mainloop()

1
我尝试了Akash Shendage的答案,但是它不能直接为我工作。但是通过一些调整,我让它工作了。
#!/bin/env python3

from tkinter import ttk
import tkinter as tk

root = tk.Tk()
root.title('Full Window Scrolling X Y Scrollbar Example')
root.geometry("1350x400")

# Create A Main frame
main_frame = tk.Frame(root)
main_frame.pack(fill=tk.BOTH,expand=1)

# Create Frame for X Scrollbar
sec = tk.Frame(main_frame)
sec.pack(fill=tk.X,side=tk.BOTTOM)

# Create A Canvas
my_canvas = tk.Canvas(main_frame)
my_canvas.pack(side=tk.LEFT,fill=tk.BOTH,expand=1)

# Add A Scrollbars to Canvas
x_scrollbar = ttk.Scrollbar(sec,orient=tk.HORIZONTAL,command=my_canvas.xview)
x_scrollbar.pack(side=tk.BOTTOM,fill=tk.X)
y_scrollbar = ttk.Scrollbar(main_frame,orient=tk.VERTICAL,command=my_canvas.yview)
y_scrollbar.pack(side=tk.RIGHT,fill=tk.Y)

# Configure the canvas
my_canvas.configure(xscrollcommand=x_scrollbar.set)
my_canvas.configure(yscrollcommand=y_scrollbar.set)
my_canvas.bind("<Configure>",lambda e: my_canvas.config(scrollregion= my_canvas.bbox(tk.ALL))) 

# Create Another Frame INSIDE the Canvas
second_frame = tk.Frame(my_canvas)

# Add that New Frame a Window In The Canvas
my_canvas.create_window((0,0),window= second_frame, anchor="nw")

for thing in range(100):
    tk.Button(second_frame ,text=f"Button  {thing}").grid(row=5,column=thing,pady=10,padx=10)

for thing in range(100):
    tk.Button(second_frame ,text=f"Button  {thing}").grid(row=thing,column=5,pady=10,padx=10)

root.mainloop()

1
你可以将滚动条设置到根元素。
scrollderoot = tkinter.Scrollbar(orient="vertical", command=root.yview)
scrollderoot.grid(column=5, row=0, sticky='ns', in_=root) #instead of number 5, set the column as the expected one for the scrollbar. Sticky ns will might be neccesary.
root.configure(yscrollcommand=scrollderoot.set)

说实话,我没有尝试过这个,但“应该”能够工作。祝好运。

你会收到错误信息 AttributeError: '_tkinter.tkapp' object has no attribute 'yview',这样你将无法得到想要的结果。 - Rakshitha Muranga Rodrigo

1
这种方法不使用Frame对象,而是创建一个非常大的带有ScrollbarsCanvas,并要求您提供要在其中显示的图像。

然后使用self.root.wm_attributes("-fullscreen", 1)self.root.wm_attributes("-top", 1)设置屏幕。

按Esc键或Alt-F4键关闭。

import tkinter as tk
from tkinter import filedialog as fido

class BigScreen:

    def __init__( self ):
        self.root = tk.Tk()
        self.root.rowconfigure(0, weight = 1)
        self.root.columnconfigure(0, weight = 1)

        w, h = self.root.winfo_screenwidth(), self.root.winfo_screenheight()
        self.canvas = tk.Canvas(self.root, scrollregion = f"0 0 {w*2} {h*2}")
        self.canvas.grid(row = 0, column = 0, sticky = tk.NSEW)
        self.makescroll(self.root, self.canvas )

        self.imagename = fido.askopenfilename( title = "Pick Image to View" )
        if self.imagename:
            self.photo = tk.PhotoImage(file = self.imagename).zoom(2, 2)
            self.window = self.canvas.create_image(
                ( 0, 0 ), anchor = tk.NW, image = self.photo)

        self.root.bind("<Escape>", self.closer)
        self.root.wm_attributes("-fullscreen", 1)
        self.root.wm_attributes("-top", 1)

    def makescroll(self, parent, thing):
        v = tk.Scrollbar(parent, orient = tk.VERTICAL, command = thing.yview)
        v.grid(row = 0, column = 1, sticky = tk.NS)
        thing.config(yscrollcommand = v.set)
        h = tk.Scrollbar(parent, orient = tk.HORIZONTAL, command = thing.xview)
        h.grid(row = 1, column = 0, sticky = tk.EW)
        thing.config(xscrollcommand = h.set)

    def closer(self, ev):
        self.root.destroy()

if __name__ == "__main__":
    Big = BigScreen()
    Big.root.mainloop()

我之前的回答超出了问题的范围,这是一个更精简的版本,更准确地回答了问题。


0
这是一个类和一些示例用法,它使用.place方法为整个窗口添加滚动条。您可以创建一个Frame对象,并将其放置在所需的(x,y)坐标上。然后,只需将您的Frame对象替换root中的main.frame,即可在所需的坐标上创建一个可滚动的窗口。
from tkinter import *

class ScrollableFrame:
    """A scrollable tkinter frame that will fill the whole window"""

    def __init__ (self, master, width, height, mousescroll=0):
        self.mousescroll = mousescroll
        self.master = master
        self.height = height
        self.width = width
        self.main_frame = Frame(self.master)
        self.main_frame.pack(fill=BOTH, expand=1)

        self.scrollbar = Scrollbar(self.main_frame, orient=VERTICAL)
        self.scrollbar.pack(side=RIGHT, fill=Y)

        self.canvas = Canvas(self.main_frame, yscrollcommand=self.scrollbar.set)
        self.canvas.pack(expand=True, fill=BOTH)

        self.scrollbar.config(command=self.canvas.yview)

        self.canvas.bind(
            '<Configure>',
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )

        self.frame = Frame(self.canvas, width=self.width, height=self.height)
        self.frame.pack(expand=True, fill=BOTH)
        self.canvas.create_window((0,0), window=self.frame, anchor="nw")

        self.frame.bind("<Enter>", self.entered)
        self.frame.bind("<Leave>", self.left)

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

    def entered(self,event):
        if self.mousescroll:
            self.canvas.bind_all("<MouseWheel>", self._on_mouse_wheel)
        
    def left(self,event):
        if self.mousescroll:
            self.canvas.unbind_all("<MouseWheel>")

# Example usage

obj = ScrollableFrame(
    master,
    height=300, # Total required height of canvas
    width=400 # Total width of master
)

objframe = obj.frame
# use objframe as the main window to make widget

0
在伟大的effbot docs中写道:
在Tkinter中,滚动条是一个单独的小部件,可以附加到支持标准滚动条接口的任何小部件。这些小部件包括: - 列表框小部件。 - 文本小部件。 - 画布小部件。 - 输入框小部件。
因此,在框架中无法直接使用滚动条。可能可以创建自己的框架子类,以支持滚动条接口。
您可以使用画布来拥有可滚动的内容,但在画布中放置小部件时不使用pack或grid,而是使用显式的像素位置(即在画布上绘制)。

在上面列出的4个小部件中,只有一个允许在其中嵌入其他小部件:画布 - 这不是一个正确的陈述。您可以在文本小部件中嵌入小部件。 - Bryan Oakley
@BryanOakley 将小部件嵌入到 Text 小部件中(而不是 Canvas),是否能提供任何处理或渲染速度上的优势? - SanguineL
@SanguineL:不,我认为这不会对那个产生任何影响。 - Bryan Oakley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接