Python Forum

Full Version: Setting icon on QAction from outside QGuiApplication
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Good evening, and a happy new year you all.

I'm working on a GUI that is expected to become larger and larger in the future, so I am aiming to make it as scalable as possible.

For this purpose, I created a custom class which should handle all default actions in my app at once:
from typing import List
from collections import namedtuple
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (QApplication, QAction, QStyle)


class JHActionSet(QAction, QStyle):
    '''
    Implements and handles default actions in a J*** H*** view.
    '''

    def __init__(self):
        super(JHActionSet, self).__init__()
        self.defaults()

    def defaults(self):
        action = namedtuple('Action', ['icon', 'text', 'method', 'tooltip'])  # TODO : Consider adding 'shortcut' field and implement regional settings.

        # Default methods declaration
        def foo():
            print("Hello, world")

        # Default actions declaration
        # TODO : Must implement regional settings, for now hardcoded str are ok
        return {
            'research': action('ico/research.png', 'Ricerca', foo, '...'),
            'selection': action(QStyle.SP_MessageBoxInformation, 'Selezione', foo, '...'),
            'composition': action(QStyle.SP_MessageBoxInformation, 'Composizione', foo, '...'),
            'infopane': action(QStyle.SP_MessageBoxInformation, 'Dettagli', foo, '...')
        }

    def get(self, request):
        actions = self.defaults()

        try:
            data = self.defaults()[request]
            action_ = QAction(text=data.text)
            action_.setToolTip(data.tooltip)
            action_.setIcon(QIcon(data.icon))
            action_.triggered.connect(data.method)

            return action_

        except ValueError:
            raise ValueError("You requested a JHAction that is not supported.")

    def get_set(self) -> List[QAction]:
        action_set = []
        for key in self.defaults():
            action_set.append(self.get(key))

        return action_set
So basically, in order to implement my let's call it "default actions pack" in the final app, I should simply initialise the class and get the actions ready to use:
actions = JHActionSet().get_set()  # -> A list of all my actions
for action in self.actions:
        self.toolbar.addAction(action)
Everything works as expected, except setting the actions' icons. If I comment out line #39 code works flawlessly, but as it is now it throws this exception:
Output:
QPixmap: Must construct a QGuiApplication before a QPixmap
I tried to pass a string instead of a QIcon() object but it raises a TypeError instead.

The whole point of doing all this was having an object that drops all my actions ready-to-use in my app, icons included, so this is a pretty fundamental part of the whole thing. I really can't figure out how to work this out.

Any help would be greatly appreciated. Also, I would like to have an opinion by more seasoned developers whether this approach is acceptable, if it goes against some conventions or best practices, or generally if this looks something that makes sense doing or not.
I am used to Swift features like extension, delegate and others that I still miss sometimes in Python (perhaps because I still have to understand the mechanism deeply).
Try creating an instance of QApplication before creating an instance of JHActionSet
QApplication() creates a QApplication object, and it sets up your application to run Qt. If you try to create a QAction object before calling QApplication(), you don't have the application framework required to manage the QAction object. The same thing happened when you tried to make a QIcon
(Jan-02-2023, 06:56 PM)deanhystad Wrote: [ -> ]QApplication() creates a QApplication object, and it sets up your application to run Qt. If you try to create a QAction object before calling QApplication(), you don't have the application framework required to manage the QAction object. The same thing happened when you tried to make a QIcon

Thank you both, that seems to fix the problem and totally makes sense.
Hoper this doesn't have consequences in terms of efficiency.