You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:为Python Tkinter应用主菜单添加右侧滚动条

为Tkinter主界面添加垂直滚动条

我正在做一个学校项目,用Python开发应用,现在想给主菜单界面右侧加一个垂直滚动条,用来浏览界面里的图片、按钮和标签。下面是我的代码,求帮忙实现滚动条功能:

import sys

print(sys.executable)

import tkinter as tk


from functools import partial

from tkinter import *

from tkinter import messagebox

from PIL import Image, ImageTk

from QRcodepage import QRcode




class ThePage():
    
    def pageMain(self):
        MainPageClass=tk.Toplevel()
        MainPageClass.geometry('500x500')
        MainPageClass.title('MainPage')
        MainPageClass.resizable(0,0)
        MainPageClass.configure(bg='#C97E48')


        #create hamburger menu
        
        def toggle_win():
            f1=Frame(MainPageClass,width=300,height=500,bg='#262626')
            f1.place(x=300,y=0)
            #create the rest of the buttons
            def bttn(x,y,text,bcolor,fcolor,cmd):
                def on_entera(e):
                    myButton1['background']=bcolor #ffcc66
                    myButton1['foreground']='#ab6038' #000d33
                def on_leavea(e):
                    myButton1['background']=fcolor
                    myButton1['foreground']='#262626'
                
                myButton1=Button(f1,text=text,width=24,height=2,fg='#262626'
                ,border=0,bg=fcolor,activeforeground='#262626'
                ,activebackground=bcolor,command=cmd)

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

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

            def closeWindow():
                #newvar=createlogin.tkLogin
                #btn=Button(MainPageClass,command=newvar.withdraw)
                #btn.pack()
                pass
           


            bttn(13,80,'HOME','#0f9d9a','#14c4c0',None)
            bttn(13,140,'TRAINER','#0f9d9a','#14c4c0',None)
            bttn(13,200,'NUTRITIONAL PLAN','#0fd9da','#14c4c0',None)
            bttn(13,260,'PHYSICAL EVALUATION','#0fd9da','#14c4c0',None)
            bttn(13,320,'CHOOSE GYM','#0fd9da','#14c4c0',None)
            bttn(13,380,'LOG OUT','#0fd9da','#14c4c0',closeWindow)

            def dele():
                f1.destroy()

            #global img2
            #img2=ImageTk.PhotoImage(Image.open('x.png'))
            

            
            Button(f1,text='X',command=dele).place(x=5,y=10)

        #Creating header using Canva function



        def code():
            code=QRcode()
            code.openQR()
        
        w,h=(550,100)

        canvas=tk.Canvas(MainPageClass,height=h,width=w)
        canvas.pack()
        bg=tk.PhotoImage(file="headerbackground.png")
        bg_1=tk.Label(MainPageClass,image=bg)
        bg_1.place()


        Logo=Image.open('C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\Logo2.png')
        LogoResiz=Logo.resize((100,100))
        LogoRend=ImageTk.PhotoImage(LogoResiz)
        LogoLabel=Label(MainPageClass,image=LogoRend)
        LogoLabel.place(relx=0,rely=0)



        
        photoHamburger=PhotoImage(file=r"C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\hamburger.png")
        photoHamburgerResize=photoHamburger.subsample(7,7)

        Hamburgerbtn=tk.Button(MainPageClass,image=photoHamburgerResize,command=toggle_win,text='Login',bd='0')
        Hamburgerbtn.place(relx=0.9,rely=0.1,anchor=CENTER)

        #This is the end of our code for the Canva area
        
      
        sb = Scrollbar(MainPageClass,orient=VERTICAL)  
        sb.pack(side = RIGHT, fill ='y') 


        TitleLabel=tk.Label(MainPageClass,text='Welcome to your digital gym friend',bg="#C97E48",font='Helvetica 14 bold',xscrollcomand=sb.set)
        TitleLabel.place(relx=0.18,rely=0.3)

        QRbutton=tk.Button(MainPageClass,text='QR Code',bd='4',command=code,xscrollcomand=sb.set)
        QRbutton.place(relx=0.45,rely=0.38)

        photoYogaclass=PhotoImage(file=r"C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\yoga.PNG")
        photoYogaResize=photoYogaclass.subsample(2,2)

        YogaLabel=tk.Label(MainPageClass,image=photoYogaResize,border=0,xscrollcomand=sb.set)
        YogaLabel.place(relx=0.1,rely=0.5)
        
        YogaText=tk.Label(MainPageClass,text='Yoga Class',border=0,bg='#C97E48', foreground='white',font=('Arial',14),xscrollcomand=sb.set)
        YogaText.place(relx=0.13,rely=0.7)

        photoJoin=PhotoImage(file=r'C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\JoinButton.PNG')
        photoJoinResize=photoJoin.subsample(1,1)

        JoinButton=tk.Button(MainPageClass,image=photoJoinResize,command=None,bd='0',bg="#C97E48",xscrollcomand=sb.set)
        JoinButton.place(relx=0.5,rely=0.5)

        photoJogging=PhotoImage(file=r'C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\Jogging.PNG')
        photoJoggingResize=photoJogging.subsample(2,2)

        JoggingLabel=tk.Label(MainPageClass,image=photoJoggingResize,border=0,xscrollcomand=sb.set)
        JoggingLabel.place(relx=0.1,rely=0.8)

        JoggingText=tk.Label(MainPageClass,text='Jogging Class',border=0,bg='#C97E48', foreground='white',font=('Arial',14),yscrollcomand=sb.set)
        JoggingText.place(relx=0.13,rely=1.1)


    


        mainloop()

