簡體   English   中英

使滾動條在 tkinter 中自動向上滾動

[英]Make the scrollbar automatically scroll back up in tkinter

我有一個用 tkinter 制作的界面,它有許多可滾動的框架,用戶可以在其中按下一個按鈕,每個按鈕將顯示相應的框架(並刪除先前顯示的框架)。

當從一幀切換到另一幀並返回到第一幀時,滾動條會停留在原來的位置。 從一個框架更改為另一個框架時,有沒有辦法讓滾動條自動向上滾動?

這是我的代碼:

import tkinter as tk
from tkinter import *
from tkinter import ttk
import platform

# ++++++++++++++++++++++++++++++++++
# Custom Class for Scrollable Frames
# ++++++++++++++++++++++++++++++++++
class ScrollableFrame(tk.Frame):

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

    def onCanvasConfigure(self, event):
        canvas_width = event.width
        self.canvas.itemconfig(self.canvas_window, width=canvas_width)

    def onMouseWheel(self, event):
        if platform.system() == 'Windows':
            self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
        else:
            if event.num == 4:
                self.canvas.yview_scroll(-1, "units")
            elif event.num == 5:
                self.canvas.yview_scroll(1, "units")

    def onEnter(self, event):
        if platform.system() == 'Linux':
            self.canvas.bind_all("<Button-4>", self.onMouseWheel)
            self.canvas.bind_all("<Button-5>", self.onMouseWheel)
        else:
            self.canvas.bind_all("<MouseWheel>", self.onMouseWheel)

    def onLeave(self, event):
        if platform.system() == 'Linux':
            self.canvas.unbind_all("<Button-4>")
            self.canvas.unbind_all("<Button-5>")
        else:
            self.canvas.unbind_all("<MouseWheel>")

    def __init__(self, parent):
        super().__init__(parent)  # create a frame (self)

        self.canvas = tk.Canvas(self, borderwidth=0, height=canvas_height, width=canvas_width, background="white")
        self.viewPort = tk.Frame(self.canvas, background="white")
        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview, background="white")
        self.canvas.configure(yscrollcommand=self.vsb.set)

        self.vsb.pack(side="right", fill="y")
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas_window = self.canvas.create_window((4, 4), window=self.viewPort, anchor="nw", tags="self.viewPort")

        self.canvas.bind("<Configure>", self.onCanvasConfigure)
        self.viewPort.bind("<Configure>", self.onFrameConfigure)

        self.viewPort.bind('<Enter>', self.onEnter)
        self.viewPort.bind('<Leave>', self.onLeave)

        self.onFrameConfigure(None)

# ----- resets all frames -----
def reset():
    update_frame.pack_forget()
    home_frame.pack_forget()


# ----- Custom Side Menu Buttons -----
def menubttn(x, y, text, cmd):
    def on_entera(e):
        myButton1['background'] = bcolor

    def on_leavea(e):
        myButton1['background'] = fcolor

    myButton1 = Button(sidemenu, text=text,
                       width=15,
                       height=2,
                       border=0,
                       bg=fcolor,
                       activebackground=bcolor,
                       command=cmd)

    myButton1.bind("<Enter>", on_entera)
    myButton1.bind("<Leave>", on_leavea)

    myButton1.place(x=x, y=y)


# ----- helper function to insert entry boxes on frames -----
def entrybox(frame, index):
    entry_box = Entry(frame,width=50)
    entry_box.grid(row=index, column=1, pady=5, padx=(0, 100))
    return entry_box


# ++++++++++++++++++++++++++++++++++
# functions that handle frames
# ++++++++++++++++++++++++++++++++++

# ----- Handles homepage -----
def homepage():
    reset()
    home_frame.pack()


# ----- Handles update frame -----
def update():
    reset()
    update_frame.pack()

    def delete():
        homepage()
        update_lf.pack_forget()

    def edit(self):
        if(dropdown_menu.get() != "choose"):
            update_lf.pack()
            entry_boxes = []
            for i in range(15):
                Label(update_lf, text="name", background="white").grid(row=i, column=0, sticky=W, padx=(100, 20))
                entry_boxes.append(entrybox(update_lf, i))

            delete_button = Button(update_lf, text="delete", command=delete)
            delete_button.grid(row=i+1, column=1, columnspan=2)

        else:
            update_lf.pack_forget()

    dropdown_menu.pack()
    dropdown_menu.bind("<<ComboboxSelected>>", edit)


# +++++++++++++++
# Initializations
# +++++++++++++++

bcolor = '#77B9CF'
fcolor = '#D5E2EB'
frame_width = 900
frame_height = 500
sidemenu_width = 111
canvas_width = frame_width - sidemenu_width - 24
canvas_height = frame_height - 40
canvas_height_scroll = canvas_height - 85

root = Tk()
root.geometry(f'{frame_width}x{frame_height}')
root.configure(bg='white')
root.resizable(False, False)
root.title("test")

# +++++++++++++
# Create Frames
# +++++++++++++

# ----- main projects frame -----
projects_frame = Frame(root, height=frame_height, width=frame_width - sidemenu_width, bg='white')
projects_frame.place(x=sidemenu_width, y=0)

# ----- sidemenu frame -----
sidemenu = Frame(root, width=sidemenu_width, height=frame_height, bg='#D5E2EB')
sidemenu.place(x=0, y=0)

# ----- homepage frame -----
home_frame = Frame(projects_frame, height=frame_height, width=frame_width - sidemenu_width, bg='white')
home_frame.pack()
Label(home_frame, text="WELCOME!", background="white", font=("", 40), foreground=bcolor).place(relx=0.5, rely=0.3,
                                                                                                  anchor=CENTER)
Label(home_frame, text="this is the homepage", background="white", font=("", 20), foreground=bcolor).place(relx=0.5, rely=0.4,
                                                                                                           anchor=CENTER)

# ----- update frame -----
menu =["elem1","elem2","elem3"]
update_frame = ScrollableFrame(projects_frame)
update_lf = LabelFrame(update_frame.viewPort, text="frame", padx=10, pady=10, background="white")
dropdown_menu = ttk.Combobox(update_frame.viewPort, state="readonly",
                             values=["choose"] + menu, width=55)
dropdown_menu.current(0)


# ++++++++++++++++++++++++
# Create Side Menu Buttons
# ++++++++++++++++++++++++
menubttn(0, 100, 'HOMEPAGE', homepage)
menubttn(0, 200, 'UPDATE', update)

root.mainloop()

當我按下更新框架中的刪除按鈕並將 go 返回更新框架時,就會出現問題。我認為這是因為框架向下滾動但我可能錯了..

在不知道您已經嘗試過的情況下很難提供幫助 - 請發布最小可重現示例

也就是說,我相信您可以通過將事件綁定到可滾動小部件來完成此操作。

# I don't know what your widgets are called, so I called it 'scrollable_frame' here
scrollable_frame.bind( 
    '<FocusOut>',  # whenever the widget loses focus...
    lambda _event: scrollable_frame.yview_moveto(0)  # scroll to top
)

您需要將類似的事件分別綁定到每個可滾動框架。

為了確保您剛剛滾動的框架具有焦點(因此您可以正確跟蹤它何時失去焦點,您可能希望像這樣向每個框架添加另一個事件綁定

scrollable_frame.bind(
    '<MouseWheel>',  # when scrolling with the mouse wheel...
    lambda _event: self.scrollable_frame.focus_force()  # force focus
)

如果您使用滾動條滾動,情況會略有不同,但原理上是相同的。

發布代碼后,我可以編輯我的答案以更具體地針對您的情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM