j4321 / tkcalendar

Calendar widget for Tkinter
https://pypi.python.org/pypi/tkcalendar
GNU General Public License v3.0
97 stars 33 forks source link

High CPU, Python 3.7.2, tkcalendar 1.4.0 #36

Closed evaldes2015 closed 5 years ago

evaldes2015 commented 5 years ago

If I place a DateEntry on a frame my application begins to behave poorly and have high CPU.

If I comment out: self.bind('<<ThemeChanged>>', lambda e: self.after(10, self._on_theme_change)) in the __init__ for DateEntry then things seem to work fine.

The frame is a tab in a ttk Notebook.

j4321 commented 5 years ago

Could you tell me which OS and which ttk theme you are using? I am using Linux and, even when putting the DateEntry in a Notebook tab, the CPU usage remains low.

I guess that the <<ThemeChanged>> event is triggered many time in your case but it is not in mine. If you could give me a minimal code sample that triggers the issue on your computer, it would make it easier for me to fix the problem.

evaldes2015 commented 5 years ago

Windows 7.

self.TLabelframe1 = ttk.Labelframe(master) self.TLabelframe1.place(relx=0.400, rely=0.037, relheight=0.122, relwidth=0.200) self.TLabelframe1.configure(text='''Dates''')

self.Startcal = DateEntry(self.TLabelframe1, width=12, background='darkblue', foreground='white', borderwidth=2, year=2019) self.Startcal.place(relx=0.475, rely=-0.100, height=24, width=98) self.Startcal.configure(state=tk.DISABLED)

evaldes2015 commented 5 years ago

I can't really post most of the code around this. I'll try to build something simple that replicates this issue.

j4321 commented 5 years ago

Ok, thanks. I will test this as soon as possible.

evaldes2015 commented 5 years ago

This doesn't look right:

def _on_theme_change(self):
    if self._theme_change:
        self._theme_change = False
        self._setup_style()
        self.after(50, self._set_theme_change)

def _set_theme_change(self):
    self._theme_change = True
j4321 commented 5 years ago

The reason why I did the binding on <<ThemeChanged>> is for the DateEntry style to be updated if the programmer changes the ttk style. But with a basic binding it was triggered many times for each change so I made this workaround to introduce a delay and avoid updating the style several times in a row for nothing.

evaldes2015 commented 5 years ago

So it looks like what winds up happening is that the <> event fires every 10ms, but the widget only updates every 50ms. Is this correct?

j4321 commented 5 years ago

Not exactly, when the event <<ThemeChanged>> is triggered, then 10 ms later, the _on_theme_change() function is executed and the widget is updated only if the last update of the widget was more than 50 ms ago.

evaldes2015 commented 5 years ago

I tried this:

self.bind('<<ThemeChanged>>', self._on_theme_change())

and:

def _on_theme_change(self):
    # if self._theme_change:
    #     self._theme_change = False
    #     self._setup_style()
    #     self.after(50, self._set_theme_change)
    self._setup_style()

It seems to work fine. The _on_theme_change event fires a few times when my application starts because I have multiple instances of DateEntry, but then the events stop. Am I missing something?

j4321 commented 5 years ago

You are executing _on_theme_change when you bind it (and nothing will happen if you try to change theme later), to avoid that you should do: self.bind('<<ThemeChanged>>', self._on_theme_change). and also you need to add the event argument in the definition of _on_theme_change: def _on_theme_change(self, event): otherwise you will get an error.

I used to do it like that but if I remember correctly it gave me a high CPU usage in Windows but there may have been some changes in tcl/tk since.

evaldes2015 commented 5 years ago

You're right. My bad. I was sloppy.

I changed it. I have six instances of DateEntry, I got around 20 _on_theme_change events as the application started, but then they stopped.

evaldes2015 commented 5 years ago

I can account for all of the events. My application uses the ttk.Notebook widget. As things are added to the tabs the _on_theme_change events fire. But once everything is in place the events stop.

I wonder why you were getting excessive events.

j4321 commented 5 years ago

Someone reported a bug (#9) and that's how I noticed the excessive events, and the workaround did fix the person's issue. I will make some more tests to see why you have the opposite problem.

evaldes2015 commented 5 years ago

Perhaps their application was constantly changing themes?

evaldes2015 commented 5 years ago

I just tried my application on Linux. The high CPU issue does not occur with 1.4.0.

evaldes2015 commented 5 years ago

In Linux the _on_theme_change fires constantly but does not seem to affect the application. In Windows the issue is so bad that the application becomes unresponsive.

den4uk commented 5 years ago

I have a similar issue of high CPU usage. Windows 10, tkcalendar==1.4.0

My calendar widget (DataEntry) is also placed into a ttk.Notepad. My bind is on <FocusOut>.

The behaviour of increased CPU usage (and thread hanging if executed on the main thread) appears when a widget is created in a non-focused Notepad tab, but after manually focusing on the widget the CPU usage goes down instantly.

I tried adding .focus() and .focus_set() on the widget, but it didn't change anything.

j4321 commented 5 years ago

@evaldes2015 I have modified the _on_theme_change() function due to another request (see #47 ). Could you test the code from the master branch and let me know if this solves your issue as well?

evaldes2015 commented 5 years ago

It seems to be OK on Windows (7). I will try it on Linux as well.

evaldes2015 commented 5 years ago

Looks like Linux is OK as well.

j4321 commented 5 years ago

Thanks for the feedback, can I close this issue then?

evaldes2015 commented 5 years ago

As far as I am concerned yes. Thanks for fixing this!!