解决方案

你当前的代码里,滚动条直接绑定到主窗口是无效的,因为Tkinter的滚动条需要和可滚动容器(比如Canvas)配合使用。下面是修改后的完整代码,核心思路是把所有需要滚动的组件放到一个Frame里,再将这个Frame嵌入Canvas中,最后绑定滚动条与Canvas的交互:

import sys

print(sys.executable)

import tkinter as tk
from functools import partial
from tkinter import *
from tkinter import messagebox
from PIL import Image, ImageTk
from QRcodepage import QRcode

class ThePage():
    def pageMain(self):
        MainPageClass=tk.Toplevel()
        MainPageClass.geometry('500x500')
        MainPageClass.title('MainPage')
        MainPageClass.resizable(0,0)
        MainPageClass.configure(bg='#C97E48')

        # 创建汉堡菜单
        def toggle_win():
            f1=Frame(MainPageClass,width=300,height=500,bg='#262626')
            f1.place(x=300,y=0)
            
            def bttn(x,y,text,bcolor,fcolor,cmd):
                def on_entera(e):
                    myButton1['background']=bcolor
                    myButton1['foreground']='#ab6038'
                def on_leavea(e):
                    myButton1['background']=fcolor
                    myButton1['foreground']='#262626'
                
                myButton1=Button(f1,text=text,width=24,height=2,fg='#262626'
                ,border=0,bg=fcolor,activeforeground='#262626'
                ,activebackground=bcolor,command=cmd)

                myButton1.bind("<Enter>",on_entera)
                myButton1.bind("<Leave>",on_leavea)
                myButton1.place(x=x,y=y)

            def closeWindow():
                pass

            bttn(13,80,'HOME','#0f9d9a','#14c4c0',None)
            bttn(13,140,'TRAINER','#0f9d9a','#14c4c0',None)
            bttn(13,200,'NUTRITIONAL PLAN','#0fd9da','#14c4c0',None)
            bttn(13,260,'PHYSICAL EVALUATION','#0fd9da','#14c4c0',None)
            bttn(13,320,'CHOOSE GYM','#0fd9da','#14c4c0',None)
            bttn(13,380,'LOG OUT','#0fd9da','#14c4c0',closeWindow)

            def dele():
                f1.destroy()

            Button(f1,text='X',command=dele).place(x=5,y=10)

        # 二维码功能
        def code():
            code=QRcode()
            code.openQR()
        
        # 头部区域
        w,h=(550,100)
        canvas=tk.Canvas(MainPageClass,height=h,width=w)
        canvas.pack()
        bg=tk.PhotoImage(file="headerbackground.png")
        bg_1=tk.Label(MainPageClass,image=bg)
        bg_1.place()

        Logo=Image.open('C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\Logo2.png')
        LogoResiz=Logo.resize((100,100))
        LogoRend=ImageTk.PhotoImage(LogoResiz)
        LogoLabel=Label(MainPageClass,image=LogoRend)
        LogoLabel.place(relx=0,rely=0)

        photoHamburger=PhotoImage(file=r"C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\hamburger.png")
        photoHamburgerResize=photoHamburger.subsample(7,7)
        Hamburgerbtn=tk.Button(MainPageClass,image=photoHamburgerResize,command=toggle_win,text='Login',bd='0')
        Hamburgerbtn.place(relx=0.9,rely=0.1,anchor=CENTER)

        # -------------------------- 滚动条核心实现 --------------------------
        # 创建滚动条
        sb = Scrollbar(MainPageClass, orient=VERTICAL)
        sb.pack(side=RIGHT, fill='y')

        # 创建Canvas作为滚动容器
        scroll_canvas = tk.Canvas(MainPageClass, bg='#C97E48', yscrollcommand=sb.set)
        scroll_canvas.pack(side=LEFT, fill=BOTH, expand=True)

        # 绑定滚动条和Canvas
        sb.config(command=scroll_canvas.yview)

        # 创建Frame,所有需要滚动的组件都放在这个Frame里
        content_frame = tk.Frame(scroll_canvas, bg='#C97E48')
        content_frame_id = scroll_canvas.create_window((0,0), window=content_frame, anchor='nw')

        # 配置Canvas滚动区域,监听Frame大小变化
        def update_scroll_region(event):
            scroll_canvas.configure(scrollregion=scroll_canvas.bbox('all'))
        
        content_frame.bind('<Configure>', update_scroll_region)

        # 鼠标滚轮支持(适配不同操作系统)
        def on_mouse_wheel(event):
            scroll_canvas.yview_scroll(int(-1*(event.delta/120)), "units")
        
        scroll_canvas.bind_all("<MouseWheel>", on_mouse_wheel)  # Windows/macOS
        scroll_canvas.bind_all("<Button-4>", on_mouse_wheel)    # Linux
        scroll_canvas.bind_all("<Button-5>", on_mouse_wheel)    # Linux
        # -------------------------- 滚动条核心实现结束 --------------------------

        # 把原本放在主窗口的组件,全部放到content_frame里
        TitleLabel=tk.Label(content_frame,text='Welcome to your digital gym friend',bg="#C97E48",font='Helvetica 14 bold')
        TitleLabel.place(relx=0.18,rely=0.3)

        QRbutton=tk.Button(content_frame,text='QR Code',bd='4',command=code)
        QRbutton.place(relx=0.45,rely=0.38)

        photoYogaclass=PhotoImage(file=r"C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\yoga.PNG")
        photoYogaResize=photoYogaclass.subsample(2,2)
        YogaLabel=tk.Label(content_frame,image=photoYogaResize,border=0)
        YogaLabel.place(relx=0.1,rely=0.5)
        
        YogaText=tk.Label(content_frame,text='Yoga Class',border=0,bg='#C97E48', foreground='white',font=('Arial',14))
        YogaText.place(relx=0.13,rely=0.7)

        photoJoin=PhotoImage(file=r'C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\JoinButton.PNG')
        photoJoinResize=photoJoin.subsample(1,1)
        JoinButton=tk.Button(content_frame,image=photoJoinResize,command=None,bd='0',bg="#C97E48")
        JoinButton.place(relx=0.5,rely=0.5)

        photoJogging=PhotoImage(file=r'C:\Robert Andrei\Facultate\FEUP\Software Design\Source code\Jogging.PNG')
        photoJoggingResize=photoJogging.subsample(2,2)
        JoggingLabel=tk.Label(content_frame,image=photoJoggingResize,border=0)
        JoggingLabel.place(relx=0.1,rely=0.8)

        JoggingText=tk.Label(content_frame,text='Jogging Class',border=0,bg='#C97E48', foreground='white',font=('Arial',14))
        JoggingText.place(relx=0.13,rely=1.1)

        # 保留图片对象引用,避免被垃圾回收导致不显示
        content_frame.photoYogaclass = photoYogaclass
        content_frame.photoJoin = photoJoin
        content_frame.photoJogging = photoJogging
        content_frame.LogoRend = LogoRend
        content_frame.bg = bg
        content_frame.photoHamburger = photoHamburger

        mainloop()

修改说明:

  • 新增scroll_canvas作为滚动容器,content_frame承载所有需要滚动的组件,解决直接绑定主窗口无效的问题。
  • 绑定滚动条与Canvas的交互逻辑,拖动滚动条时同步控制Canvas的垂直滚动。
  • 添加update_scroll_region函数,自动适配内容区域大小,确保所有内容都能被滚动到。
  • 增加鼠标滚轮支持,适配Windows、macOS、Linux等不同操作系统。
  • 保留图片对象的引用,避免Tkinter的图片被垃圾回收机制清理导致不显示。

内容的提问来源于stack exchange,提问作者Lacatus Robert Andrei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 10:50:24