求助:为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
相关产品推荐
相关产品推荐

