Python Tkinter滚动条摇晃滚动 [英] Python Tkinter Scrollbar Shaky Scrolling

查看:116
本文介绍了Python Tkinter滚动条摇晃滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介: 我的Python Tkinter应用程序设计为在侧面具有滚动条,以便在调整窗口大小时仍可以通过滚动条查看该应用程序.为此,我将所有内容的框架放在画布中,并使用滚动条控制画布.在调整窗口大小时,我有一个名为resizeCanvas的函数,它可以调整画布的大小.

Introduction: My Python Tkinter application is designed to have a scrollbar on the side so that if the window is resized, the application can still be viewed via the scrollbar. I do this by putting a frame with all my content inside a canvas, with a scrollbar controlling the canvas. On window resize, I have a function called resizeCanvas which resizes the canvas.

问题: :在我调整窗口大小后,滚动条可以工作,但似乎跳来跳去,像坐立不安那样烦躁不安.但是,在初始化时,滚动条会平稳运行.因此,调整窗口大小似乎是问题所在. 关于滚动条为何如此的任何建议?

Problem: After I resize the window, the scrollbar sort of works but it seems to jump around and fidget like its having a seizure. However, at initialization the scroll bar works smoothly. So resizing the window seems to be the problem. Any suggestions on why the scroll bar is behaving like this?

应用程序层次结构:

