root.update在Linux中落后,但在Windows中落后

时间:2019-04-02 02:11:42

标签: python tkinter

我的python tkinter代码在linux中严重滞后,但在Windows中却严重滞后。它与root.update()和root.config()有关。如何解决此问题,使linux版本与Windows版本一样快?

我已经在Windows上编写了一个运行良好的python程序。我目前正在制作linux版本。进行一些修改后,Linux版本可以正常工作,但有很大的滞后。我插入代码来计时程序的不同部分。对于root.update()root.config()行,从Windows到Linux有很大的不同。

以下几行是导致延迟的行:

root.update()
root.config(menu=menubar)

我在Windows和Linux中多次运行了该程序,并记录了执行代码所花费的时间。

以下是这些行的运行时间的记录:

在Windows中:

root update:  0.47  seconds 
root update:  0.2656  seconds
root update:  0.3125  seconds
root update:  0.3594  second
root update:  0.3593  seconds
menubar root config done:  0.0081
menubar root config done:  0.0

在Windows中:进程结束,退出代码为-1

Windows中的

pycharm使用的是Python 3.7


在Linux中:

root update:  2.4416  seconds
root update:  87.3216  seconds
root update:  1.5798  seconds
root update:  148.2783  seconds
root update:  2.2533  seconds
root update:  2.2771  seconds
root update:  2.4898  seconds
root update:  8.022  seconds
root update:  171.6852  seconds
root update:  1.7088  seconds
menubar root config done:  0.0441
menubar root config done:  2.4566
menubar root config done:  1.2589

在linux中:进程以退出代码9

完成

Linux中的pycharm使用的是Python 3.6

这是我能做到的简单代码。 tkinter制作了一个gui,查询mysql数据库,该函数生成菜单栏并将许多小部件放在网格中。

root = Tk()
root.title("KLUSTERBOX")

...

def main_frame(): # call function to make the main screen

# define and put widgets on a grid

...

generate_menubar(Frame) # call function to make menubar

# define the menubar

root.config(menu=menubar)

...

# define and put widgets on a grid

root.update()

我被要求提供MCVE。这是一个示例程序,重复了该问题:

from tkinter import *
import time
import sys
def main_frame():
    starttime = time.time()
    F = Frame(root)
    F.pack(fill=BOTH, side=LEFT)
    C1 = Canvas(F)
    C1.pack(fill=BOTH, side=BOTTOM)
    Button(C1, text="Refresh", width=12, command=lambda: [F.destroy(),main_frame()]).pack(side=LEFT)
    Button(C1, text="Quit", width=12, command=root.destroy).pack(side=LEFT)
    # link up the canvas and scrollbar
    S = Scrollbar(F)
    C = Canvas(F, width=1600)
    S.pack(side=RIGHT, fill=BOTH)
    C.pack(side=LEFT, fill=BOTH, pady=10, padx=10)
    S.configure(command=C.yview, orient="vertical")
    C.configure(yscrollcommand=S.set)
    if sys.platform == "win32":
        C.bind_all('<MouseWheel>', lambda event: C.yview_scroll(int(-1 * (event.delta / 120)), "units"))
    elif sys.platform == "linux":
        C.bind_all('<Button-4>', lambda event: C.yview('scroll',-1,'units'))
        C.bind_all('<Button-5>', lambda event: C.yview('scroll',1,'units'))
    # create the frame inside the canvas
    preF=Frame(C)
    C.create_window((0, 0), window=preF, anchor=NW)
    Label(preF, text="To refresh - press REFRESH").pack()
    Label(preF, text="To quit - press QUIT").pack()
    Label(preF, text="Run times are displayed in console").pack()
    FF = Frame(C)
    C.create_window((0,108), window=FF, anchor=NW)
    for i in range(100):
        Button(FF, text=i, width=5, bg="yellow", anchor="w").grid(row=i,column=0)
        Button(FF, text="hello there", width=24, bg="yellow", anchor="w").grid(row=i,column=1)
        Button(FF, text=" ", width=5, bg="green", anchor="w").grid(row=i, column=2)
        Button(FF, text=" ", width=5, bg="green", anchor="w").grid(row=i,column=3)
        Button(FF, text=" ", width=5, bg="green", anchor="w").grid(row=i, column=4)
        Button(FF, text=" ", width=5, bg="green", anchor="w").grid(row=i, column=5)
    endtime = time.time()
    print("runtime prior to root.update(): ", round(endtime - starttime,4), " seconds")
    starttime = time.time()
    root.update()
    endtime = time.time()
    print("root.update() runtime: ", round(endtime-starttime,4)," seconds")
    C.config(scrollregion=C.bbox("all"))
    mainloop()
