I noticed a lagging behavior when I dragged my Tkinter Root window across the screen (it does not have same motion speed as my mouse cursor). I have created a simple Tkinter app where one of the features is that user can select via button widget(s) to show/hide different Frame widgets which contains other child widgets. I have created all the required widget(s) during init() in a class.
In this example, lets say I have 4 Frame widgets (Frame A, B, C, D) and 4 buttons (Button A, B, C, D), respectively. Each Frame widget(s) contain several child widget(s). So, when I click Button A, the app will show Frame A using .grid(), and hide other Frame(s) using .grid_remove(). However, when I continue my clicking actions on the rest of the Button(s) to display & hide other Frame(s), I noticed it affected my Root window dragging motion when I want to move the app across my screen.

Code:
import tkinter as tk
from functools import partial
from tkinter import ttk
class AppGui(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master, *args, **kwargs)
self.grid_columnconfigure(index = 0, weight = 1)
self.grid_rowconfigure(index = 1, weight = 1)
self.main_interface()
def main_interface(self):
prnt = tk.Frame(self, highlightthickness = 0, bd = 0)
self.btn_a = tk.Button(prnt, relief = tk.GROOVE, text = 'Frame A', width = 12, font='Helvetica 11 bold')
self.btn_b = tk.Button(prnt, relief = tk.GROOVE, text = 'Frame B', width = 12, font='Helvetica 11 bold')
self.btn_c = tk.Button(prnt, relief = tk.GROOVE, text = 'Frame C', width = 12, font='Helvetica 11 bold')
self.btn_d = tk.Button(prnt, relief = tk.GROOVE, text = 'Frame D', width = 12, font='Helvetica 11 bold')
self.btn_a['command'] = partial(self.fr_sel_func, 'A')
self.btn_b['command'] = partial(self.fr_sel_func, 'B')
self.btn_c['command'] = partial(self.fr_sel_func, 'C')
self.btn_d['command'] = partial(self.fr_sel_func, 'D')
self.btn_a.grid(column = 0, row = 0, columnspan = 1, rowspan = 1, padx = (1,5), pady = (1,1), sticky = 'nwse')
self.btn_b.grid(column = 1, row = 0, columnspan = 1, rowspan = 1, padx = (1,5), pady = (1,1), sticky = 'nwse')
self.btn_c.grid(column = 2, row = 0, columnspan = 1, rowspan = 1, padx = (1,5), pady = (1,1), sticky = 'nwse')
self.btn_d.grid(column = 3, row = 0, columnspan = 1, rowspan = 1, padx = (1,1), pady = (1,1), sticky = 'nwse')
self.hashmap_fr_gui = {}
# self.create_fr_gui(): Function to create a Frame widget with all the child widgets.
# Store the Frame widget(s) in a hashmap
self.hashmap_fr_gui['A'] = self.create_fr_gui('A')
self.hashmap_fr_gui['B'] = self.create_fr_gui('B')
self.hashmap_fr_gui['C'] = self.create_fr_gui('C')
self.hashmap_fr_gui['D'] = self.create_fr_gui('D')
prnt.grid(column = 0, row = 0, columnspan = 1, rowspan = 1, padx = (2,1), pady = (1,1), sticky = 'nwse')
self.btn_a.invoke()
def fr_sel_func(self, hashmap_id):
if hashmap_id in self.hashmap_fr_gui:
for kw, tk_gui in self.hashmap_fr_gui.items():
if kw == hashmap_id:
tk_gui.grid(column = 0, row = 1, columnspan = 1, rowspan = 1, padx = (2,2), pady = (3,1), sticky = 'nwse')
else:
tk_gui.grid_remove()
def create_fr_gui(self, hashmap_id):
# Create Parent Frame GUI
prnt_gui = tk.Frame(self)
prnt_gui['bg'] = 'white'
prnt_gui.grid_columnconfigure(index = 0, weight = 1)
prnt_gui.grid_columnconfigure(index = 1, weight = 1)
prnt_gui.grid_rowconfigure(index = 0, weight = 1)
prnt_gui.grid_rowconfigure(index = 1, weight = 1)
child_gui_a = self.create_fr_child(prnt_gui, 'Subframe 1{}'.format(hashmap_id))
child_gui_b = self.create_fr_child(prnt_gui, 'Subframe 2{}'.format(hashmap_id))
child_gui_c = self.create_fr_child(prnt_gui, 'Subframe 3{}'.format(hashmap_id))
child_gui_d = self.create_fr_child(prnt_gui, 'Subframe 4{}'.format(hashmap_id))
child_gui_a.grid(column = 0, row = 0, columnspan = 1, rowspan = 1, padx = (1,1), pady = (1,1), sticky = 'nwse')
child_gui_b.grid(column = 1, row = 0, columnspan = 1, rowspan = 1, padx = (3,1), pady = (1,1), sticky = 'nwse')
child_gui_c.grid(column = 0, row = 1, columnspan = 1, rowspan = 1, padx = (1,1), pady = (3,1), sticky = 'nwse')
child_gui_d.grid(column = 1, row = 1, columnspan = 1, rowspan = 1, padx = (3,1), pady = (3,1), sticky = 'nwse')
return prnt_gui
def create_fr_child(self, prnt, panel_name):
# Create Child Frame GUI
child_gui = tk.Frame(prnt, highlightthickness = 1, highlightbackground = 'black')
child_gui.grid_columnconfigure(index = 0, weight = 1)
child_gui.grid_columnconfigure(index = 1, weight = 10)
child_gui.grid_rowconfigure(index = 0, weight = 0)
child_gui.grid_rowconfigure(index = 1, weight = 1)
name_tk_lb = tk.Label(child_gui, text = panel_name, font = 'Helvetica 14 bold'
, justify = tk.LEFT, anchor = 'nw')
name_tk_lb.grid(column = 0, row = 0, columnspan = 2, rowspan = 1, padx = (5,1), pady = (5,5), sticky = 'nwse')
#####################################################################################################################
# Left Side Grid Widget(s)
left_grid = tk.Frame(child_gui)
left_grid.grid_columnconfigure(index = 0, weight = 1)
left_grid.grid(column = 0, row = 1, columnspan = 1, rowspan = 1, padx = (20,1), pady = (1,1), sticky = 'nwse')
tk_lb = tk.Label(left_grid, text = 'Combobox: ', font = 'Helvetica 12 italic', width = 12
, justify = 'left', anchor = 'w')
tk_lb.grid(column = 0, row = 0, columnspan = 1, rowspan = 1, padx = (1,5), pady = (1,1), sticky = 'nwse')
ttk_cbox = ttk.Combobox(left_grid, values = [], width=13, state='readonly', font = 'Helvetica 11')
ttk_cbox.grid(column = 0, row = 1, columnspan = 1, rowspan = 1, padx = (1,5), pady = (5,1), sticky = 'nwse')
ttk_cbox.unbind_class("TCombobox", "<MouseWheel>")
tk_btn = tk.Button(left_grid, relief = tk.GROOVE, width = 10, height = 1, font = 'Helvetica 12')
tk_btn['text'] = 'Button'
tk_btn.grid(column = 0, row = 2, columnspan = 1, rowspan = 1, padx = (1,5), pady = (100,1), sticky = 'nwse')
#####################################################################################################################
# Right Side Grid Widget(s)
right_grid = tk.Frame(child_gui)
right_grid.grid_columnconfigure(index = 0, weight = 5)
right_grid.grid_columnconfigure(index = 1, weight = 10)
right_grid.grid_columnconfigure(index = 2, weight = 1)
right_grid.grid(column = 1, row = 1, columnspan = 1, rowspan = 1, padx = (10,20), pady = (1,1), sticky = 'nwse')
for i in range(0, 6):
right_grid.grid_rowconfigure(index = i, weight = 1, min = 50)
tk_lb = tk.Label(right_grid, text = 'Scalebar {}'.format(i + 1), font = 'Helvetica 12', justify = 'right', anchor = 'ne')
scl_var = tk.StringVar()
sbox_var = tk.StringVar()
tk_scl = tk.Scale(right_grid, from_=1, to=10, variable=scl_var, orient='horizontal', showvalue=0)
tk_sbox = tk.Spinbox(right_grid, width = 4, textvariable = sbox_var, from_=1, to=10
, highlightbackground="black", highlightthickness=1, font = 'Helvetica 12')
scl_var.set(1)
tk_lb.grid(column = 0, row = i, columnspan = 1, rowspan = 1, padx = (3,1), pady = (3,1), sticky = 'nwes')
tk_scl.grid(column = 1, row = i, columnspan = 1, rowspan = 1, padx = (3,1), pady = (4,1), sticky = 'nwe')
tk_sbox.grid(column = 2, row = i, columnspan = 1, rowspan = 1, padx = (3,3), pady = (3,1), sticky = 'nwe')
return child_gui
if __name__ == '__main__':
tk_root = tk.Tk()
tk_root_width = 890
tk_root_height = 600
screen_width = tk_root.winfo_screenwidth()
screen_height = tk_root.winfo_screenheight()
x_coordinate = int((screen_width/2) - (tk_root_width/2))
y_coordinate = int((screen_height/2) - (tk_root_height/2))
tk_root.geometry("{}x{}+{}+{}".format(tk_root_width, tk_root_height, x_coordinate, y_coordinate))
app_gui = AppGui(tk_root)
tk_root.grid_columnconfigure(index = 0, weight = 1)
tk_root.grid_rowconfigure(index = 0, weight = 1)
app_gui.grid(column = 0, row = 0, columnspan = 1, rowspan = 1, padx = (1,1), pady = (1,1), sticky = 'nwse')
tk_root.mainloop()
The issue seem to be mitigated when i experimented with .grid_destroy() on the Frame widget(s). However, I prefer not to use .grid_destroy(), otherwise I have to re-create my widget(s) again. So to solve this issue, do I have to use .grid_remove() on every child widgets within my Frame widget(s)? Or is there any other advise/solution to this.
EDIT 1: To replicate the lagging behavior when dragging the app window, user need to click each button(s) to display each Frame widgets at least once.
I experienced the same behavior with my Tkinter app and I found out that it's caused by my mouse (SteelSeries Sensei Ten).
When I tried moving the window with a different generic mouse, the "slugish" movement was gone. Finally, I tried messing with my mouse settings and it turned out that lowering my polling rate from 1000 to 250 Hz fixes it as well.
I also found out that this behavior is dependent alongside the polling rate on the number of used widgets and the size of the window.
I guess that a better solution would be to limit the "refresh rate" of your application locally. However, I'm not sure if that's possible.
EDIT: It is possible actually.
from time import sleep
def on_configure(e):
if e.widget == tk_root:
sleep(0.015)
if __name__ == '__main__':
tk_root = tk.Tk()
tk_root.bind("<Configure>", on_configure)
tk_root_width = 890
tk_root_height = 600
screen_width = tk_root.winfo_screenwidth()
screen_height = tk_root.winfo_screenheight()
x_coordinate = int((screen_width/2) - (tk_root_width/2))
y_coordinate = int((screen_height/2) - (tk_root_height/2))
tk_root.geometry("{}x{}+{}+{}".format(tk_root_width, tk_root_height, x_coordinate, y_coordinate))
app_gui = AppGui(tk_root)
tk_root.grid_columnconfigure(index = 0, weight = 1)
tk_root.grid_rowconfigure(index = 0, weight = 1)
app_gui.grid(column = 0, row = 0, columnspan = 1, rowspan = 1, padx = (1,1), pady = (1,1), sticky = 'nwse')
tk_root.mainloop()
This fixed it for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With