Application Hierarchy:

  • Tkinter根
    • 框架(只是画布的容器)
      • 画布(滚动条已连接到此画布)
        • 框架(内容在此框架中)
        • Tkinter root
          • frame (just a container for the canvas)
            • canvas (scroll bar is attached to this canvas)
              • frame (content is in this frame)

              注意:Python 2.7.2

              NOTE: Python 2.7.2

              代码段:

              Code Snippit:

                  myframe=Frame(root,width=winx,height=winy)
                  myframe.place(x=0,y=0)
                  canvas = Tkinter.Canvas(myframe,width=winx,height=winy)
                  frame = Frame(canvas,width=winx,height=winy)
                  myscrollbar=Scrollbar(myframe,orient="vertical")
                  myscrollbar.configure(command=canvas.yview)
                  canvas.configure(yscrollcommand=myscrollbar.set)
              
                  myscrollbar.pack(side="left",fill="y")
                  canvas.pack(side="left")
                  canvas.create_window((0,0),window=frame,anchor='nw')
                  frame.bind("<Configure>", initializeCanvas)
                  bind("<Configure>", resizeCanvas)
              
              def initializeCanvas(self, event):
                 canvas.configure(scrollregion=self.canvas.bbox("all"),width=winx,height=winy)
              
              def resizeCanvas(self, event):
                  update()
                  cwidth = self.winfo_width()
                  cheight = self.winfo_height()
                  canvas.config(width=cwidth, height=cheight)
              

              完整代码:

              Entire Code:

              import sys
              #external python files are in the includes folder
              sys.path.insert(0, 'includes')
              
              import webbrowser
              import os
              import Tkinter
              import tkFileDialog
              import tkMessageBox
              import ConfigParser
              from ttk import *
              import tkFont
              import Tix
              
              # configurations held in this variable
              config = ConfigParser.RawConfigParser()
              # pady padding for create buttons
              py = 15
              # padx padding for create buttons
              px = 5
              # padding on left side for indenting elements
              indentx = 25
              winx = 815
              winy = 515
              # array to hold features
              FEATURES =['']
              
              
              # wrapper class for GUI
              class AppTk(Tkinter.Tk):
                  def __init__(self, parent):
                      Tkinter.Tk.__init__(self, parent)
                      self.parent = parent
                      self.settings = "./settings/settings.cfg"
                      self.initialize_gui()
                      self.minsize(winx, 100)
                      sizex = winx
                      sizey = winy
                      posx  = 100
                      posy  = 100
                      self.wm_geometry("%dx%d+%d+%d" % (sizex, sizey, posx, posy))
              
                      try:
                          self.iconbitmap('./imgs/favicon.ico')
                      except Exception, e:
                          print "\n****Error occurred (GUI_MBD_File_Creator.init):  favicon not found!"
              
                  # Setup grid of elements in GUI
                  # action: on start of application
                  def initialize_gui(self):
              
                      # ----------------------------------------------------
                      # START Settings frame initialization
                      # ----------------------------------------------------
                      self.myframe=Frame(self,width=winx,height=winy)
                      self.myframe.place(x=0,y=0)
                      self.canvas = Tkinter.Canvas(self.myframe,width=winx,height=winy)
                      self.frame = Frame(self.canvas,width=winx,height=winy)
                      self.myscrollbar=Scrollbar(self.myframe,orient="vertical")
                      self.myscrollbar.configure(command=self.canvas.yview)
                      self.canvas.configure(yscrollcommand=self.myscrollbar.set)
              
                      self.myscrollbar.pack(side="left",fill="y")
                      self.canvas.pack(side="left")
                      self.canvas.create_window((0,0),window=self.frame,anchor='nw')
                      self.frame.bind("<Configure>",self.initializeCanvas)
                      self.bind("<Configure>",self.resizeCanvas)
              
              
                      frameFont = tkFont.Font(size=13, weight=tkFont.BOLD)
              
                      self.frameSettings = Tkinter.LabelFrame(self.frame, text="Settings: fill these out first", relief="groove", borderwidth="3", font=frameFont)
                      self.frameSettings.grid(sticky="EW", padx=px, pady=(5,15))
              
                      labelSpreadsheet = Label(self.frameSettings, text="1. Spreadsheet Path:")
                      labelSpreadsheet.grid(row=0, column=0, sticky='W', padx=(indentx,0))
                      variableSpreadsheet = Tkinter.StringVar()
                      self.entrySpreadsheet = Entry(self.frameSettings, textvariable=variableSpreadsheet, width=90, state=Tkinter.DISABLED)
                      self.entrySpreadsheet.grid(row=0, column=1, sticky='W', padx=px, pady=5)
                      self.entrySpreadsheet.svar = variableSpreadsheet
                      buttonSpreadsheet = Button(self.frameSettings, text="Browse...")
                      buttonSpreadsheet.grid(row=0, column=2, sticky='W', padx=(0,10))
              
                      labelPath = Label(self.frameSettings, text="2. Root Save Path:")
                      labelPath.grid(row=1, column=0, sticky='W', padx=(indentx,0))
                      variablePath = Tkinter.StringVar()
                      self.entryPath = Entry(self.frameSettings, textvariable=variablePath, width=90, state=Tkinter.DISABLED)
                      self.entryPath.grid(row=1, column=1, sticky='W', padx=px, pady=(5,10))
                      self.entryPath.svar = variablePath
                      buttonPath = Button(self.frameSettings, text="Browse...")
                      buttonPath.grid(row=1, column=2, sticky='W', padx=(0,10), pady=(0,5))
              
                      # ----------------------------------------------------
                      # START Creation Menu frame initialization
                      # ----------------------------------------------------
              
                      self.frameCreationIndividual = Tkinter.LabelFrame(self.frame, text="Feature Files Creation Menu", relief="groove", borderwidth="3", font=frameFont)
                      self.frameCreationIndividual.grid(sticky="EW", padx=px, pady=(5,15))
              
                      labelReq = Label(self.frameCreationIndividual, text="3. Feature(s):")
                      labelReq.grid(row=0, column=0, sticky='NW', pady=(5,0), padx=(indentx,15))
                      self.scrollbarReq = Scrollbar(self.frameCreationIndividual)
                      self.scrollbarReq.grid(row=1, column=3, rowspan=16, sticky="NSW", pady=(0,15),padx=(0,20))
              
                      variableSelectAll = Tkinter.IntVar()
                      self.checkSelectAll = Checkbutton(self.frameCreationIndividual, text = "Select All", variable = variableSelectAll, onvalue = 1, offvalue = 0)
                      self.checkSelectAll.grid(row=0, column=1, columnspan=2, sticky='NE', padx=px, pady=(5,0))
                      self.checkSelectAll.svar = variableSelectAll
              
                      labelReq = Label(self.frameCreationIndividual, text="4. Files:")
                      labelReq.grid(row=0, column=5, sticky='NW', pady=(5,0), padx=15)
              
                      variableIndividualFFS = Tkinter.IntVar()
                      self.checkIndividualFFS = Checkbutton(self.frameCreationIndividual, text = "Create Feature File", variable = variableIndividualFFS, onvalue = 1, offvalue = 0)
                      self.checkIndividualFFS.grid(row=1, column=5, sticky='NW', padx=15)
                      self.checkIndividualFFS.svar = variableIndividualFFS
              
                      variableIndividualSFS = Tkinter.IntVar()
                      self.checkIndividualSFS = Checkbutton(self.frameCreationIndividual, text = "Create SubFeature Files", variable = variableIndividualSFS, onvalue = 1, offvalue = 0)
                      self.checkIndividualSFS.grid(row=2, column=5, sticky='NW', padx=15)
                      self.checkIndividualSFS.svar = variableIndividualSFS
              
                      variableIndividualDO = Tkinter.IntVar()
                      self.checkIndividualDO = Checkbutton(self.frameCreationIndividual, text = "Create Doc Outline", variable = variableIndividualDO, onvalue = 1, offvalue = 0)
                      self.checkIndividualDO.grid(row=3, column=5, sticky='NW', padx=15)
                      self.checkIndividualDO.svar = variableIndividualDO
              
                      variableIndividualDWR = Tkinter.IntVar()
                      self.checkIndividualDWR = Checkbutton(self.frameCreationIndividual, text = "Create Doc With Requirements", variable = variableIndividualDWR, onvalue = 1, offvalue = 0)
                      self.checkIndividualDWR.grid(row=4, column=5, sticky='NW', padx=(15,30))
                      self.checkIndividualDWR.svar = variableIndividualDWR
              
                      self.buttonIndividualAll = Button(self.frameCreationIndividual, text="Create...", width=43)
                      self.buttonIndividualAll.grid(row=1, column=6, rowspan=4, sticky='NESW', padx=px)
              
                      # ----------------------------------------------------
                      # START Entire System Creation frame initialization
                      # ----------------------------------------------------
              
                      self.frameCreationSystem = Tkinter.LabelFrame(self.frame, text="System Creation Menu", relief="groove", borderwidth="3", font=frameFont)
                      self.frameCreationSystem.grid(sticky="EW", padx=px, pady=15)
              
                      self.buttonLAIF = Button(self.frameCreationSystem, text="Create Layers/App Integration Files", width=35)
                      self.buttonLAIF.grid(row=11, column=0, sticky='NESW', ipady=5, padx=(indentx,0), pady=(16,8))
              
                      self.buttonDO = Button(self.frameCreationSystem, text="Create Entire Doc Outline")
                      self.buttonDO.grid(row=12, column=0, sticky='NESW', ipady=5, padx=(indentx,0), pady=(8,10))
              
                      # ----------------------------------------------------
                      # START Feature Tab Creation Frame initialization
                      # ----------------------------------------------------
              
                      self.frameCreationNew = Tkinter.LabelFrame(self.frame, text="Feature Tab Creation Menu", relief="groove", borderwidth="3", font=frameFont)
                      self.frameCreationNew.grid(sticky="EW", padx=px, pady=(15,5))
              
                      labelIssueSpreadsheet = Label(self.frameCreationNew, text="2. Feature Spreadsheet Path:")
                      labelIssueSpreadsheet.grid(row=0, column=0, sticky='W', padx=(indentx,0))
                      variableIssueSpreadsheet = Tkinter.StringVar()
                      self.entryIssueSpreadsheet = Entry(self.frameCreationNew, textvariable=variableIssueSpreadsheet, width=83, state=Tkinter.DISABLED)
                      self.entryIssueSpreadsheet.grid(row=0, column=1, sticky='W', padx=px, pady=5)
                      self.entryIssueSpreadsheet.svar = variableIssueSpreadsheet
                      buttonIssueSpreadsheet = Button(self.frameCreationNew, text="Browse...")
                      buttonIssueSpreadsheet.grid(row=0, column=2, sticky='W')
              
                      labelFeatureTab = Label(self.frameCreationNew, text="3. Feature Name:")
                      labelFeatureTab.grid(row=1, column=0, sticky='W', padx=(indentx,0))
                      variableFeatureTab = Tkinter.StringVar()
                      self.entryFeatureTab = Entry(self.frameCreationNew, textvariable=variableFeatureTab, width=83)
                      self.entryFeatureTab.grid(row=1, column=1, sticky='W', padx=px, pady=5)
                      self.entryFeatureTab.svar = variableFeatureTab
              
                      labelFeatureAbbrv = Label(self.frameCreationNew, text="4. Feature Abbreviation:")
                      labelFeatureAbbrv.grid(row=2, column=0, sticky='W', padx=(indentx,0))
                      variableFeatureAbbrv = Tkinter.StringVar()
                      self.entryFeatureAbbrv = Entry(self.frameCreationNew, textvariable=variableFeatureAbbrv, width=83)
                      self.entryFeatureAbbrv.grid(row=2, column=1, sticky='W', padx=px, pady=5)
                      self.entryFeatureAbbrv.svar = variableFeatureAbbrv
              
                      self.buttonNewFeature = Button(self.frameCreationNew, text="Create Feature Tab", width=35)
                      self.buttonNewFeature.grid(row=3, column=0, columnspan =2, sticky='NWS', ipady=5, pady=(8,10), padx=(indentx,0))
              
                  # ----------------------------------------------------
                  # START general purpose methods
                  # ----------------------------------------------------
              
                  def initializeCanvas(self, event):
                      self.canvas.configure(scrollregion=self.canvas.bbox("all"),width=winx,height=winy)
              
                  def resizeCanvas(self, event):
                      self.update()
                      cwidth = self.winfo_width()
                      cheight = self.winfo_height()
                      self.canvas.config(scrollregion=self.canvas.bbox("all"), width=cwidth, height=cheight)
              
              # ----------------------------------------------------
              # Initialize application
              # ----------------------------------------------------
              if __name__ == "__main__":
                  app = AppTk(None)
                  app.title("MBD File Creator")
                  app.mainloop()
              

              推荐答案

              虽然可能还有其他错误,但是您有一个非常关键的缺陷:您正在为<Configure>事件创建绑定到self的绑定.由于self是根窗口的实例,因此您创建的每个小部件都将继承此绑定.您的resizeCanvas方法实际上在启动时被调用了数百次,而在调整窗口大小时则被调用了数百次.

              While there may be other errors, you have one very critical flaw: you are creating a binding for the <Configure> event to self. Because self is the instance of the root window, every widget you create inherits this binding. Your resizeCanvas method is literally being called hundreds of times at startup, and hundreds of times when the window is resized.

              您还存在在事件处理程序中调用update的问题.通常,这是不好的.实际上,这就像调用mainloop一样,直到处理完所有事件后它才会返回.如果您的代码导致要处理更多事件(例如,重新配置窗口并导致触发<configure>事件),则最终将导致递归循环.

              You also have the problem where you are calling update in an event handler. As a general rule, this is bad. In effect, it's like calling mainloop in that it will not return until all events are processed. If your code causes more events to be processed (such as reconfiguring a window and causing the <configure> event to fire, you end up in a recursive loop.

              您可能需要删除对self.update()的调用,并且/或者将它们替换为危险程度较小的self.update_idletasks().您还需要删除self上的<Configure>绑定,或者在方法中需要检查导致事件触发的窗口小部件(即:检查event.widget是根窗口).

              You probably need to remove the calls to self.update() and/or replace them with the less dangerous self.update_idletasks(). You also need to either remove the <Configure> binding on self, or in the method you need to check for which widget caused the event to fire (ie: check that the event.widget is the root window).

              这篇关于Python Tkinter滚动条摇晃滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