root = Tk()
root.geometry("%dx%d+%d+%d" % (625,600,100,50))
main_frame()

我已经为root.update()root.config(menu=menubar)设置了运行时间。 linux中的时间太长,会使该程序无法使用,特别是考虑到该程序的其他部分滞后得多。

1 个答案:

答案 0 :(得分:0)

在我的Linux Mint上,它需要0.3秒(Python 3.7、3.6、2.7),而且我不知道为什么它在Linux上运行这么慢。

这里只有一些更改的代码-也许会有所帮助。

  • 我不使用root.update(),而是使用after()在主循环启动100毫秒后更改scrollregion。在mainloop运行之前,窗口小部件不存在,因此无法计算滚动区域。

  • 我不会使用所有小部件销毁F,但我只会使用创建表格的按钮来构成框架,而我只会重新创建该框架。

  • 我不再运行main_frame,所以我不再运行另一个mainloop()

  • 我不得不使用global来访问带有表的框架,因为command=无法从函数中获取值并无法赋值给变量。

启动需要0.3秒,刷新需要0.09秒

from tkinter import *
import time
import sys

def create_table(C):
    table = Frame(C)

    C.create_window((0,108), window=table, anchor=NW)

    for i in range(100):
        Button(table, text=i, width=5, bg="yellow", anchor="w").grid(row=i,column=0)
        Button(table, text="hello there" + str(X), width=24, bg="yellow", anchor="w").grid(row=i,column=1)
        Button(table, text=" ", width=5, bg="green", anchor="w").grid(row=i, column=2)
        Button(table, text=" ", width=5, bg="green", anchor="w").grid(row=i,column=3)
        Button(table, text=" ", width=5, bg="green", anchor="w").grid(row=i, column=4)
        Button(table, text=" ", width=5, bg="green", anchor="w").grid(row=i, column=5)

    return table

def refresh(C):
    global table

    starttime = time.time()

    table.destroy()
    table = create_table(C)

    endtime = time.time()

    print("refresh: ", round(endtime-starttime,4)," seconds")


def main_frame():
    global table

    starttime = time.time()

    F = Frame(root)
    F.pack(fill=BOTH, side=LEFT)

    C1 = Canvas(F)
    C1.pack(fill=BOTH, side=BOTTOM)

    Button(C1, text="Refresh", width=12, command=lambda:refresh(C)).pack(side=LEFT)
    Button(C1, text="Quit", width=12, command=root.destroy).pack(side=LEFT)

    # link up the canvas and scrollbar
    S = Scrollbar(F)
    C = Canvas(F, width=1600)
    S.pack(side=RIGHT, fill=BOTH)
    C.pack(side=LEFT, fill=BOTH, pady=10, padx=10)
    S.configure(command=C.yview, orient="vertical")
    C.configure(yscrollcommand=S.set)

    if sys.platform == "win32":
        C.bind_all('<MouseWheel>', lambda event: C.yview_scroll(int(-1 * (event.delta / 120)), "units"))
    elif sys.platform == "linux":
        C.bind_all('<Button-4>', lambda event: C.yview('scroll',-1,'units'))
        C.bind_all('<Button-5>', lambda event: C.yview('scroll',1,'units'))

    # create the frame inside the canvas
    preF=Frame(C)
    C.create_window((0, 0), window=preF, anchor=NW)
    Label(preF, text="To refresh - press REFRESH").pack()
    Label(preF, text="To quit - press QUIT").pack()
    Label(preF, text="Run times are displayed in console").pack()

    table = create_table(C)

    endtime = time.time()
    print("runtime: ", round(endtime - starttime,4), " seconds")

    # update scrollregion 100ms after mainloop start
    root.after(100, lambda:C.config(scrollregion=C.bbox("all")))
    mainloop()


root = Tk()
root.geometry("%dx%d+%d+%d" % (625,600,100,50))
main_frame()