树莓派屏幕Python 3.8环境下Tkinter滚动功能添加后窗口空白问题
树莓派屏幕Python 3.8环境下Tkinter滚动功能添加后窗口空白问题
嗨,我来帮你搞定这个问题!你的窗口变空白主要有两个核心问题,咱们逐个解决:
问题根源分析
- 主循环位置错误:你把
tkFenster.mainloop()放在了滚动条代码之后,而Tkinter的主循环一旦启动就会阻塞后续代码执行,后面所有创建按钮、标签的代码根本没机会运行,窗口自然是空的。 - 滚动条绑定错误:Tkinter的顶层窗口(
Toplevel)本身不支持滚动视图(yview),你直接把滚动条的command绑定到自身的yview是无效的,得用一个可滚动的容器来承载所有控件。
解决方案步骤
第一步:调整主循环位置
把tkFenster.mainloop()移到所有代码的最后一行,确保所有控件都创建完成后再启动主循环。
第二步:重构滚动功能
我们用Canvas作为滚动容器,在Canvas内部放一个Frame,所有原来的控件都放到这个Frame里,再把滚动条和Canvas绑定起来,这样就能实现滚动效果了。
修改后的完整代码
import tkinter as tk from tkinter import * from tkinter import ttk # 假设这些变量是你之前定义好的(用户代码里用到但没给出的变量) maxschritte = 10 max_ausgaenge = 8 rez_arr = [[0 for _ in range(max_ausgaenge+3)] for _ in range(maxschritte)] Wartaufext = 0 Wartwert = 1000 Drehwinkel = 90 # 定义用户代码里用到的函数(示例空实现,你替换成自己的逻辑) def Einstellungen_zurueck(): pass def einst_speichern_double(): pass def plusschritte(): pass def minusschritte(): pass def Kalibrierung(): pass def Motorplus(): pass def Motorminus(): pass def Startposition(): pass # 创建顶层窗口 tkFenster = tk.Toplevel() tkFenster.title("Einstellungen") tkFenster.geometry('800x480') tkFenster.attributes('-zoomed', True) # ------------------- 滚动功能实现 ------------------- # 创建滚动条 Yscroll = tk.Scrollbar(tkFenster) Yscroll.pack(side=tk.RIGHT, fill=Y) # 创建Canvas作为滚动容器 scroll_canvas = tk.Canvas(tkFenster, yscrollcommand=Yscroll.set) scroll_canvas.pack(side=LEFT, fill=BOTH, expand=True) # 绑定滚动条到Canvas的yview Yscroll.configure(command=scroll_canvas.yview) # 创建内部Frame,所有控件都放在这个Frame里 content_frame = tk.Frame(scroll_canvas) # 将Frame放到Canvas中 canvas_window = scroll_canvas.create_window((0, 0), window=content_frame, anchor=NW) # 定义函数更新Canvas的滚动区域 def update_scroll_region(event): scroll_canvas.configure(scrollregion=scroll_canvas.bbox("all")) # 绑定Frame大小变化事件,更新滚动区域 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) # --------------------------------------------------- # 原来的控件创建代码,注意把所有tkFenster替换成content_frame rowsizelist = [] einst_reihenanzahl = 1 if maxschritte <= 6: einst_reihenanzahl = 7 else: einst_reihenanzahl=maxschritte+1 for i in range(einst_reihenanzahl): rowsizelist.append(i) columnamount = 4 columnamount = max_ausgaenge + 3 columnsizelist = [] for i in range(columnamount): columnsizelist.append(i) content_frame.rowconfigure(rowsizelist, minsize = 10, weight = 1) content_frame.columnconfigure(columnsizelist, minsize = 10, weight = 1) btn_zurueckscreen = tk.Button(content_frame, text = "Zurück", command = Einstellungen_zurueck) btn_zurueckscreen.grid(row = 0, column = 0, rowspan = 1, columnspan = 1, sticky = "nsew") btn_save = tk.Button(content_frame, text = "Speichern", command = einst_speichern_double) btn_save.grid(row = 1, column = 0, rowspan = 2, columnspan = 1, sticky = "nsew") btn_plusSchritt = tk.Button(content_frame, text = "+ Schritte", command = plusschritte) btn_plusSchritt.grid(row = 3, column = 0, rowspan = 1, columnspan = 1, sticky = "nsew") btn_minusSchritt = tk.Button(content_frame, text = "- Schritte", command = minusschritte) btn_minusSchritt.grid(row = 4, column = 0, rowspan = 1, columnspan = 1, sticky = "nsew") # hier wird das 2D Dictionary vorbereitet IDs = [] for i in range(maxschritte): IDs.append("Schritt " + str(i+1)) holder_defaultslist = [] #print(max_ausgaenge) for i in range(max_ausgaenge): if i < 6: holder_defaultslist.append("Aus. " + str(i+1)) if i == 6: holder_defaultslist.append("Mot.+") if i == 7: holder_defaultslist.append("Mot.-") if i == 8: holder_defaultslist.append("Wart.") holder_defaults = {} holder_defaults = dict.fromkeys(holder_defaultslist, "") # print(holder_defaults) IDs.append("Warten \n auf extern") var_holder= dict.fromkeys(IDs, holder_defaults) #print(var_holder) kalla = 3 reihe = 0 vars_rez = [] for i in range(maxschritte*max_ausgaenge+1): # hier werden Checkbuttonsvariablen erstellt vars_rez.append(tk.IntVar()) rei = int(((i-i%max_ausgaenge)/max_ausgaenge)) spal = int(i%max_ausgaenge) + 2 #print(str(rei) +" Reihe +" + str(spal) + " Spalte") # print(str(rei) + " ? " + str(spal)) # print(rez_arr[rei][spal]) if i<maxschritte*max_ausgaenge: if rez_arr[rei][spal] == 1: vars_rez[i].set(True) else: vars_rez[i].set(False) else: vars_rez[i].set(False) #print(vars_rez[i]) laufer = 0 ent_rez=[] for i in range(maxschritte): # hier wird Entryvariablen erstellt ent_rez.append(tk.StringVar()) ent_rez.append(tk.StringVar()) #für Wartwert ent_rez.append(tk.StringVar()) #für Drehwinkel for labelz in var_holder.keys(): # print (labelz) if reihe < maxschritte: lbl = tk.Label(content_frame, text = labelz + "\n Zeit(ms)") # hier wird das Label erstellt lbl.grid(row = reihe, column = 1, rowspan = 1, columnspan = 1, sticky = "nsew") ent = tk.Entry(content_frame,width = 5, textvariable = ent_rez[reihe]) # hier wird das Entry erstellt, die Breite zur Not wieder weglassen wenns auf dem Touch nicht geht ent.grid(row = reihe, column = 2, rowspan = 1, columnspan = 1, sticky = "nsew") ent.delete(0, 'end') ent.insert(0, rez_arr[reihe][1]) else: lbl = tk.Label(content_frame, text = labelz) # hier wird das Label für letzte Zeile erstellt lbl.grid(row = reihe, column = 1, rowspan = 1, columnspan = 1, sticky = "nsew") if reihe < maxschritte: for labely in var_holder[labelz].keys(): chb = tk.Checkbutton(content_frame, text = labely, variable=vars_rez[laufer]) # hier wird der Checkbutton erstellt chb.grid(row = reihe, column = kalla, rowspan = 1, columnspan = 1, sticky = "nsew") if rez_arr[reihe][kalla-1] == 1: chb.select() kalla = kalla + 1 laufer = laufer + 1 if kalla == 3 + max_ausgaenge: kalla = 3 reihe = reihe + 1 else: chb = tk.Checkbutton(content_frame, text = "W a ext", variable=vars_rez[laufer]) # hier wird der Checkbutton erstellt #print(vars_rez[laufer]) global Wartwert global Drehwinkel print(Wartwert) print(Drehwinkel) chb.grid(row = reihe, column = kalla-1, rowspan = 1, columnspan = 1, sticky = "nsew") #print("wart auf ext vor select"+ str(Wartaufext)) if Wartaufext == 1: chb.select() #print(rez_arr) btn_Kalibrierung = tk.Button(content_frame, width = 4, text = "Kalibrie-\nrung", command = Kalibrierung) btn_Kalibrierung.grid(row = reihe, column = 3, rowspan = 1, columnspan = 2, sticky = "nsew") btn_Motorplus = tk.Button(content_frame, width = 4, text = "Motor+", command = Motorplus) btn_Motorplus.grid(row = 5, column = 0, rowspan = 1, columnspan = 1, sticky = "nsew") btn_Motorminus = tk.Button(content_frame, width = 4, text = "Motor-", command = Motorminus) btn_Motorminus.grid(row = 6, column = 0, rowspan = 1, columnspan = 1, sticky = "nsew") lbl = tk.Label(content_frame, text = "Warten auf\nmaximal:") lbl.grid(row = reihe, column = 5, rowspan = 1, columnspan = 1, sticky = "nsew") ent = tk.Entry(content_frame, width = 4, textvariable = ent_rez[reihe]) ent.grid(row = reihe, column = 6, rowspan = 1, columnspan = 1, sticky = "nsew") ent.delete(0, 'end') #Wartwert = ent_rez[reihe].get() ent.insert(0, Wartwert) lbl = tk.Label(content_frame, text = "Winkel(°)\nvor/zurück") lbl.grid(row = reihe, column = 7, rowspan = 1, columnspan = 1, sticky = "nsew") ent = tk.Entry(content_frame, width = 4, textvariable = ent_rez[reihe+1]) ent.grid(row = reihe, column = 8, rowspan = 1, columnspan = 1, sticky = "nsew") ent.delete(0, 'end') #Drehwinkel = ent_rez[reihe+1].get() ent.insert(0, Drehwinkel) btn_Startposition = tk.Button(content_frame, width = 4, text = "Motor in \n Startposition", command = Startposition) btn_Startposition.grid(row = reihe, column = 9, rowspan = 1, columnspan = 2, sticky = "nsew") #lbl = Label(content_frame, text = "Motor im \nUhrzeigersinn") #lbl.grid(row = reihe, column = 9, rowspan = 1, columnspan = 1, sticky = "nsew") #lbl = Label(content_frame, text = "Motor gegen \nUhrzeigersinn") #lbl.grid(row = reihe, column = 10, rowspan = 1, columnspan = 1, sticky = "nsew") reihe=reihe+1 # print(vars_rez) # lbl = Label(content_frame, text="Warten \n auf extern") # lbl.grid(row=maxschritte, column=1, rowspan=1,columnspan=1, sticky="nsew" ) # chb = Checkbutton(content_frame, text = "W a ex", variable=vars_rez[maxschritte*max_ausgaenge]) # hier wird der Checkbutton erstellt # chb.grid(row = maxschritte, column = 2, rowspan = 1, columnspan = 1, sticky = "nsew") print("varscheckforext=" + str(vars_rez[maxschritte*max_ausgaenge])) # 主循环移到最后 tkFenster.mainloop()
关键修改点说明
- 主循环位置:把
tkFenster.mainloop()移到代码最后,确保所有控件都初始化完成。 - 滚动容器结构:用
Canvas+Frame的组合承载所有控件,解决顶层窗口无法滚动的问题。 - 控件父容器替换:把所有原来绑定到
tkFenster的控件,全部改成绑定到content_frame(Canvas内部的Frame)。 - 滚动区域更新:绑定
content_frame的<Configure>事件,自动更新Canvas的滚动范围,确保所有内容都能被滚动到。 - 修复变量赋值:你代码里的
vars_rez[i].set = True是错误的,应该改成vars_rez[i].set(True),我已经帮你修正了这个小bug。
这样修改后,你的滚动功能就能正常工作,同时原来的按钮、标签等控件也会正常显示啦~
备注:内容来源于stack exchange,提问作者Mprog
相关产品推荐
相关产品推荐

