CustomTkinter
CustomTkinter copied to clipboard
Scrollbar is stuttering
I was previously using ttk.Scrollbar widget, but thought of migrating to the ctk.CTkScrollbar because of easy customization. It looks good, but there is a problem ruins the scroll effect. When i hold down the scroll bar to move (not using the scroll wheel) through the page quickly, it creates this stuttering effect (shown in attached screen recording), while this does not occur in the native scroll bar.
Native:
self.scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
CTk:
self.scrollbar = ctk.CTkScrollbar(self, orientation="vertical",
command=self.canvas.yview,
fg_color=ColorPalette.black_3,
scrollbar_color=ColorPalette.black_4,
scrollbar_hover_color=ColorPalette.black_5,
width=30, corner_radius=10)
https://user-images.githubusercontent.com/86649457/175858559-fa04e43c-c9ae-4d3b-804a-bf1b373ad548.mp4
I hope the 2 parts of this video are differentiable. Sorry for low quality.
I don't know exactly what you mean. Is the rendering lagging? In the video it looks like the rendering lags a bit but also on the normal scrollbar. Or do you mean the scrolling is not smooth, and has bigger steps than the normal scrollbar?
Here is a clearer version of the recording:
| Native Scrollbar | CTk Scrollbar |
|---|---|
Yes, i believe the rendering is not smooth, as you can see in the video.
This happens with both of the scrollbars, but is more noticeable in the CTkScrollbar
I was previously using
ttk.Scrollbarwidget, but thought of migrating to thectk.CTkScrollbarbecause of easy customization. It looks good, but there is a problem ruins the scroll effect. When i hold down the scroll bar to move (not using the scroll wheel) through the page quickly, it creates this stuttering effect (shown in attached screen recording), while this does not occur in the native scroll bar.Native:
self.scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)CTk:
self.scrollbar = ctk.CTkScrollbar(self, orientation="vertical", command=self.canvas.yview, fg_color=ColorPalette.black_3, scrollbar_color=ColorPalette.black_4, scrollbar_hover_color=ColorPalette.black_5, width=30, corner_radius=10)2022-06-27.09-23-32_2.mp4 I hope the 2 parts of this video are differentiable. Sorry for low quality.
https://github.com/TomSchimansky/CustomTkinter/issues/215#issue-1285209510
Nothing to do with the issue itself, but your gui seems nice
Can you post your code? Or part of it with the scrollable frame?
I just changes this line:
self.scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
to this:
self.scrollbar = ctk.CTkScrollbar(self, orientation="vertical",
command=self.canvas.yview,
fg_color=ColorPalette.black_3,
scrollbar_color=ColorPalette.black_4,
scrollbar_hover_color=ColorPalette.black_5,
width=30, corner_radius=10)
Code:
it is used in a class called ScrollableFrame (extends ttk.Frame object)
class ScrollableFrame(ttk.Frame):
def __init__(self, container, *args, **kwargs):
super().__init__(container, *args, **kwargs)
self.canvas = tk.Canvas(self)
# self.scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.scrollbar = ctk.CTkScrollbar(self, orientation="vertical",
command=self.canvas.yview,
fg_color=ColorPalette.black_3,
scrollbar_color=ColorPalette.black_4,
scrollbar_hover_color=ColorPalette.black_5,
width=30, corner_radius=10)
self.scrollable_frame = ttk.Frame(self.canvas)
self.scrollable_frame.bind("<Configure>", lambda *args, **kwargs: self.canvas.configure(
scrollregion=self.canvas.bbox("all")))
self.bind_all("<MouseWheel>", self._on_mousewheel)
self.bind("<Destroy>", lambda *args, **kwargs: self.unbind_all("<MouseWheel>"))
self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.canvas.pack(side="left", fill="both", expand=True)
self.scrollbar.pack(side="right", fill="y")
def _on_mousewheel(self, event):
self.canvas.yview_scroll(-1 * round(event.delta / 120), "units")
Usage (unchanged):
s = ttk.Style()
s.configure('My.scrollable.TFrame', background=color.black_3)
scrollable_frame = my_classes.ScrollableFrame(rec_frame)
scrollable_frame.place(x=border, y=border, anchor='nw', width=stats_w, height=stats_h + border + rec_table_h)
scrollable_frame.scrollable_frame.configure(style='My.scrollable.TFrame')
scrollable_frame.canvas.configure(background=color.black_3, highlightthickness=0)
Can you post an executable one-file example where the effect is visible for you?
you mean packing an example app in exe file?
This code works in windows 11:
from ctypes import windll
from tkinter import ttk
import tkinter as tk
from win32api import GetMonitorInfo, MonitorFromPoint
import customtkinter as ctk
###############################################
################# set scaling #################
###############################################
screensize_old = windll.user32.GetSystemMetrics(0)
windll.shcore.SetProcessDpiAwareness(1)
screensize_new = windll.user32.GetSystemMetrics(0)
scale = round(screensize_old / screensize_new, 2)
ctk.set_window_scaling(scale)
ctk.set_spacing_scaling(scale)
ctk.set_widget_scaling(scale)
###############################################
###############################################
work_area = GetMonitorInfo(MonitorFromPoint((0, 0))).get("Work")
screen_w, screen_h = work_area[2], work_area[3]
root_w = 800
root_h = 500
border = 20
lines = 100
###############################################
###############################################
class ScrollableFrame(ttk.Frame):
def __init__(self, container, *args, **kwargs):
super().__init__(container, *args, **kwargs)
self.canvas = tk.Canvas(self)
# self.scrollbar = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.scrollbar = ctk.CTkScrollbar(self, orientation="vertical",
command=self.canvas.yview,
fg_color='#202020',
scrollbar_color='#303030',
scrollbar_hover_color='#404040',
width=30, corner_radius=10)
self.scrollable_frame = ttk.Frame(self.canvas)
self.scrollable_frame.bind("<Configure>", lambda *args, **kwargs: self.canvas.configure(
scrollregion=self.canvas.bbox("all")))
self.bind_all("<MouseWheel>", self._on_mousewheel)
self.bind("<Destroy>", lambda *args, **kwargs: self.unbind_all("<MouseWheel>"))
self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.canvas.pack(side="left", fill="both", expand=True)
self.scrollbar.place(relx=1, rely=0, relheight=1, anchor="ne")
# self.scrollbar.pack(side="right", fill="y")
def _on_mousewheel(self, event):
self.canvas.yview_scroll(-1 * round(event.delta / 120), "units")
# ininitialize the root window
root = ctk.CTk(fg_color='#202020')
root.title("Scrollbar")
# spawn window in center of the screen
root.geometry(f"{root_w}x{root_h}+{int(screen_w / 2 - root_w / 2)}+{int(screen_h / 2 - root_h / 2)}")
root.resizable(False, False)
scrollable_frame = ScrollableFrame(root)
scrollable_frame.place(x=border, y=border, anchor='nw', width=root_w - 2 * border, height=root_h - 2 * border)
# configuring looks of the scrollbar frame
ttk_style = ttk.Style()
ttk_style.configure('My.scrollable.TFrame', background='#202020')
scrollable_frame.scrollable_frame.configure(style='My.scrollable.TFrame')
scrollable_frame.canvas.configure(background='#202020', highlightthickness=0)
# creating text labels in the scrollable frame
for i in range(lines):
ctk.CTkLabel(
scrollable_frame.scrollable_frame,
fg_color='#404040',
bg_color='#202020',
width=root_w - 4 * border,
corner_radius=10,
text=f"Line {i + 1}",
text_font="Consolas 24 normal",
).pack(pady=(10, 0))
root.mainloop()
any update?
how can we implement scroll on the frame?