spyder-ide / qtawesome

Iconic fonts in PyQt and PySide applications
https://qtawesome.readthedocs.io/en/latest/index.html
MIT License
802 stars 105 forks source link

Need a way to stop animation icon from calling _update #165

Closed paljsingh closed 10 months ago

paljsingh commented 3 years ago

Once a spin icon is added, there does not seem to be an easy way to stop it from calling icon update. With the default interval of 10ms, it starts consuming a lot of cpu if there are more than a few such icons a page.

In my use case, I need spin icons temporarily to show items being processed, and later these are replaced with non-spin icons, however the spin icons do not get garbage collected and keep calling Spin._update every 10 ms.

Attaching a sample code to show the impact on cpu usage.

In idle case, the CPU usage is close to 0, and that remains close to 0 even after setting the icons to non spin ones. However, once the button icons are set to spinner, CPU usage shoots up to 70% or above, and remains at the same level even if the buttons are later set to another icon.

import sys
from functools import partial

import qtawesome as qta
from PySide2.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QVBoxLayout

class SpinIconTest(QWidget):

    def __init__(self):
        super().__init__()
        self.spin_buttons = list()
        self.setup_ui()

    def setup_ui(self):

        # layout..
        hbox = QHBoxLayout()
        vbox = QVBoxLayout()

        num_buttons = 10

        for i in range(num_buttons):
            button = QPushButton('button {}'.format(i), self)
            vbox.addWidget(button)
            self.spin_buttons.append(button)

        self.button1 = QPushButton('set spin icon!', self)
        self.button1.clicked.connect(partial(self.set_spin_icon))

        self.button2 = QPushButton('set to regular icon!', self)
        self.button2.clicked.connect(partial(self.set_regular_icon))

        hbox.addWidget(self.button1)
        hbox.addWidget(self.button2)

        container_widget = QWidget()
        container_widget.setLayout(vbox)
        hbox.addWidget(container_widget)
        self.setLayout(hbox)

        self.show()

    def set_spin_icon(self):
        for button in self.spin_buttons:
            button.setIcon(qta.icon("fa5s.spinner", animation=qta.Spin(button)))

    def set_regular_icon(self):
        for button in self.spin_buttons:
            button.setIcon(qta.icon("fa5s.check-circle"))

def main():

    app = QApplication([])
    ex = SpinIconTest()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
paljsingh commented 3 years ago

At Idle

idle-case

After setting to Spin Icons...

spin-icon

Switching to another icon does not reduce the CPU usage.

non-spin-icon
dalthviz commented 3 years ago

Hi @paljsingh thanks for the feedback! Maybe providing something like a stop_timer method for the Spin class could help?

paljsingh commented 3 years ago

Yes, that would be great. Thanks.

dalthviz commented 3 years ago

@paljsingh would you like to help us checking the implementation of this method?

paljsingh commented 3 years ago

@paljsingh would you like to help us checking the implementation of this method?

Sure, please let me know once a fix is available for testing.

dalthviz commented 3 years ago

I meant to say that you could help us doing the implementation and submitting a PR (sorry for the confusion there 😅 ) I think you already worked in some logic when doing a workaround for this here (which is taking the timer reference and calling stop() on it) so maybe you would like to help us doing the implementation here to have a cleaner solution in your side.

paljsingh commented 3 years ago

No worries, I'll try to implement a solution and raise a pull request in a few days.